[c]代碼庫
#include
#include
#include
#include
#include
/// 游戲活動區(qū)域
#define GAME_W? 20
#define GAME_H? 14
/// 方向
#define UP????? 72
#define DOWN??? 80
#define LEFT??? 75
#define RIGHT?? 77
#define gotoxyInGameAndPrint(x, y, color, ch) gotoxyAndPrint(x + 1, y + 1, color, ch)
/// 蛇結(jié)點
typedef?struct
{
????int?x;
????int?y;
}Node;
/// 游戲相關(guān)數(shù)據(jù)
typedef?struct
{
????int?map [GAME_H][GAME_W];?// 二維數(shù)組蛮艰,用于碰撞檢測
????Node??? snake [GAME_H * GAME_W];?// 蛇身
????double?speed;?// 速度
????int?length;?// 蛇身長度
????int?director;?// 蛇頭當前方向
????Node??? food;?// 食物(坐標)
????bool?pause;?// 游戲暫停
????bool?dead;?// 是否死亡
}Data;
/// 句柄
HANDLE?g_hConsoleHandl;
Data gameData;
//-------------------------------------------------------------------
//
// 函數(shù)聲明
//
//-------------------------------------------------------------------
void?gotoxyAndPrint (int?x,?int?y, unsigned color,?char* ch);?// 設(shè)置光標位置并打印
void?onEnter ();?// 游戲開始前的處理
void?gameMenu ();?// 游戲菜單
void?lostGame ();?// 游戲失敗
void?drawGameBorder (int?w,?int?h);?// 繪制游戲邊界
void?printPrompting ();?// 顯示提示信息
void?printGameData (Data* data);?// 顯示游戲數(shù)據(jù)
void?initGame (Data* data);?// 初始化游戲數(shù)據(jù)
void?runGame (Data* data);?// 運行游戲
void?keyDownControl (Data* data,?char?key);?// 鍵盤按鍵控制
Node getNewPos (Data* data);
void?move (Data* data);?// 移動蛇
void?updateMap (Data* data);?// 更新 map
void?repaint (Data* data);?// 刷新畫面
void?createFood (Data* data);?// 生成食物
bool?isEatDood (Data* data);?// 判斷前方是否有食物可吃
void?eatFood (Data* data);?// 吃食物
bool?isDead (Data* data);?// 是否死亡(結(jié)束游戲)
//-------------------------------------------------------------------
//
// 主函數(shù) main()
//
//-------------------------------------------------------------------
int?main ()
{
????onEnter ();
????while?( TRUE ) {
????????gameMenu ();
????????initGame (&gameData);
????????runGame (&gameData);
????????lostGame ();
????}
????system?("pause");
????return?0;
}
//
// 游戲開始前的處理
//
void?onEnter ()
{
????g_hConsoleHandl = GetStdHandle (STD_OUTPUT_HANDLE);?// 獲取標準輸出句柄
????CONSOLE_CURSOR_INFO cursorInfo = { 1, FALSE };?// 光標信息
????SetConsoleCursorInfo (g_hConsoleHandl, &cursorInfo);?// 隱藏光標
????system?("title GameSnake");?// 設(shè)置控制臺窗口標題
}
//
// 設(shè)置光標位置
//
void?gotoxyAndPrint (int?x,?int?y, unsigned color,?char* ch)
{
????COORD pos;
????pos.X = x << 1;
????pos.Y = y;
????// 移動到目標
????SetConsoleTextAttribute (g_hConsoleHandl, color);
????// 設(shè)置顏色
????SetConsoleCursorPosition (g_hConsoleHandl, pos);
????printf?("%s", ch);
}
//
// 游戲菜單
//
void?gameMenu ()
{
????gotoxyAndPrint (15, 5, 0x0F,?"┏━━━━━┓");
????gotoxyAndPrint (15, 6, 0x0F,?"");
????printf?("┃? %s? ┃",?"貪食蛇");
????gotoxyAndPrint (15, 7, 0x0F,?"┗━━━━━┛");
????gotoxyAndPrint (14, 10, 0x0F,?" 按任意鍵開始游戲 ");
????while?( _getch () ) {
????????system?("cls");
????????break;
????}
}
//
// 游戲失敗
//
void?lostGame ()
{
????gotoxyAndPrint (6, 6, 0x7,?"死亡J僮谩!按任意鍵返回");
????// pause 會顯示 按任意鍵退出?
????// pause>nul 就是將顯示的內(nèi)容重定向到nul 就是 不顯示按任意鍵退出
????system?("pause > nul");
????system?("cls");?// 清屏
}
//
// 是否死亡(結(jié)束游戲)
//
bool?isDead (Data* data)
{
????Node pos = getNewPos (data);
????return?( pos.x < 0 || pos.x > GAME_W - 1 || pos.y < 0 || pos.y > GAME_H - 1 || data->map [pos.y][pos.x] );
}
//
// 初始化游戲數(shù)據(jù)
//
void?initGame (Data* data)
{
????// 設(shè)置隨機種子
????srand?(( unsigned?int?)?time?(NULL));
????// 將 dot(游戲數(shù)據(jù)) 和 node(蛇身) 全部置0
????memset?(data, 0,?sizeof( Data ));
????memset?(data->snake, 0,?sizeof( Node ) * 50);
????// 初始化數(shù)據(jù)
????data->length = 1;?// 蛇長度為 1
????data->director = RIGHT;?// 開始時方向向右
????data->dead = FALSE;?// 不暫停
????data->speed = 0.3;?// 速度
????// 創(chuàng)建蛇身
????data->snake [1].x =?rand?() % ( GAME_W - 5 );
????data->snake [1].y =?rand?() % GAME_H;
????data->snake [0] = data->snake [1];
????// 生成食物
????createFood (data);
????drawGameBorder (GAME_W, GAME_H);?// 繪制邊界
????printPrompting ();?// 顯示提示信息
????printGameData (&gameData);?// 顯示游戲數(shù)據(jù)
}
//
// 繪制游戲邊界
//
void?drawGameBorder (int?w,?int?h)
{
????int?x, y;
????// 打印上下邊界
????for?( x = 0; x < w + 1; x++ ) {
????????gotoxyAndPrint (x, 0, 0x7,?"■");
????????gotoxyAndPrint (x, h + 1, 0x7,?"■");
????}
????// 打印左右邊界
????for?( y = 0; y < h + 2; y++ ) {
????????gotoxyAndPrint (0, y, 0x7,?"■");
????????gotoxyAndPrint (w + 1, y, 0x7,?"■");
????}
}
//
// 顯示提示信息
//
void?printPrompting ()
{
????gotoxyAndPrint (GAME_W + 4, 1, 0x9,?"■游戲提示:");
????gotoxyAndPrint (GAME_W + 4, 3, 0x9,?"□向下移動:↓");
????gotoxyAndPrint (GAME_W + 4, 4, 0x9,?"□向上移動:↑");
????gotoxyAndPrint (GAME_W + 4, 5, 0x9,?"□向左移動:←");
????gotoxyAndPrint (GAME_W + 4, 6, 0x9,?"□向右移動:→");
????gotoxyAndPrint (GAME_W + 4, 7, 0x9,?"□暫停游戲:回車");
????gotoxyAndPrint (GAME_W + 4, 8, 0x9,?"□提升速度:空格");
}
//
// 顯示游戲數(shù)據(jù)
//
void?printGameData (Data* data)
{
????int?startY = 10;?// 垂直方向的起始坐標
????// GAME_W + 4 : 右邊界在空 2 格
????gotoxyAndPrint (GAME_W + 4, startY, 0xD,?"■游戲數(shù)據(jù):");
????gotoxyAndPrint (GAME_W + 4, startY + 2, 0xD,?"");
????printf?("□移動速度: %.2lf", data->speed);
????gotoxyAndPrint (GAME_W + 4, startY + 3, 0xD,?"");
????printf?("□蛇的長度: %d", data->length);
????gotoxyAndPrint (GAME_W + 4, startY + 4, 0xD,?"");
????printf?("□食物位置:( %2d - %2d )? ", data->food.x, data->food.y);
????gotoxyAndPrint (GAME_W + 4, startY + 5, 0xD,?"");
????printf?("□蛇頭位置:( %2d - %2d )? ", data->snake [data->length].x, data->snake [data->length].y);
}
//
// 根據(jù)蛇頭的方向,獲取蛇頭下一個位置的坐標
//
Node getNewPos (Data* data)
{
????// 獲取蛇頭的坐標
????Node newPos = data->snake [data->length];
????// 根據(jù)蛇頭的方向墩蔓,獲取蛇頭下一個位置的坐標
????switch?( data->director ) {
????case?UP:
????????newPos.y--;
????????break;
????case?DOWN:
????????newPos.y++;
????????break;
????case?LEFT:
????????newPos.x--;
????????break;
????case?RIGHT:
????????newPos.x++;
????????break;
????}
????return?newPos;
}
//
// 移動蛇
//
void?move (Data* data)
{
????// 判斷前方是否有食物烂瘫,如果有食物扎即,先吃掉食物醒第,再生成新的食物
????if?( isEatDood (data) ) {
????????eatFood (data);?// 吃掉食物
????????createFood (data);?// 生成新的食物
????????return;
????}
????// 判斷是否死亡(即碰到邊界 或 自己)
????if?( isDead (data) ) {
????????data->dead = TRUE;?// 標記為死亡,退出游戲循環(huán)
????????return;
????}
????// 實現(xiàn)蛇的移動
????memmove?(data->snake, data->snake + 1,?sizeof( data->snake [0] ) * data->length);
????data->snake [data->length] = getNewPos (data);
????updateMap (data);?// 更新 map
????repaint (data);?// 重繪蛇
????printGameData (data);?// 刷新游戲數(shù)據(jù)
}
//
// 刷新畫面
//
void?repaint (Data* data)
{
????// 先擦除尾巴
????gotoxyInGameAndPrint (data->snake [0].x, data->snake [0].y, 0xC,?" ");
????// 新顯示蛇頭
????gotoxyInGameAndPrint (data->snake [data->length].x, data->snake [data->length].y, 0xC,?"■");
}
//
// 更新 map
//
void?updateMap (Data* data)
{
????data->map [data->snake [data->length].y][data->snake [data->length].x] = 1;
????data->map [data->snake [0].y][data->snake [0].x] = 0;
}
//
// 生成食物
//
void?createFood (Data* data)
{
????// 獲取隨機坐標
????int?x = 0, y = 0;
????do?{
????????x =?rand?() % GAME_W;
????????y =?rand?() % GAME_H;
????}?while?( data->map [y][x] );
????// 設(shè)置食物坐標
????data->food.x = x;
????data->food.y = y;
????// 繪制食物
????gotoxyInGameAndPrint (data->food.x, data->food.y, 0xA,?"■");
}
//
// 判斷前方是否有食物可吃
//
bool?isEatDood (Data* data)
{
????Node pos = getNewPos (data);?// 獲取蛇頭的下一個位置坐標
????// 判斷是否和食物坐標重合
????return?( pos.x == data->food.x && pos.y == data->food.y );
}
//
// 吃食物
//
void?eatFood (Data* data)
{
????// 增加蛇身長度
????data->snake [data->length + 1] = getNewPos (data);
????data->length++;?// 蛇長度 + 1
????updateMap (data);?// 更新 map
????// 繪制新的節(jié)點
????gotoxyInGameAndPrint (data->snake [data->length].x, data->snake [data->length].y, 0xC,?"■");
????printGameData (data);?// 刷新游戲數(shù)據(jù)
}
//
// 運行游戲
//
void?runGame (Data* data)
{
????char?key;
????clock_t?clockLast, clockNow;
????clockLast =?clock?();?// 獲取第一次計時
????while?( !data->dead ) {
????????// 獲取鍵盤輸入
????????while?( _kbhit () ) {
????????????key = _getch ();
????????????// TODO: 相關(guān)鍵盤控制代碼
????????????keyDownControl (data, key);
????????}
????????// 暫停
????????if?( data->pause ) {
????????????continue;
????????}
????????clockNow =?clock?();?// 獲取當前計時
????????// 如果時間間隔 > speed
????????if?( clockNow - clockLast > data->speed * CLOCKS_PER_SEC )
????????{
????????????clockLast = clockNow;
????????????// TODO: 相關(guān)游戲邏輯代碼
????????????move (data);
????????}
????}
}
//
// 鍵盤控制處理
//
void?keyDownControl (Data* data,?char?key)
{
????// 暫停
????if?( key == 13 ) {
????????data->pause = !data->pause;
????}
????// 不處理
????if?( data->pause ) {
????????return;
????}
????switch?( key ) {
????case?72:?/* 上 */
????????if?( data->director != DOWN ) {
????????????data->director = UP;
????????}
????????break;
????case?80:?/* 下 */
????????if?( data->director != UP ) {
????????????data->director = DOWN;
????????}
????????break;
????case?75:?/* 左 */
????????if?( data->director != RIGHT ) {
????????????data->director = LEFT;
????????}
????????break;
????case?77:?/* 右 */
????????if?( data->director != LEFT ) {
????????????data->director = RIGHT;
????????}
????????break;
????case?' ':
????????data->speed -= 0.05;
????????break;
????}
}