赞
踩
在之前的C语言小游戏开发系列我们已经介绍了扫雷游戏的开发,本篇我们继续此系列第二篇,同样是比较简单但好玩的一个游戏--贪吃蛇。因为有了之前的游戏框架,我们只需要直接搬来原来的框架即可,可以省去不少活。
先看看游戏效果预览
下面进行详细的逻辑介绍。
贪吃蛇是一款经典的游戏,玩家需要控制一条蛇在屏幕上移动,不断吃掉食物并成长,同时要避免碰到墙壁或自己的身体。蛇在移动过程中会遇到食物,玩家需要让蛇的头部碰到食物,蛇就会自动将食物吞下,并且蛇的长度会相应增加。碰到墙壁或自己的身体就游戏结束。
贪吃蛇游戏的核心逻辑在于蛇的移动和食物的生成。蛇的移动需要精确控制,避免蛇的头部碰到自己的身体或者墙壁,食物的生成需要有一定的随机性,使得游戏有一定的变化性。
我们首先将游戏分三个场景进行绘制,分别是开始前的菜单显示、游戏进行中的场景显示、以及游戏结束界面的显示。我们可以直接用一个全局整型变量g_nGameState来区分场景。在游戏进行时我们主要绘制蛇行走的地图,这个在前面扫雷游戏中有所介绍,大同小异,主要就是一个一维数组实现的二维平面。
int g_nMap[ C_MAP_WIDTH * C_MAP_HEIGHT] = {0};
然后是蛇的表示,我们用一个坐标数组来表示蛇身体所处地图位置。
POINT g_ptSnake[C_SNAKE_MAXLEN];
地图绘制就是根据地图表示的地形绘制出相应内容
- for(j=0;j<C_MAP_HEIGHT;++j)
- {
- for(i=0;i<C_MAP_WIDTH;++i)
- {
- switch( g_nMap[j*C_MAP_WIDTH+i] )
- {
- case enumMAPTYPE_STONE:
- solidrectangle( i*C_IMAGE_BLOCK, j*C_IMAGE_BLOCK, i*C_IMAGE_BLOCK+C_IMAGE_BLOCK, j*C_IMAGE_BLOCK+C_IMAGE_BLOCK);
- break;
- case enumMAPTYPE_FOOD:
- setfillcolor(RGB(0xAA,0x0,0x0));
- solidcircle( i*C_IMAGE_BLOCK+10, j*C_IMAGE_BLOCK+10, 5);
- setfillcolor(RGB(0xAA,0xAA,0xAA));
- break;
- }
-
- }
- }

蛇的行走就只需要根据当前方向进行坐标移动就可以了
- switch( g_nSnakDir )
- {
- case enumDIR_LEFT:
- SnakeMoveTo(g_ptSnake[0].x-1,g_ptSnake[0].y);
- break;
- case enumDIR_RIGHT:
- SnakeMoveTo(g_ptSnake[0].x+1,g_ptSnake[0].y);
- break;
- case enumDIR_UP:
- SnakeMoveTo(g_ptSnake[0].x,g_ptSnake[0].y-1);
- break;
- case enumDIR_DOWN:
- SnakeMoveTo(g_ptSnake[0].x,g_ptSnake[0].y+1);
- break;
- }
以上就是贪吃蛇涉及的主要设计难点,都比较容易理解,就不展开讨论了。
以下就是贪吃蛇的全部主要代码,只是示例程序,所以只设置了一关、有兴趣的同学可以自行扩展代码。
- // GameSnake.cpp : 定义控制台应用程序的入口点。
- //
-
- #include "../import/include/SimpleCG.h"
- #include "GameUI.h"
-
-
- #ifdef _DEBUG
- #pragma comment(lib,"../import/lib/SimpleCG_MDd.lib")
- #else
- #ifdef _WIN64
- #pragma comment(lib,"../import/lib/x64/MTRelease/SimpleCG_MT64.lib")
- #else
- #pragma comment(lib,"../import/lib/SimpleCG_MT.lib")
- #endif
- #endif
-
-
- #define C_SNAK_VERSION 1001
-
- #define C_IMAGE_WIDTH 640
- #define C_IMAGE_HEIGHT 480
- #define C_IMAGE_BLOCK 20
- #define C_MAP_WIDTH C_IMAGE_WIDTH/C_IMAGE_BLOCK
- #define C_MAP_HEIGHT C_IMAGE_HEIGHT/C_IMAGE_BLOCK
- #define C_SNAKE_MAXLEN 50
- enum ENUM_GAMESTATE
- {
- enumGS_MENU
- , enumGS_RUNNING
- , enumGS_GAMEOVER
- };
- enum ENUM_MAPTYPE
- {
- enumMAPTYPE_NULL
- , enumMAPTYPE_STONE
- , enumMAPTYPE_FOOD
- };
- enum ENUM_DIRECTION
- {
- enumDIR_LEFT
- , enumDIR_RIGHT
- , enumDIR_UP
- , enumDIR_DOWN
- };
- int g_nMap[ C_MAP_WIDTH * C_MAP_HEIGHT] = {0};
- int g_nSnakDir = enumDIR_LEFT;
- POINT g_ptSnake[C_SNAKE_MAXLEN];
- int g_nSnakLen = 2;
- int g_nGameState = enumGS_MENU;
- char g_nTitle[] = { 0x4f,0x49,0x49,0x79,0x0,0x7f,0xe,0x30,0x7f,0x0,0x7e,0x9,0x9,0x7e,0x0,0x7f,0x8,0x14,0x63,0x0,0x7f,0x49,0x49,0x49 };
- char g_pGame[] = { 0x7f,0x41,0x5d,0x49,0x7b,0x0,0x7c,0x12,0x11,0x12,0x7c,0x0,0x7f,0x2,0x4,0x2,0x7f,0x0,0x7f,0x49,0x49,0x49,0x49 };
- char g_pOver[] = { 0x7f,0x41,0x41,0x41,0x7f,0x0,0x1f,0x20,0x40,0x20,0x1f,0x0,0x7f,0x49,0x49,0x49,0x49,0x0,0x7f,0x9,0x19,0x29,0x46 };
- int g_nMenu = 0;
- int g_nScore = 0;
- int g_nSpeed = 1;
- LRESULT OnKeyDown(HWND hWnd, WPARAM wParam, LPARAM lParam);
- LRESULT OnLButtonDown( HWND hWnd, WPARAM wParam, int nX, int nY );
- LRESULT OnRButtonDown( HWND hWnd, WPARAM wParam, int nX, int nY );
- LRESULT OnMouseMove( HWND hWnd, WPARAM wParam, int nX, int nY );
- //绘制标题
- void DrawTitle( int nX, int nY, char *pTitle, int nSize);
- void MakeFood()
- {
- bool bFoodSet = false;
- int nRand = 0;
- while(!bFoodSet)
- {
- nRand=rand()%(C_MAP_WIDTH*C_MAP_HEIGHT);
- if(g_nMap[nRand] == enumMAPTYPE_NULL )
- {
- g_nMap[nRand] = enumMAPTYPE_FOOD;
- bFoodSet = true;
- }
- }
- }
- //初始化游戏
- void InitGame(HWND hWnd)
- {
- int i=0;
- int j=0;
- for(j=0;j<C_MAP_HEIGHT;++j)
- {
- for(i=0;i<C_MAP_WIDTH;++i)
- {
- if(i==0||i==C_MAP_WIDTH-1||j==0||j==C_MAP_HEIGHT-1)
- {
- g_nMap[j*C_MAP_WIDTH+i] = enumMAPTYPE_STONE;
- }
- else
- {
- g_nMap[j*C_MAP_WIDTH+i] = enumMAPTYPE_NULL;
- }
-
- }
- }
- g_nSpeed = 1;
- g_nSnakLen = 2;
- g_ptSnake[0].x = 10;
- g_ptSnake[0].y = 10;
- g_ptSnake[1].x = 11;
- g_ptSnake[1].y = 10;
- g_nSnakDir = enumDIR_LEFT;
- srand(GetTickCount());
- MakeFood();
- //按键处理初始化
- //SetKeyboardProcess( enumINMSG_KEYDOWN, OnKeyDown );
- GetKeyboardInput()->onKeyDown = OnKeyDown;
- GetMouseInput()->onMouseDownLeft = OnLButtonDown;
- GetMouseInput()->onMouseDownRight = OnRButtonDown;
- GetMouseInput()->onMouseMove = OnMouseMove;
- g_nGameState = enumGS_MENU;
- }
- //移动蛇
- void SnakeMoveTo(int x, int y)
- {
- int i=0;
- if(x<0 || y<0 || x>=C_MAP_WIDTH || y>=C_MAP_HEIGHT )
- return;
- //GetFood
- if(g_nMap[y*C_MAP_WIDTH+x]==enumMAPTYPE_FOOD)
- {
- g_nMap[y*C_MAP_WIDTH+x]=enumMAPTYPE_NULL;
- g_ptSnake[g_nSnakLen].x = g_ptSnake[g_nSnakLen-1].x;
- g_ptSnake[g_nSnakLen].y = g_ptSnake[g_nSnakLen-1].y;
- if( g_nSnakLen<C_SNAKE_MAXLEN-1)
- g_nSnakLen++;
-
- g_nScore += 10 * g_nSpeed;
- g_nSpeed = g_nSnakLen / 5 + 1;
- MakeFood();
- }
- else if(g_nMap[y*C_MAP_WIDTH+x]==enumMAPTYPE_STONE )//dead
- {
- g_nGameState = enumGS_GAMEOVER;
- return;
- }
- for(i=g_nSnakLen-1;i>0;--i)
- {
- if( g_ptSnake[i].x==x && g_ptSnake[i].y==y )
- {
- g_nGameState = enumGS_GAMEOVER;
- return;
- }
- g_ptSnake[i].x = g_ptSnake[i-1].x;
- g_ptSnake[i].y = g_ptSnake[i-1].y;
- }
- g_ptSnake[0].x = x;
- g_ptSnake[0].y = y;
- }
- //按方向移动
- void MoveFoward()
- {
- switch( g_nSnakDir )
- {
- case enumDIR_LEFT:
- SnakeMoveTo(g_ptSnake[0].x-1,g_ptSnake[0].y);
- break;
- case enumDIR_RIGHT:
- SnakeMoveTo(g_ptSnake[0].x+1,g_ptSnake[0].y);
- break;
- case enumDIR_UP:
- SnakeMoveTo(g_ptSnake[0].x,g_ptSnake[0].y-1);
- break;
- case enumDIR_DOWN:
- SnakeMoveTo(g_ptSnake[0].x,g_ptSnake[0].y+1);
- break;
- }
- }
- //更新游戏状态
- void UpdateGame( UINT nElapse )
- {
- static int s_nLastTick = 0;
- int nWait = 9-g_nSpeed;
- if(nWait<0)
- nWait = 1;
- if( ( nElapse - s_nLastTick )<nWait*50 )
- return;
- switch(g_nGameState)
- {
- case enumGS_MENU:
- break;
- case enumGS_RUNNING:
- s_nLastTick = nElapse;
- MoveFoward();
- break;
- case enumGS_GAMEOVER:
- break;
- }
-
- }
- //绘制地图
- void DrawMap()
- {
- int i=0;
- int j=0;
- setfillcolor(RGB(0xAA,0xAA,0xAA));
- for(j=0;j<C_MAP_HEIGHT;++j)
- {
- for(i=0;i<C_MAP_WIDTH;++i)
- {
- switch( g_nMap[j*C_MAP_WIDTH+i] )
- {
- case enumMAPTYPE_STONE:
- solidrectangle( i*C_IMAGE_BLOCK, j*C_IMAGE_BLOCK, i*C_IMAGE_BLOCK+C_IMAGE_BLOCK, j*C_IMAGE_BLOCK+C_IMAGE_BLOCK);
- break;
- case enumMAPTYPE_FOOD:
- setfillcolor(RGB(0xAA,0x0,0x0));
- solidcircle( i*C_IMAGE_BLOCK+10, j*C_IMAGE_BLOCK+10, 5);
- setfillcolor(RGB(0xAA,0xAA,0xAA));
- break;
- }
-
- }
- }
- }
- //绘制标题
- void DrawTitle( int nX, int nY, char *pTitle, int nSize)
- {
- int i=0;
- int j=0;
- for(i=0;i<nSize;++i)
- {
- int nNum = pTitle[i];
- for(j=0;j<8;++j)
- {
- if(nNum&0x1)
- {
- solidrectangle( nX+i*C_IMAGE_BLOCK, nY+j*C_IMAGE_BLOCK, nX+i*C_IMAGE_BLOCK+C_IMAGE_BLOCK, nY+j*C_IMAGE_BLOCK+C_IMAGE_BLOCK);
-
- }
- nNum>>=1;
- }
- }
- }
- //绘制蛇
- void DrawSnake()
- {
- int i=0;
- setfillcolor(RGB(0x0,0xAA,0x0));
- for(i=0; i<g_nSnakLen; ++i)
- {
- solidrectangle( g_ptSnake[i].x*C_IMAGE_BLOCK, g_ptSnake[i].y*C_IMAGE_BLOCK, g_ptSnake[i].x*C_IMAGE_BLOCK+C_IMAGE_BLOCK, g_ptSnake[i].y*C_IMAGE_BLOCK+C_IMAGE_BLOCK);
- }
- }
- void DrawMenu()
- {
- setfillcolor(RGB(0x0,0xAA,0x0));
- DrawTitle( 60, 60, g_nTitle, sizeof(g_nTitle)/sizeof(g_nTitle[0]));
-
- DrawButton( 200, 260, 120, 30, RGB(0x0,0xDD,0x0), 0, _T("开始游戏"));
- DrawButton( 200, 300, 120, 30, RGB(0x0,0xDD,0x0), 0, _T("退出游戏"));
- setlinecolor(0);
- fillcircle( 180, g_nMenu * 40 + 260 + 15, 10 );
- }
- //绘制游戏
- void RenderGame()
- {
- clearrectangle(0,0,C_IMAGE_WIDTH, C_IMAGE_HEIGHT);
- switch(g_nGameState)
- {
- case enumGS_MENU:
- DrawMenu();
- break;
- case enumGS_RUNNING:
- DrawMap();
- DrawSnake();
- RenderUI();
- break;
- case enumGS_GAMEOVER:
- DrawTitle( 100, 60, g_pGame, sizeof(g_pGame)/sizeof(g_pGame[0]));
- DrawTitle( 100, 220, g_pOver, sizeof(g_pOver)/sizeof(g_pOver[0]));
-
- settextcolor(0);
- printfRectEx( 0, 380, C_IMAGE_WIDTH, 20, SCG_TEXT_MIDDLE, _T("分数: %d"), g_nScore );
- //outtextRectEx( 0, 400, C_IMAGE_WIDTH, 100, _T("Press any key to continue..."), SCG_TEXT_MIDDLE);
- outtextRectEx( 0, 400, C_IMAGE_WIDTH, 100, _T("按任意键继续..."), SCG_TEXT_MIDDLE);
- break;
- }
- }
- //按键消息响应函数
- LRESULT OnKeyDown(HWND hWnd, WPARAM wParam, LPARAM lParam)
- {
- switch( g_nGameState )
- {
- case enumGS_MENU:
- switch( wParam )
- {
- case VK_DOWN:
- if( g_nMenu<1 )
- ++g_nMenu;
- break;
- case VK_UP:
- if( g_nMenu> 0 )
- --g_nMenu;
- break;
- case VK_SPACE:
- case VK_RETURN:
- if( g_nMenu == 1)
- PostQuitMessage(0);
- else
- g_nGameState = enumGS_RUNNING;
- break;
- }
- break;
- case enumGS_RUNNING:
- switch( wParam )
- {
- case VK_DOWN:
- if(g_nSnakDir == enumDIR_LEFT || g_nSnakDir == enumDIR_RIGHT)
- {
- g_nSnakDir = enumDIR_DOWN;
-
- MoveFoward();
- }
- return 1;
- break;
- case VK_UP:
- if(g_nSnakDir == enumDIR_LEFT || g_nSnakDir == enumDIR_RIGHT)
- {
- g_nSnakDir = enumDIR_UP;
-
- MoveFoward();
- }
- return 1;
- break;
- case VK_LEFT:
- if(g_nSnakDir == enumDIR_UP || g_nSnakDir == enumDIR_DOWN)
- {
- g_nSnakDir = enumDIR_LEFT;
-
- MoveFoward();
- }
- return 1;
- break;
- case VK_RIGHT:
- if(g_nSnakDir == enumDIR_UP || g_nSnakDir == enumDIR_DOWN)
- {
- g_nSnakDir = enumDIR_RIGHT;
-
- MoveFoward();
- }
- return 1;
- break;
- }
- break;
- case enumGS_GAMEOVER:
- InitGame(NULL);
- break;
- }
-
- return 0;
- }
-
- LRESULT OnLButtonDown( HWND hWnd, WPARAM wParam, int nX, int nY )
- {
- switch( g_nGameState )
- {
- case enumGS_MENU:
- if( g_nMenu == 1)
- PostQuitMessage(0);
- else
- g_nGameState = enumGS_RUNNING;
- break;
- case enumGS_RUNNING:
- switch(g_nSnakDir )
- {
- case enumDIR_LEFT:
- g_nSnakDir = enumDIR_DOWN;
- break;
- case enumDIR_RIGHT:
- g_nSnakDir = enumDIR_UP;
- break;
- case enumDIR_UP:
- g_nSnakDir = enumDIR_LEFT;
- break;
- case enumDIR_DOWN:
- g_nSnakDir = enumDIR_RIGHT;
- break;
- }
- break;
- case enumGS_GAMEOVER:
- InitGame(NULL);
- break;
- }
- return false;
- }
- LRESULT OnRButtonDown( HWND hWnd, WPARAM wParam, int nX, int nY )
- {
- if( g_nGameState == enumGS_RUNNING)
- {
- switch(g_nSnakDir )
- {
- case enumDIR_LEFT:
- g_nSnakDir = enumDIR_UP;
- break;
- case enumDIR_RIGHT:
- g_nSnakDir = enumDIR_DOWN;
- break;
- case enumDIR_UP:
- g_nSnakDir = enumDIR_RIGHT;
- break;
- case enumDIR_DOWN:
- g_nSnakDir = enumDIR_LEFT;
- break;
- }
- }
- return false;
- }
- LRESULT OnMouseMove( HWND hWnd, WPARAM wParam, int nX, int nY )
- {
- if( g_nGameState == enumGS_MENU)
- {
- if( nY>=300)
- g_nMenu = 1;
- else
- g_nMenu = 0;
- }
- return false;
- }
- int _tmain(int argc, _TCHAR* argv[])
- {
- SCG_GameLoopInfo info;
- info.nFPS = 60;
- info.nHeight = C_IMAGE_HEIGHT;
- info.nWidth = C_IMAGE_WIDTH;
- info.pFunDrawProcess = RenderGame;
- info.pFunFrameUpdate = UpdateGame;
- info.pFunInitGame = InitGame;
- info.pFunInput = NULL;
-
- if( !StartGameLoopEx( &info ))
- return 1;
- return 0;
- }

贪吃蛇完整VS2010工程可在以下地址下载。
gamesnake · master · b2b160 / SimpleCG_Demo · GitCode
编译此程序需安装SimpleCG库,安装方法如下:
如果只想执行程序可在如下地址下载
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。