游戏编程笔记-起步(三)-贪吃蛇游戏实现
游戏编程笔记-起步
3.贪吃蛇游戏实现

代码下载:http://download.csdn.net/detail/you_lan_hai/3738025
核心代码实现如下,算法描述见 “起步(一)”:
#include "app.h"
#include <string.h>
#include <stdlib.h>
int g_map[100][100];//2维地图
int g_nWidth = 610; //窗口宽度
int g_nHeight = 514;//窗口高度
int g_rows = 0; //地图行数
int g_cols = 0; //地图列数
int g_nSize = 30; //地图方格尺寸
struct Point//二维点
{
int r;//行
int c;//列
};
Point g_snake[1000]; //蛇
int g_nLength = 0; //蛇的长度
int g_nSpeed;
bool g_bLive = true; //是否存活
int g_nSnakeDir = 0; //蛇的当前移动方向。0-左,1-右,2-上,3-下
const Point g_direction[4] = {{0,-1},{0,1},{-1,0},{1,0}};//四个方向运动增量。
Point g_prizePos; //奖子坐标
bool g_bPause = true; //是否暂停
HBRUSH g_brushs[4]; //背景画刷
void setSnakeDir(int dir)//设置蛇的运动方向。
{
if ((dir==0 && g_nSnakeDir==1)
|| (dir==1 && g_nSnakeDir==0)
|| (dir==2 && g_nSnakeDir==3)
|| (dir==3 && g_nSnakeDir==2))//反方向移动则令他暂停
{
g_bPause = true;
return;//直接返回,什么也不做。
}
else
{
g_bPause = false;
g_nSnakeDir = dir;
}
}
void resetLevel()//重置关卡
{
/*初始化地图。将四边初始为障碍,即不可通过。
* 0-可通过,1-障碍,2-奖子,3-蛇
*/
memset(g_map,0,sizeof(g_map));
for (int r=0; r<g_rows; ++r)
{
g_map[r][0] = 1;
g_map[r][g_cols-1] = 1;
}
for (int c=0; c<g_cols; ++c)
{
g_map[0][c] = 1;
g_map[g_rows-1][c] = 1;
}
g_nSpeed = 500;
g_bPause = true;//暂停
g_nSnakeDir = 1;//向右。
g_bLive = true;
g_nLength = 3;//蛇初始有3个结点
g_snake[0].r = 1;//蛇头
g_snake[0].c = 3;
g_snake[1].r = 1;
g_snake[1].c = 2;
g_snake[2].r = 1;
g_snake[2].c = 1;
//把初始状态写入地图
for (int i=0; i<g_nLength; ++i)
{
g_map[g_snake[i].r][g_snake[i].c] = 3;
}
//初始化奖子坐标
g_prizePos.r = 1;
g_prizePos.c = g_cols-2;
}
void init()//游戏初始化
{
g_brushs[0] = CreateSolidBrush(RGB(255,255,255));//白色画刷
g_brushs[1] = CreateSolidBrush(RGB(0,0,255));//绘制障碍画刷
g_brushs[2] = CreateSolidBrush(RGB(255,0,0));//绘制奖子画刷
g_brushs[3] = CreateSolidBrush(RGB(0,255,0));//绘制蛇画刷
srand(GetTickCount());
//矫正窗口高度、宽度数据
RECT rc;
GetClientRect(getHWnd(),&rc);
g_nWidth = rc.right - rc.left;
g_nHeight = rc.bottom - rc.top;
//计算行列值
g_rows = g_nHeight / g_nSize;
g_cols = g_nWidth / g_nSize;
resetLevel();
}
void update()//逻辑更新
{
//时钟控制
static int oldTime = 0;
int curTime = GetTickCount();
if (curTime - oldTime < g_nSpeed)
{
return ;
}
oldTime = curTime;
//////////////////////////////////////////////////////////////////////////
static int lastOcurTime = 0;//奖子上次出现的时间
if(curTime - lastOcurTime > 10000)//每隔10s更新一次位置。
{
//lastOcurTime不为-1表示,没有被吃掉,则将原来位置的奖子从地图擦掉。
if (lastOcurTime != -1)
{
g_map[g_prizePos.r][g_prizePos.c] = 0;
}
lastOcurTime = curTime;
//随机产生奖子位置。
bool flag = true;
while(flag)
{
g_prizePos.r = rand()%(g_rows-2)+1;
g_prizePos.c = rand()%(g_cols-2)+1;
if (g_map[g_prizePos.r][g_prizePos.c] == 0)//符合条件
{
flag = false;
g_map[g_prizePos.r][g_prizePos.c] = 2;
}
}
}
if (!g_bLive || g_bPause)//死亡或暂停
{
return ;
}
//先判断是否可走,即是否撞死。
Point newHead;
newHead.r = g_snake[0].r + g_direction[g_nSnakeDir].r;
newHead.c = g_snake[0].c + g_direction[g_nSnakeDir].c;
if (g_map[newHead.r][newHead.c]==1 || g_map[newHead.r][newHead.c]==3)
{
g_bLive = false;
if(IDYES == MessageBox(getHWnd(),L"你撞死啦!是否重新来过?",
L"撞死提示",MB_YESNO))
{
resetLevel();
}
else
{
PostQuitMessage(0);
}
return ;
}
else if (g_map[newHead.r][newHead.c] == 2)//遇到奖子
{
++g_nLength ;
lastOcurTime = -1;
g_nSpeed -= 10;
}
else
{
//撤销尾部在地图上遗留数据
g_map[g_snake[g_nLength-1].r][g_snake[g_nLength-1].c] = 0;
}
memmove(g_snake+1,g_snake,sizeof(Point)*(g_nLength-1));//移动蛇的中间数据
g_snake[0].r = newHead.r;
g_snake[0].c = newHead.c;
//添加蛇头数据
g_map[g_snake[0].r][g_snake[0].c] = 3;
//////////////////////////////////////////////////////////////////////////
}
void render()//画面渲染
{
HDC hDC = GetDC(getHWnd()); //获得系统绘图设备
HDC memDC = CreateCompatibleDC(0); //创建辅助绘图设备
HBITMAP bmpBack = CreateCompatibleBitmap(hDC,g_nWidth,g_nHeight);//创建掩码位图(画布)
SelectObject(memDC,bmpBack); //将画布贴到绘图设备上
HPEN penBack = CreatePen(PS_SOLID,1,RGB(255,0,255));//创建画笔
SelectObject(memDC,penBack); //将画笔选到绘图设备上
//擦除背景
RECT rcClient;//区域结构
GetClientRect(getHWnd(),&rcClient);//获得客户区域
HBRUSH brushTemp = (HBRUSH)GetStockObject(WHITE_BRUSH);//获得库存物体,白色画刷。
FillRect(memDC,&rcClient,brushTemp);//填充客户区域。
//////////////////////////////////////////////////////////////////////////
//绘制2维网格,矩形画法。
for (int r=0; r<g_rows; ++ r)
{
for (int c=0; c<g_cols; ++c)
{
SelectObject(memDC,g_brushs[g_map[r][c]]);
Rectangle(memDC,c*g_nSize,r*g_nSize,(c+1)*g_nSize,(r+1)*g_nSize);
}
}
//////////////////////////////////////////////////////////////////////////
BitBlt(hDC,0,0,g_nWidth,g_nHeight,memDC,0,0,SRCCOPY);//复制到系统设备上显示
DeleteObject(penBack); //释放画笔资源
DeleteObject(bmpBack); //释放位图资源
DeleteDC(memDC); //释放辅助绘图设备
ReleaseDC(getHWnd(),hDC); //归还系统绘图设备
Sleep(10);
}
void clear()//资源释放
{
//释放画刷资源
for (int i=0; i<4; ++i)
{
if(g_brushs != NULL)
{
DeleteObject(g_brushs[i]);
g_brushs[i] = NULL;
}
}
}
/*窗口过程。如果没有处理消息请返回0,否则返回1。*/
LRESULT wndProc(HWND hwnd,UINT uMsg, WPARAM wParam,LPARAM lParam )
{
switch(uMsg)
{
case WM_KEYDOWN:
{
switch(wParam)
{
case VK_LEFT: setSnakeDir(0); break; //向左
case VK_RIGHT: setSnakeDir(1); break; //向右
case VK_UP : setSnakeDir(2); break; //向上
case VK_DOWN: setSnakeDir(3); break; //向下
case VK_ESCAPE: DestroyWindow(hwnd);break;
}
}
break;
default:
return 0;
}
return 1;
}
//主函数
int WINAPI WinMain( HINSTANCE hInstance, HINSTANCE , LPSTR , int )
{
if(!initApp(hInstance,L"贪吃蛇游戏",g_nWidth,g_nHeight))
{
return 0;
}
//初始化游戏
init();
//游戏循环
mainLoop();
//释放资源
clear();
return 0;
}

浙公网安备 33010602011771号