Visual C++游戏编程基础之动画显示问题

一、为什么要进行贴图修正

目的是解决恐龙底下的阴影问题,要想办法让它重合,不然看起来不流畅,所以要适当修改即将贴图的坐标;

二、排序贴图

1.为什么要进行排序贴图?

假设有两只恐龙,1号和2号,先贴1号后贴2号,结果可能出现如图遮掩的情况

为了避免这种情况,采用排序贴图;

2.什么是排序贴图?

(1)首先约定,y越小表示越远,y越大表示越近;

(2)建立一个数组,以恐龙的Y坐标作为数组元素,假设有10个,按从小到大排列,这样每次贴图的时候,先贴远处的后贴近处 的,即按数组顺序贴图;

(3)程序采用的排序算法是冒泡排序;

假设有n个数,现在要找出最大的数放到最后一个位置,需要比较n-1次;

然后再找第二大的数,这时候除最后一个数外还有n-1个数,需要比较n-2次;

。。。

最后找第二小的数,这时候就剩两个数,需要比较1次;

由上一共需要找n-1次,这个由外循环控制;而每次循环的比较次数由内循环控制;

 for(i=0;i<n-1;i++) { f = false; for(j=0;j<n-i-1;j++) { if(dra[j+1].y < dra[j].y) { tmp = dra[j+1]; dra[j+1] = dra[j]; dra[j] = tmp; f = true; } }

三、基本思路

1.建立恐龙结构体数组,用来存储要产生的恐龙,每个数据元素是一个结构体变量,其成员变量是恐龙的贴图坐标及方向,方向 无非就是上下左右,这里用0,1,2,3表示;

2.建立switch函数,假设数组大小为10,那么将每个恐龙的方向作为switch的判断条件,从而决定各个恐龙对应的贴图坐标,然 后进行透明处理后显示;

3.显示后随机决定恐龙的移动方向,随机4个方向,假设第一只恐龙,随机表示要往上走,那么接着判断当前恐龙的当前方向, 根据当前方向计算向上走的贴图坐标,适当进行贴图修正,还要注意贴图不能超过窗口范围;

四、代码如下

  #include "stdafx.h" #include <stdio.h> struct dragon { int x,y; int dir;//表示恐龙的移动方向 }; const int draNum = 10; HINSTANCE hInst; HBITMAP draPic[4],bg;//存储恐龙上下左右移动的图案;bg为背景图 HDC hdc,mdc,bufdc; HWND hWnd; DWORD tPre,tNow; int picNum;//记录图号 dragon dra[draNum];//建立数组,产生画面中的恐龙 ATOM MyRegisterClass(HINSTANCE hInstance); BOOL InitInstance(HINSTANCE, int); LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); void MyPaint(HDC hdc); 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); } BOOL InitInstance(HINSTANCE hInstance, int nCmdShow) { HBITMAP bmp; hInst = hInstance; int i; hWnd = CreateWindow("canvas", "绘图窗口" , WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, 0, CW_USEDEFAULT, 0, NULL, NULL, hInstance, NULL); if (!hWnd) { return FALSE; } MoveWindow(hWnd,10,10,640,480,true); ShowWindow(hWnd, nCmdShow); UpdateWindow(hWnd); hdc = GetDC(hWnd); mdc = CreateCompatibleDC(hdc); bufdc = CreateCompatibleDC(hdc); bmp = CreateCompatibleBitmap(hdc,640,480); SelectObject(mdc,bmp); 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; //起始方向,3表示的是初始移动方向向左 dra[i].x = 200; //贴图起始X坐标 dra[i].y = 200; //贴图起始Y坐标 } MyPaint(hdc); return TRUE; } void BubSort(int n)//打破固定贴图顺序,始终由远及近贴图,这样来避免后者掩盖前者的问题! { int i,j; bool f; dragon tmp; for(i=0;i<n-1;i++) { f = false; for(j=0;j<n-i-1;j++) { if(dra[j+1].y < dra[j].y) { tmp = dra[j+1]; dra[j+1] = dra[j]; dra[j] = tmp; f = true; } } if(!f) break; } } void MyPaint(HDC hdc) { int w,h,i; if(picNum == 8) picNum = 0; 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]);//将恐龙的移动方向选取对应位图贴到bufdc 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);//在mdc上进行透明处理 } 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)//共有10个恐龙,首先i=0表示第一只恐龙出来了,这时候产生了0-4中的一个数,假设是1,那么根据第一只恐龙当前的方向(0-4中的一个),来选择下一次贴图的坐标在哪 { 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) { switch (message) { int i; 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; } 

五、效果