本系列文章由@二货梦想家张程 所写,转载请注明出处。

本文章链接:http://blog.csdn.net/terence1212/article/details/44264153

作者:ZeeCoder  微博链接:http://weibo.com/zc463717263

我的邮箱:michealfloyd@126.com   欢迎大家发邮件来和我交流编程心得

you are what you read!与大家共勉!

-------------------------------------------------分割线:ZeeCoder--------------------------------------------

一、循环背景动画

循环背景动画就是不断地进行背景图的裁剪和接合,然后显示在窗口上所产生的一种背景循环滚动的效果。要达到这样的效果我们需要一张接合后看不出团接缝的背景图。其原理如下:

如上图所示,裁剪和接合过程:首先将左图黑色部分裁剪下来贴到右图黑色部分,然后将左图白色部分裁剪下来贴到右图白色部分。重复上述步骤即可完成循环背景动画。

二、多背景循环动画

多背景循环动画的原理和循环背景动画的原理相同,那么在多背景循环动画中,为了达到远近层次以及实际视觉移动效果,需要决定背景贴图的先后顺序,以及滚动的顺序。

上图是最终的效果图,从图中可以看到,整个动画分为四个层次,依次是天空,草地,海岛,人物,其中,海岛和人物需要

完成透明贴图。背景的滚动速度依次是天空<海岛<草地。人物即在原地跑动就可以看到向前奔跑的效果。

三、具体实现

#include "stdafx.h"
#include "MulitBg.h"

#define MAX_LOADSTRING 100

// Global Variables:
HINSTANCE hInst;								// current instance
TCHAR szTitle[MAX_LOADSTRING];					// The title bar text
TCHAR szWindowClass[MAX_LOADSTRING];			// the main window class name
HDC hdc,mdc,bufdc;
HWND hWnd;
HBITMAP g_bg , g_island , g_walker;
DWORD g_tNow , g_tPre;
int g_x0 = 0 , g_x1 = 0 , g_x2 = 0 , g_x4 = 0 , g_num;
// Forward declarations of functions included in this code module:
ATOM				MyRegisterClass(HINSTANCE hInstance);
BOOL				InitInstance(HINSTANCE, int);
LRESULT CALLBACK	WndProc(HWND, UINT, WPARAM, LPARAM);
void				MyPaint(HDC hdc);
//***************************主函数**********************************
int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{
	UNREFERENCED_PARAMETER(hPrevInstance);
	UNREFERENCED_PARAMETER(lpCmdLine);

 	// TODO: Place code here.
	MSG msg;

	// Initialize global strings
	LoadString(hInstance, IDS_APP_TITLE, szTitle, MAX_LOADSTRING);
	LoadString(hInstance, IDC_MULITBG, szWindowClass, MAX_LOADSTRING);
	MyRegisterClass(hInstance);

	// Perform application initialization:
	if (!InitInstance (hInstance, nCmdShow))
	{
		return FALSE;
	}

	// Main message loop:
	GetMessage(&msg , NULL , NULL , NULL);
	while (msg.message != WM_QUIT)
	{
		if ( PeekMessage( &msg , NULL ,0 ,0 ,PM_REMOVE))//PM_REMOVE消息从队列里除掉
		{
			TranslateMessage( &msg);
			DispatchMessage(&msg);
		}
		else
		{
			g_tNow = GetTickCount();
			if (g_tNow - g_tPre >= 120)
			{
				MyPaint(hdc);
			}
		}
	}
	return (int) msg.wParam;
}

//***************************窗口类函数**********************************
ATOM MyRegisterClass(HINSTANCE hInstance)
{
	WNDCLASSEX wcex;

	wcex.cbSize = sizeof(WNDCLASSEX);

	wcex.style			= CS_HREDRAW | CS_VREDRAW;
	wcex.lpfnWndProc	= WndProc;
	wcex.cbClsExtra		= 0;
	wcex.cbWndExtra		= 0;
	wcex.hInstance		= hInstance;
	wcex.hIcon			= LoadIcon(hInstance, MAKEINTRESOURCE(IDI_MULITBG));
	wcex.hCursor		= LoadCursor(NULL, IDC_ARROW);
	wcex.hbrBackground	= (HBRUSH)(COLOR_WINDOW+1);
	wcex.lpszMenuName	= MAKEINTRESOURCE(IDC_MULITBG);
	wcex.lpszClassName	= szWindowClass;
	wcex.hIconSm		= LoadIcon(wcex.hInstance, MAKEINTRESOURCE(IDI_SMALL));

	return RegisterClassEx(&wcex);
}
//***************************初始化函数**********************************
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
   HBITMAP bmp;
   hInst = hInstance; // Store instance handle in our global variable

   hWnd = CreateWindow(_T("MulitBg"), _T("多背景循环滚动"), WS_OVERLAPPEDWINDOW,
      CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);

   if (!hWnd)
   {
      return FALSE;
   }

   MoveWindow(hWnd , 10 , 10 , 800 ,600 ,true);
   ShowWindow(hWnd, nCmdShow);
   UpdateWindow(hWnd);

   hdc = GetDC(hWnd);
   mdc = CreateCompatibleDC(hdc);
   bufdc = CreateCompatibleDC(hdc);

   bmp = CreateCompatibleBitmap(hdc , 800 , 600);
   SelectObject(mdc , bmp);

   g_bg  = (HBITMAP)LoadImage(NULL , _T("bg0.bmp") , IMAGE_BITMAP , 800 , 600 , LR_LOADFROMFILE);//天空
   g_island = (HBITMAP)LoadImage(NULL , _T("bg.bmp") , IMAGE_BITMAP , 800 , 1200 , LR_LOADFROMFILE);//海岛

   g_walker = (HBITMAP)LoadImage(NULL , _T("1.bmp") , IMAGE_BITMAP , 968 , 258 , LR_LOADFROMFILE);//人物跑动

   MyPaint(hdc);
   return TRUE;
}

//***************************消息响应函数**********************************
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	int wmId, wmEvent;

	switch (message)
	{
	case WM_COMMAND:
		wmId    = LOWORD(wParam);
		wmEvent = HIWORD(wParam);
		// Parse the menu selections:
		switch (wmId)
		{
		case IDM_EXIT:
			DestroyWindow(hWnd);
			break;
		default:
			return DefWindowProc(hWnd, message, wParam, lParam);
		}
		break;
	case WM_DESTROY:
		DeleteDC(mdc);
		DeleteObject(g_bg);
		DeleteObject(g_island);
		DeleteObject(g_walker);
		ReleaseDC(hWnd , hdc);
		PostQuitMessage(0);
		break;
	default:
		return DefWindowProc(hWnd, message, wParam, lParam);
	}
	return 0;
}
//***************************自定义绘图函数*********************************

void MyPaint(HDC hdc)
{
	//贴上天空图
	SelectObject(bufdc , g_bg);
	BitBlt(mdc , 0  , 0 , g_x0 , 370, bufdc , 800 - g_x0 , 0 , SRCCOPY);
	BitBlt(mdc , g_x0 , 0 , 800 - g_x0 , 370 , bufdc , 0 , 0 , SRCCOPY);

	//贴上海面图
	BitBlt(mdc , 0 , 370 , g_x1 , 230 , bufdc , 800 - g_x1 ,370 , SRCCOPY);
	BitBlt(mdc , g_x1 , 370 , 800 - g_x1 , 230 , bufdc , 0 , 370 , SRCCOPY);

	//贴上海岛图并透明
	SelectObject(bufdc , g_island);
	BitBlt(mdc , 0 , 0 , g_x2 , 600 ,bufdc , 800 - g_x2 , 600 , SRCAND);
	BitBlt(mdc , g_x2 , 0 , 800 - g_x2 , 600 , bufdc , 0 , 600 , SRCAND);
	BitBlt(mdc , 0 , 0 , g_x2 , 600 ,bufdc , 800 - g_x2 , 0 , SRCPAINT);
	BitBlt(mdc , g_x2 , 0 , 800- g_x2 , 600 ,bufdc , 0 , 0 , SRCPAINT);

	//贴上人物图并透明
	SelectObject(bufdc , g_walker);
	BitBlt(mdc , 250, 350 ,121 , 129 ,bufdc , g_num*121 , 129 , SRCAND);
	BitBlt(mdc ,250	,  350 , 121, 129 , bufdc , g_num*121 , 0 , SRCPAINT);

	//将最后的画面显示在窗口上
	BitBlt(hdc , 0 , 0 , 800 , 600 , mdc , 0 , 0 ,SRCCOPY);

	g_tPre = GetTickCount();//获取当前系统时间

	g_x0 += 5 ; //重设天空背景切割宽度
	if ( g_x0 >= 800)
	{
		g_x0 = 0 ;
	}

	g_x1 += 20;//重设海面背景切割宽度
	if ( g_x1 >= 800)
	{
		g_x1 = 0 ;
	}

	g_x2 += 10 ;//重设海岛背景切割宽度
	if (g_x2 == 800)
	{
		g_x2 = 0;
	}

	g_x4 += 5;
	if (g_x4 >= 800)
	{
		g_x4 = 0 ;
	}
	g_num ++;//重设跑动图的图号
	if (g_num == 8)
	{
		g_num = 0 ;
	}

}

笔记六就写到这里。利用bitblt进行动画设计的技巧到这篇笔记也结束了。

偶尔会翻书看后面利用directX SDK来进行3D游戏动画设计,但总觉得学什么东西都不能急于求成,就像一开始以为bitblt这个函

数很简单,但真正在写代码的时候才发现会遇到很多问题,所以在以后的学习过程中,要做到任何一个简单的程序都不能忽视。

最后还是那几句话,欢迎大家发邮件和我交流游戏编程的经验,也希望大牛们能不吝赐教。

---end

本笔记代码已经上传,欢迎下载:【Visual C++】游戏编程学习笔记之六:多背景循环动画---配套代码

【Visual C++】游戏编程学习笔记之六:多背景循环动画的更多相关文章

  1. 【Visual C++】游戏编程学习笔记之四:透明动画实现

    本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44224963 作者:ZeeCod ...

  2. 【Visual C++】游戏编程学习笔记之八:鼠标输入消息(小demo)

     本系列文章由@二货梦想家张程 所写,转载请注明出处. 作者:ZeeCoder  微博链接:http://weibo.com/zc463717263 我的邮箱:michealfloyd@126.c ...

  3. 【Visual C++】游戏编程学习笔记之七:键盘输入消息

     本系列文章由@二货梦想家张程 所写,转载请注明出处. 作者:ZeeCoder  微博链接:http://weibo.com/zc463717263 我的邮箱:michealfloyd@126.c ...

  4. DirectX 11游戏编程学习笔记之8: 第6章Drawing in Direct3D(在Direct3D中绘制)(习题解答)

            本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com         注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...

  5. DirectX 11游戏编程学习笔记之6: 第5章The Rendering Pipeline(渲染管线)

            本文由哈利_蜘蛛侠原创,转载请注明出处.有问题欢迎联系2024958085@qq.com         注:我给的电子版是700多页,而实体书是800多页,所以我在提到相关概念的时候 ...

  6. 【Visual C++】游戏编程学习笔记之五:单一背景滚动

    本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44224963 作者:ZeeCod ...

  7. 【Visual C++】游戏编程学习笔记之三:游戏循环的使用

     本系列文章由@二货梦想家张程 所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44208419 作者:Zee ...

  8. 【Visual C++】游戏编程学习笔记之九:回合制游戏demo(剑侠客VS巡游天神)

    本系列文章由@二货梦想家张程 所写,转载请注明出处. 作者:ZeeCoder  微博链接:http://weibo.com/zc463717263 我的邮箱:michealfloyd@126.com ...

  9. 【Visual C++】游戏编程学习笔记之二:定时器的使用

    本系列文章由@二货梦想家张程所写,转载请注明出处. 本文章链接:http://blog.csdn.net/terence1212/article/details/44195831 作者:ZeeCode ...

随机推荐

  1. Spark:聚类算法

    Spark:聚类算法 Kmeans聚类 KMeans算法的基本思想是初始随机给定K个簇中心,按照最邻近原则把待分类样本点分到各个簇.然后按平均法重新计算各个簇的质心,从而确定新的簇心.一直迭代,直到簇 ...

  2. Java基础之枚举妙用

    对于枚举,初学Java的时候可能我们就已经接触过了,但是在毕业前,其实一直都不知道真正工作里面枚举是怎么用的,枚举有什么用?接下来,博主就介绍枚举在实际工作中的一种使用场景,本文只适合初级的小菜鸟看哈 ...

  3. Nginx的负载均衡 - 加权轮询 (Weighted Round Robin) 上篇

    Nginx版本:1.9.1 我的博客:http://blog.csdn.net/zhangskd 算法介绍 来看一个简单的Nginx负载均衡配置. http { upstream cluster { ...

  4. maven隐式依赖引起的包冲突

    包冲突 使用maven管理项目时可能会遇到包冲突的情况比如:log4j-over-slf4j.jar 和 slf4j-log4j12.jar这两个包同时一起运行时就会有问题. 这种冲突可能是显式依赖导 ...

  5. Java中循环声明变量方法

    Java循环声明变量 之前想这样做,但是网上一直搜索不到,下面是我的方式 项目中 // 得到需要查询外表的数量,然后分别创建缓存,插入数据多的时候如果编码在缓存里面,就不需要再去查询数据库了.key: ...

  6. Python 自动刷博客浏览量

    哈哈,今天的话题有点那什么了哈.咱们应该秉承学习技术的角度来看,那么就开始今天的话题吧. 思路来源 今天很偶然的一个机会,听到别人在谈论现在的"刷量"行为,于是就激发了我的好奇心. ...

  7. Android初级教程对大量数据的做分页处理理论知识

    有时候要加载的数据上千条时,页面加载数据就会很慢(数据加载也属于耗时操作).因此就要考虑分页甚至分批显示.先介绍一些分页的理论知识.对于具体用在哪里,会在后续博客中更新. 分页信息 1,一共多少条数据 ...

  8. android 特卖列表倒计时卡顿问题

    在Android的开发中,我们经常遇见倒计时的操作,通常使用Timer和Handler共同操作来完成.当然也可以使用Android系统控件CountDownTimer,这里我们封装成一个控件,也方便大 ...

  9. python的u'字符串"(字符编码):字符串前有u,表示字符串以unicode格式存储

    举个例子 >>> s = u'\u6ce8\u91ca' >>> s u'\u6ce8\u91ca' >>> print s 注释 >> ...

  10. 使用TT模板+mvc+wcf实现简单查询

    今天是除夕,小编的这篇博客是掐着点儿发的,在此,祝各位小伙伴新年快乐,身体健康,万事如意:喜从天降,欣喜若狂:喜气盈门,好事成双:好人好运,金玉满堂:神采飞扬,如愿以偿,财源滚滚来,福如东海长:伴随着 ...