游戏编程总结(三) 打砖块2.0版

 
还是看那本游戏编程书,我突发奇想,想写书上的第一个游戏。打砖块。
因为那本书的代码风格和我的不一样,所以只能参考他的代码。
他的结构是:设定了若干个游戏状态,然后对于不同的状态,做不同的事情。
 
而我的代码则没有这么麻烦,直接就是三个状态:
1、游戏初始化
2、开始游戏
3、结束
 
游戏的一些截图:

图片

 

游戏结束:

图片

 

当然了,任意时刻按下ESC键就会退出,当life减为0的时候,按下F1就会重新开始游戏。

 

这里说明一下:

为什么游戏是2.0版本,而不是1.0版本。

因为最先开始1.0版本的时候我想的是干脆就不要life这个参数,球掉到屏幕的下方的时候。照样弹起来,不过分数减去100分

后来听了车韵的意见,加入了生命值这个参数。

并且加入提示语句。每过一次关卡,小球的横向速度和纵向速度都会增加2

也就是说,速度增加2*sqrt(2)

另外每一关的砖块分数会比上一关多一点。

 

 

 游戏还是那样。分成三个部分。初始化的时候把所有表面都创建好。然后调色板也创建好。

当然,其中有一个很重要的一步,就是去宏定义很多参数

比如每一个砖块的宽度和高度,以及砖块与砖块之间的间距。

游戏的时候,需要做碰撞检测以及绘画,还有检测键盘消息等

最后退出的时候释放掉内存即可。

 

当然程序的其他重点还有:

1、碰撞检测。

怎么样方便的碰撞检测,判断当前的小球是否碰到砖块或者屏幕边界

碰到的话,就需要更改方向。

检测碰撞,这个要利用每一个砖块的的每一条边都是要么垂直于屏幕的一个边,要门水平。

所以我们就可以不用去写砖块的每一条边的解析式,然后做线段与射线的交点。

这个已经涉及到非常复杂的计算几何算法。

一种比较简单的写法是:

(ball_cx>x)&&(ball_cx<x+BLOCK_WIDTH)&&(ball_cy>y&&ball_cy<y+BLOCK_HEIGHT)

如果同时满足这四个条件,那么球必然碰撞了砖块。

 

 

2、碰撞后的折返

更改方向这个其实不好想。

首先,如果单纯的从解析几何的角度去设一条直线为y=kx+b,然后各种计算。这样的话必然要考虑斜率为0和无穷大的两种非常特殊的情况

另外,如果这样写,势必会产生大量的浮点数。精度损失,效率低下,计算复杂各种悲剧的事情就会接踵而至。

一个比较好的方法是:

把速度分解为x方向和y方向。两个分量

如果碰撞,则把相应的方向速度设置为反向。这样就大大的简化了计算

 

 

改进方向:

可以增加游戏的趣味性,比如增加一些道具,可以把下面的乒乓球板扩大等等

另外还可以每5000分或者更高的时候,增加一条生命。

 

 

 

#pragma comment(lib,"dxguid.lib") 
#include<stdio.h>
#include<windows.h>
#include<time.h>
#include<stdlib.h>
#include<ddraw.h>

#define KEYDOWN(key) ((GetAsyncKeyState(key) & 0x8000) ? 1 : 0)
#define KEYUP(key)   ((GetAsyncKeyState(key) & 0x8000) ? 0 : 1)
#define DD_INIT_STRUCT(ddstruct){memset(&ddstruct,0,sizeof(ddstruct));ddstruct.dwSize=sizeof(ddstruct);}
#define SCREEN_WIDTH    640
#define SCREEN_HEIGHT   480
#define SCREEN_BPP      8

#define BLOCK_ROW 6
#define BLOCK_COL 8

#define PADDLE_WIDTH            50
#define PADDLE_HEIGHT           8
#define PADDLE_COLOR            191

#define BLOCK_WIDTH             64
#define BLOCK_HEIGHT            16
#define BLOCK_ORIGIN_X          8
#define BLOCK_ORIGIN_Y          8
#define BLOCK_X_GAP             80
#define BLOCK_Y_GAP             32

#define BALL_SIZE                4

UCHAR *double_buffer = NULL;
LPDIRECTDRAW7 lpdd=NULL;
LPDIRECTDRAWSURFACE7 lpddsprimary=NULL;
LPDIRECTDRAWSURFACE7 lpddsback=NULL;
DDSURFACEDESC2 ddsd;
LPDIRECTDRAWPALETTE lpddpal=NULL;
PALETTEENTRY palette[256];
UCHAR blocks[BLOCK_ROW][BLOCK_COL];

#define _RGB16BIT555(r,g,b) ((b&31)+((g&31)<<5)+((r&31)<<10))
#define _RGB16BIT565(r,g,b) ((b&31)+((g&63)<<5)+((r&31)<<11))
#define _RGB32BIT(a,r,g,b) ((b)+((g)<<8)+((r)<<16)+((a)<<24))

struct BALL
{
	int x;
	int y;
	int xv;
	int yv;
};
struct PADDLE
{
	int x;
	int y;
	int v;
};
PADDLE paddle;
BALL ball;
int block_hit;
int score=0;
int level=0;
int life=3;
int count=0;

void Plot_Pixel_Faster32(int x,int y,int a,int r,int g,int b,UINT *video_buffer,int lpitch32)
{
	UINT color;
	color=_RGB32BIT(a,r,g,b);
	video_buffer[x+y*lpitch32]=color;
}

HWND hwd;
HINSTANCE hIns;

LRESULT CALLBACK WinSunProc(
	HWND hwnd,
	UINT uMsg,
	WPARAM wParam,
	LPARAM lParam
)
{
	HDC hdc;
	PAINTSTRUCT ps;
	switch(uMsg)
	{
	case WM_PAINT:
		hdc=BeginPaint(hwnd,&ps);

		EndPaint(hwnd,&ps);
		break;
	case WM_DESTROY:
		PostQuitMessage(0);
		break;
	default:
		break;
	}
	return DefWindowProc(hwnd,uMsg,wParam,lParam);
}

LPDIRECTDRAWCLIPPER DDraw_Attach_Clipper(LPDIRECTDRAWSURFACE7 lpdds,int num_rects,LPRECT clip_list)
{
	int index;
	LPDIRECTDRAWCLIPPER lpddclipper;
	LPRGNDATA region_data;
	if (FAILED(lpdd->CreateClipper(0,&lpddclipper,NULL)))
		return(NULL);
	region_data=(LPRGNDATA)malloc(sizeof(RGNDATAHEADER)+num_rects*sizeof(RECT));
	memcpy(region_data->Buffer,clip_list,sizeof(RECT)*num_rects);
	region_data->rdh.dwSize=sizeof(RGNDATAHEADER);
	region_data->rdh.iType=RDH_RECTANGLES;
	region_data->rdh.nCount=num_rects;
	region_data->rdh.nRgnSize=num_rects*sizeof(RECT);
	region_data->rdh.rcBound.left=64000;
	region_data->rdh.rcBound.top=64000;
	region_data->rdh.rcBound.right=-64000;
	region_data->rdh.rcBound.bottom=-64000;
	for(index=0;index<num_rects;index++)
    {
		if (clip_list[index].left<region_data->rdh.rcBound.left)
			region_data->rdh.rcBound.left=clip_list[index].left;
		if (clip_list[index].right>region_data->rdh.rcBound.right)
			region_data->rdh.rcBound.right=clip_list[index].right;
		if (clip_list[index].top<region_data->rdh.rcBound.top)
			region_data->rdh.rcBound.top=clip_list[index].top;
		if (clip_list[index].bottom>region_data->rdh.rcBound.bottom)
			region_data->rdh.rcBound.bottom=clip_list[index].bottom;
    }
	if(FAILED(lpddclipper->SetClipList(region_data, 0)))
	{
		free(region_data);
		return(NULL);
	}
	if(FAILED(lpdds->SetClipper(lpddclipper)))
	{
		free(region_data);
		return(NULL);
	}
	free(region_data);
	return(lpddclipper);
}

int Draw_Text_GDI(char *text,int x,int y,int color,LPDIRECTDRAWSURFACE7 lpdds=lpddsback)
{
	HDC xdc;
	if (lpdds->GetDC(&xdc)!=DD_OK)
		return(0);
	SetTextColor(xdc,RGB(palette[color].peRed,palette[color].peGreen,palette[color].peBlue));
	SetBkMode(xdc,TRANSPARENT);
	TextOut(xdc,x,y,text,strlen(text));
	lpdds->ReleaseDC(xdc);
	return(1);
}

int DDraw_Fill_Surface(LPDIRECTDRAWSURFACE7 lpdds,int color)
{
	DDBLTFX ddbltfx;
	DD_INIT_STRUCT(ddbltfx);
	ddbltfx.dwFillColor=color;
	lpdds->Blt(NULL,NULL,NULL,DDBLT_COLORFILL|DDBLT_WAIT,&ddbltfx);
	return(1);
}

void Draw_Rectangle(int x1,int y1,int x2,int y2,int color,LPDIRECTDRAWSURFACE7 lpdds=lpddsback)
{
	DDBLTFX ddbltfx;
	RECT fill_rect;

	fill_rect.left=x1;
	fill_rect.top=y1;
	fill_rect.right=x2;
	fill_rect.bottom=y2;
	
	DD_INIT_STRUCT(ddbltfx);
	ddbltfx.dwFillColor=color;

	lpddsback->Blt(&fill_rect,NULL,NULL,DDBLT_COLORFILL|DDBLT_WAIT,&ddbltfx);
}

void Game_Init()
{
	if(FAILED(DirectDrawCreateEx(NULL,(void**)&lpdd,IID_IDirectDraw7,NULL)))
		return;
	if(FAILED(lpdd->SetCooperativeLevel(hwd,DDSCL_FULLSCREEN|DDSCL_ALLOWMODEX|DDSCL_EXCLUSIVE|DDSCL_ALLOWREBOOT)))
		return;
	if(FAILED(lpdd->SetDisplayMode(SCREEN_WIDTH,SCREEN_HEIGHT,SCREEN_BPP,0,0)))
		return;
	DD_INIT_STRUCT(ddsd);
	ddsd.dwFlags=DDSD_CAPS|DDSD_BACKBUFFERCOUNT;
	ddsd.dwBackBufferCount=1;
	ddsd.ddsCaps.dwCaps = DDSCAPS_PRIMARYSURFACE|DDSCAPS_COMPLEX|DDSCAPS_FLIP;
	if(FAILED(lpdd->CreateSurface(&ddsd,&lpddsprimary,NULL)))
		return;
	ddsd.ddsCaps.dwCaps=DDSCAPS_BACKBUFFER;
	if(FAILED(lpddsprimary->GetAttachedSurface(&ddsd.ddsCaps,&lpddsback)))
		return;
	int index;
	for(index=0;index<256;index++)
    {
		if(index<64)
			palette[index].peRed=index*4; 
		else if(index>=64&&index<128) 
			palette[index].peGreen=(index-64)*4;
		else if(index>=128&&index<192) 
			palette[index].peBlue=(index-128)*4;
		else if(index>=192&&index<256) 
			palette[index].peRed=palette[index].peGreen=palette[index].peBlue = (index-192)*4;
		palette[index].peFlags = PC_NOCOLLAPSE;
    }
	if(FAILED(lpdd->CreatePalette(DDPCAPS_8BIT|DDPCAPS_ALLOW256|DDPCAPS_INITIALIZE,palette,&lpddpal,NULL)))
		return;
	if(FAILED(lpddsprimary->SetPalette(lpddpal)))
		return;
	DDraw_Fill_Surface(lpddsprimary,0);
	DDraw_Fill_Surface(lpddsback,0);

	RECT screen_rect={0,0,SCREEN_WIDTH-1,SCREEN_HEIGHT-1};
	DDraw_Attach_Clipper(lpddsback,1,&screen_rect);

	srand(time(NULL));
	memset(&ball,0,sizeof(ball));
	ball.x=SCREEN_WIDTH/2;
	ball.y=SCREEN_HEIGHT/2;
	while(ball.xv==0)
		ball.xv=rand()%8-4;
	while(ball.yv==0)
		ball.yv=rand()%8-4;
	
	paddle.x=(SCREEN_WIDTH/2-16);
	paddle.y=SCREEN_HEIGHT-32;

	int i,j;
	for(i=0;i<BLOCK_ROW;i++)
		for(j=0;j<BLOCK_COL;j++)
			blocks[i][j]=i*16+j*6+16;
	block_hit=0;
	paddle.v=12;
}

void Draw_Blocks()
{
	int x1=BLOCK_ORIGIN_X;
	int y1=BLOCK_ORIGIN_Y;

	int i,j;
	for(i=0;i<BLOCK_ROW;i++)
	{
		x1=BLOCK_ORIGIN_X;
		for(j=0;j<BLOCK_COL;j++)
		{
			if(blocks[i][j])
			{
				Draw_Rectangle(x1-4,y1+4,x1+BLOCK_WIDTH-4,y1+BLOCK_HEIGHT+4,0);
				Draw_Rectangle(x1,y1,x1+BLOCK_WIDTH,y1+BLOCK_HEIGHT,blocks[i][j]);
			}
			x1=x1+BLOCK_X_GAP;
		}
		y1=y1+BLOCK_Y_GAP;
	}
}

void Game_Main()
{
	if(KEYDOWN(VK_ESCAPE))
		PostMessage(hwd,WM_DESTROY,0,0);
	
	Draw_Rectangle(0,0,SCREEN_WIDTH-1,SCREEN_HEIGHT-1,200);
	char buffer[150];

	if(KEYDOWN(VK_RIGHT))
	{
		paddle.x=paddle.x+paddle.v;
		if(paddle.x>SCREEN_WIDTH-PADDLE_WIDTH)
			paddle.x=SCREEN_WIDTH-PADDLE_WIDTH;
	}

	if(KEYDOWN(VK_LEFT))
	{
		paddle.x=paddle.x-paddle.v;
		if(paddle.x<0)
			paddle.x=0;
	}

	Draw_Blocks();

	ball.x=ball.x+ball.xv;
	ball.y=ball.y+ball.yv;

	Draw_Rectangle(ball.x-4,ball.y+4,ball.x+BALL_SIZE-4,ball.y+BALL_SIZE+4,0);
	Draw_Rectangle(ball.x,ball.y,ball.x+BALL_SIZE,ball.y+BALL_SIZE,255);

	if((ball.x>=SCREEN_WIDTH-BALL_SIZE)||(ball.x<=0))
	{
		ball.xv=-ball.xv;
		ball.x=ball.x+ball.xv;
	}

	if(ball.y<=0)
	{
		ball.yv=-ball.yv;
		ball.y=ball.y+ball.yv;
	}

	if(ball.y>=SCREEN_HEIGHT-BALL_SIZE)
	{
		ball.yv=-ball.yv;
		ball.y=ball.y+ball.yv;
		life--;
		memset(&ball,0,sizeof(ball));
		ball.x=SCREEN_WIDTH/2;
		ball.y=SCREEN_HEIGHT/2;
		while(ball.xv==0)
			ball.xv=rand()%8-4;
		while(ball.yv==0)
			ball.yv=rand()%8-4;
		paddle.x=SCREEN_WIDTH/2-16;
		paddle.y=SCREEN_HEIGHT-32;
		Sleep(1500);
	}
	Draw_Rectangle(paddle.x-4,paddle.y+4,paddle.x+PADDLE_WIDTH-4,paddle.y+PADDLE_HEIGHT+4,0);
	Draw_Rectangle(paddle.x,paddle.y,paddle.x+PADDLE_WIDTH,paddle.y+PADDLE_HEIGHT,PADDLE_COLOR);
	
	sprintf(buffer,"B E A T   B L O C K S 2.0             S C O R E:  %d    L E V E L:  %d    L I F E:  %d",score,level,life);
	Draw_Text_GDI(buffer,8,SCREEN_HEIGHT-16,100);

	if(life==0)
	{
		sprintf(buffer,"G A M E    O V E R    Y O U    G O T:  %d",score);
		Draw_Text_GDI(buffer,SCREEN_WIDTH/2-100,SCREEN_HEIGHT/2,100);
		sprintf(buffer,"P R E S S    F 1    T O    R E S T A R  ,  E S C    T O    Q U I T    T H E    G A M E");
		Draw_Text_GDI(buffer,SCREEN_WIDTH/2-250,SCREEN_HEIGHT/2+16,100);
		ball.xv=0;
		ball.yv=0;
		if(KEYDOWN(VK_F1))
		{
			score=0;
			life=3;
			memset(&ball,0,sizeof(ball));
			ball.x=SCREEN_WIDTH/2;
			ball.y=SCREEN_HEIGHT/2;
			while(ball.xv==0)
				ball.xv=rand()%8-4;
			while(ball.yv==0)
				ball.yv=rand()%8-4;
			paddle.x=SCREEN_WIDTH/2-16;
			paddle.y=SCREEN_HEIGHT-32;
		}
	}

	int i,j;
	int x=BLOCK_ORIGIN_X;
	int y=BLOCK_ORIGIN_Y;
	int ball_cx=ball.x+BALL_SIZE/2;
	int ball_cy=ball.y+BALL_SIZE/2;

	if((ball_cx>paddle.x)&&(ball_cx<paddle.x+PADDLE_WIDTH)&&(ball_cy>paddle.y&&ball_cy<paddle.y+PADDLE_HEIGHT))
	{
		ball.yv=-ball.yv;
		ball.xv=ball.xv+rand()%2-1;
		MessageBeep(MB_OK);
	}

	for(i=0;i<BLOCK_ROW;i++)
	{
		x=BLOCK_ORIGIN_X;
		for(j=0;j<BLOCK_COL;j++)
		{
			if(blocks[i][j])
			{
				if((ball_cx>x)&&(ball_cx<x+BLOCK_WIDTH)&&(ball_cy>y&&ball_cy<y+BLOCK_HEIGHT))
				{
					blocks[i][j]=0;
					ball.yv=-ball.yv;
					score=score+level*50+50;
					ball.xv=ball.xv+rand()%2-1;
					MessageBeep(MB_OK);
				}
			}
			x=x+BLOCK_X_GAP;
		}
		y=y+BLOCK_Y_GAP;
	}
	
	bool flag=false;
	for(i=0;i<BLOCK_ROW;i++)
		for(j=0;j<BLOCK_COL;j++)
			if(blocks[i][j])
				flag=true;
	if(!flag)
	{
		sprintf(buffer,"C O N G R A T U L A T I O N S    Y O U    A R E    P A S S    T H E    L E V E L: %d",level);
		level++;
		Draw_Text_GDI(buffer,SCREEN_WIDTH/2-300,SCREEN_HEIGHT/2,100);
		Sleep(3000);
		Draw_Blocks();
		ball.xv=ball.xv+2;
		ball.yv=ball.yv+2;
		paddle.x=SCREEN_WIDTH/2-16;
		paddle.y=SCREEN_HEIGHT-32;
		paddle.v=paddle.v+3;
	}
	while(FAILED(lpddsprimary->Flip(NULL,DDFLIP_WAIT)));
	Sleep(30);
}

void Game_Shut()
{
	if(lpddpal)
	{
		lpddpal->Release();
		lpddpal=NULL;
	}
	if(lpddsprimary)
	{
		lpddsprimary->Release();
		lpddsprimary=NULL;
	}
	if(lpdd)
	{
		lpdd->Release();
		lpdd=NULL;
	}
}

int WINAPI WinMain(
	HINSTANCE hInstance,
	HINSTANCE hPrevInstance,
	LPSTR lpCmdline,
	int nShowCmd
)
{
	WNDCLASS wndclass;
	wndclass.cbClsExtra=0;
	wndclass.cbWndExtra=0;
	wndclass.hbrBackground=(HBRUSH)GetStockObject(BLACK_BRUSH);
	wndclass.hCursor=LoadCursor(NULL,IDC_ARROW);
	wndclass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
	wndclass.hInstance=hInstance;
	wndclass.lpfnWndProc=WinSunProc;
	wndclass.lpszClassName="bingshen";
	wndclass.lpszMenuName=NULL;
	wndclass.style=CS_HREDRAW|CS_VREDRAW;
//-------------------------------------------	

	HWND hwnd;
	RegisterClass(&wndclass);
//-------------------------------------------
	hwnd=CreateWindow("bingshen","-------bingshen",WS_POPUP|WS_VISIBLE,
		0,0,SCREEN_WIDTH,SCREEN_HEIGHT,
		NULL,NULL,hInstance,NULL);
//-------------------------------------------
	hwd=hwnd;
	HDC hdc=GetDC(hwnd);
	ShowCursor(FALSE);
	hIns=hInstance;

	Game_Init();
	MSG msg;
	while(true)
	{
		DWORD Start_time=GetTickCount();
		if(PeekMessage(&msg,NULL,0,0,PM_REMOVE))
		{
			if(msg.message==WM_QUIT)
				break;
			TranslateMessage(&msg);
			DispatchMessage(&msg);
		}
		Game_Main();
	}
	Game_Shut();
	ReleaseDC(hwnd,hdc);
	return msg.wParam;
}


 

猜你喜欢

转载自blog.csdn.net/xieshimao/article/details/7303643