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;
}

五、效果

 

    

展开阅读全文

没有更多推荐了,返回首页