游戏结束:
当然了,任意时刻按下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; }