代码地址:http://download.csdn.net/download/liu_liu213/4015679
/************************************************************************/
/*
1.贴图坐标修正
动画的制作需要多张连续的图片,若这些连续图片规格不一,那么进行贴图时
就需要进行贴图坐标修正,否则就可能产生动画晃动和不顺畅的情况。
2.排序贴图
'排序贴图'的问题源自于物体远近呈现的一种贴图概念,回忆之前贴图方式,对于
距离较远的物体先进行贴图操作,然后再进行近距离物体的贴图操作,而一旦定出
贴图顺序后就无法再改变。这样的做法在画面上物体会彼此遮掩的情况下便不使用。
为了避免这种因贴图顺序固定而产生的错误画面,必须在每一次窗口重绘时动态去重新
排列每一个物体的的贴图顺序。
排序如何运用在贴图中呢? 假设现在又10个需要进行贴图的图案,先把它存在一个数组中,
从2D平面远近角度来看,Y轴较小(在窗口坐标系较上方)的是比较远的物体;若我们一Y轴
坐标来对数组由小到大排序,然后进行贴图时则由数组从小到大一个一个进行处理,
便可实现"远的物体先贴图"的目的了。
(0,0)
|----------+>X
|
|
|
+
Y
这里使用冒泡排序(Bubble Sort)
原因:a.程序代码简单
b.排序效率中等
c.属于稳定(stable)排序法,这个特性会使得Y轴坐标相同的物体,不必再考虑
它X坐标上的排序
*/
/************************************************************************//
#include "stdafx.h"
//全局变量声明
typedef struct tagDRAGON
{
int x,y;
int dir; //方向
}DRAGON;
const int draNum = 10; //代表程序在画面上要出现物体的数目
HINSTANCE hInst;
HBITMAP draPic[4], bg;//draPic[4]存储上下左右移动的连续图案,bg存储背景图
HDC hdc, mdc, bufdc;
HWND hWnd;
DWORD tPre; //上次绘图的时间
DWORD tNow; //此次准备绘图的时间
int picNum;
DRAGON dra[draNum];
//全局函数
void MyPaint(HDC);
ATOM MyRegisterClass(HINSTANCE hInstance);
BOOL InitInstance(HINSTANCE, int);
LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);
//****程序入口**************************************
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
MyRegisterClass(hInstance);
//运行初始化函数
if (!InitInstance (hInstance, nCmdShow))
{
return FALSE;
}
//游戏循环
while (msg.message != WM_QUIT)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
{
tNow = GetTickCount();
if (tNow-tPre >= 100)
{
MyPaint(hdc);
}
}
}
return msg.wParam;
}
//****定义及注册窗口类别函数*************************
ATOM MyRegisterClass(HINSTANCE hInstance)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)WndProc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = hInstance;
wcex.hIcon = NULL;
wcex.hCursor = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)(COLOR_WINDOW+1);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = "canvas"; //类别名称
wcex.hIconSm = NULL;
return RegisterClassEx(&wcex);
}
//****初始化*************************************
// 1.存储instance handle与全局变量中
// 2.建立并显示主窗口
BOOL InitInstance(HINSTANCE hInstance, int nCmdShow)
{
HBITMAP bmp;
int i;
hInst = hInstance;
hWnd = CreateWindow("canvas", "绘图窗口" , WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL);
if (!hWnd)
{
return FALSE;
}
MoveWindow(hWnd,10,10,600,450,true);
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);
hdc = GetDC(hWnd);
mdc = CreateCompatibleDC(hdc);
bufdc = CreateCompatibleDC(hdc);
bmp = CreateCompatibleBitmap(hdc,640,480);
SelectObject(mdc,bmp); //建立一空位图并放入mdc中,用于区别hdc
//加载跑动图及背景图,以0.1.2.3来代表物体的上下左右移动
draPic[0] = (HBITMAP)LoadImage(NULL,"dra0.bmp",IMAGE_BITMAP,528,188,LR_LOADFROMFILE);
draPic[1] = (HBITMAP)LoadImage(NULL,"dra1.bmp",IMAGE_BITMAP,544,164,LR_LOADFROMFILE);
draPic[2] = (HBITMAP)LoadImage(NULL,"dra2.bmp",IMAGE_BITMAP,760,198,LR_LOADFROMFILE);
draPic[3] = (HBITMAP)LoadImage(NULL,"dra3.bmp",IMAGE_BITMAP,760,198,LR_LOADFROMFILE);
bg = (HBITMAP)LoadImage(NULL,"bg.bmp",IMAGE_BITMAP,640,480,LR_LOADFROMFILE);
for(i=0;i<draNum;i++)
{
dra[i].dir = 3; //起始方向
dra[i].x = 200; //贴图起始X坐标
dra[i].y = 200; //贴图起始Y坐标
}//设定初始的贴图坐标都为(200,200),初始的移动方向都为右
MyPaint(hdc);
return TRUE;
}
//冒泡排序
void BubSort(int n){
int i, j;
bool f; //在n-1次内提前完成排序,可避免后续的外层循环
DRAGON tmp;
for(i=0; i<n-1; i++)
{
f = false;
for(j=0; j<n-i-1; j++)
{
if(dra[j].y > dra[j+1].y)
{
tmp = dra[j+1];
dra[j+1] = dra[j];
dra[j] = tmp;
f = true;
}
};
if (!f) break;
}
}
/************************************************************************/
/*
1.对窗口中跑动的物体进行排序贴图
2.物体贴图坐标修正
*/
/************************************************************************/
void MyPaint(HDC hdc){
int w, h, i;
if (picNum == 8){
picNum = 0;
}
//在mdc中先贴上背景图
SelectObject(bufdc, bg);
BitBlt(mdc,0,0,640,480,bufdc,0,0,SRCCOPY);
BubSort(draNum);
for(i=0;i<draNum;i++)
{
SelectObject(bufdc,draPic[dra[i].dir]);
switch(dra[i].dir)
{
case 0:
w = 66;
h = 94;
break;
case 1:
w = 68;
h = 82;
break;
case 2:
w = 95;
h = 99;
break;
case 3:
w = 95;
h = 99;
break;
}
BitBlt(mdc,dra[i].x,dra[i].y,w,h,bufdc,picNum*w,h,SRCAND);
BitBlt(mdc,dra[i].x,dra[i].y,w,h,bufdc,picNum*w,0,SRCPAINT);
}
//将最后画面显示在窗口中
BitBlt(hdc,0,0,640,480,mdc,0,0,SRCCOPY);
//记录此次绘图时间
tPre = GetTickCount();
picNum++;
for(i=0; i<draNum; i++)
{
switch(rand()%4) //随机决定下次移动方向
{
case 0: //上
switch(dra[i].dir)
{
case 0:
dra[i].y -= 20;
break;
case 1:
dra[i].x += 2;
dra[i].y -= 31;
break;
case 2:
dra[i].x += 14;
dra[i].y -= 20;
break;
case 3:
dra[i].x += 14;
dra[i].y -= 20;
break;
}
if(dra[i].y < 0)
dra[i].y = 0;
dra[i].dir = 0;
break;
case 1: //下
switch(dra[i].dir)
{
case 0:
dra[i].x -= 2;
dra[i].y += 31;
break;
case 1:
dra[i].y += 20;
break;
case 2:
dra[i].x += 15;
dra[i].y += 29;
break;
case 3:
dra[i].x += 15;
dra[i].y += 29;
break;
}
if(dra[i].y > 370)
dra[i].y = 370;
dra[i].dir = 1;
break;
case 2: //左
switch(dra[i].dir)
{
case 0:
dra[i].x -= 34;
break;
case 1:
dra[i].x -= 34;
dra[i].y -= 9;
break;
case 2:
dra[i].x -= 20;
break;
case 3:
dra[i].x -= 20;
break;
}
if(dra[i].x < 0)
dra[i].x = 0;
dra[i].dir = 2;
break;
case 3: //右
switch(dra[i].dir)
{
case 0:
dra[i].x += 6;
break;
case 1:
dra[i].x += 6;
dra[i].y -= 10;
break;
case 2:
dra[i].x += 20;
break;
case 3:
dra[i].x += 20;
break;
}
if(dra[i].x > 535)
dra[i].x = 535;
dra[i].dir = 3;
break;
}
}
}
//****回调函数***********************************
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
//PAINTSTRUCT ps;
//HDC hdc;
int i;
switch (message)
{
//case WM_PAINT:
// hdc = BeginPaint(hWnd, &ps);
// EndPaint(hWnd, &ps);
// break;
case WM_DESTROY:
DeleteDC(mdc);
DeleteDC(bufdc);
for(i=0;i<4;i++)
DeleteObject(draPic[i]);
DeleteObject(bg);
ReleaseDC(hWnd,hdc);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}