头文件
#pragma once
#include<stdio.h>
#include<Windows.h>
#include<stdbool.h>
#include<locale.h>
#include<time.h>
#define KEY_PRESS(vk) ( (GetAsyncKeyState(vk) & 1) ? 1 : 0)
#define POS_X 24
#define POS_Y 5
#define FOOD L'鼠'
#define WALL L'墙'
#define BODY L'蛇'
//类型声明
//蛇方向
enum DIRECTION
{UP = 1,//上DOWM,//下LEFT,//左RIGHT//右
};
//蛇的状态
//正常 撞墙 自撞 正常退出
enum GAME_STATUS
{OK,//正常KILL_BY_WALL,//撞墙KILL_BY_SELF,//撞自己END_NORMAL//推出
};
//蛇身结点类型
typedef struct SnakeNode
{//坐标int x;int y;//指向下一个结点的指针struct SnakeNode* next;
}SnakeNode,* pSnakeNode;
//贪吃蛇
typedef struct Snake
{pSnakeNode _pSnake;//指向蛇头pSnakeNode _pFood;//食物位置enum DIRECTION _dir;//蛇头方向enum GAME_STATUS _status;//状态int _food_weight;//食物分数int _score;//总成绩int _sleep_time;//休息时间
}Snake,*pSnake;
//函数声明
void SetPos(short x, short y);
//游戏初始化
void GameStart(pSnake ps);
//游戏开始
void GameRun(pSnake ps);
//欢迎界面
void WelcomeToGame();
//打印地图
void CreateMap();
//初始化蛇
void InitSnake(pSnake ps);
//创建食物
void CreatteFood(pSnake ps);
//蛇的移动
void SnakeMove(pSnake ps);
//判断吃到了没?
int NextIsFood(pSnakeNode pNextNode,pSnake ps);
//吃了食物
void EatFood(pSnakeNode pNextNode, pSnake ps);
//没吃
void NoFood(pSnakeNode pNextNode, pSnake ps);
//撞墙和撞自己
void KillByWall(pSnake ps);
void KillBySelf(pSnake ps);
//游戏善后
void GameEnd(pSnake ps);
实现文件
#define _CRT_SECURE_NO_WARNINGS
#include"snake.h"
void SetPos(short x, short y)
{COORD pos = { x, y };HANDLE hOutput = NULL;//获取标准输出的句柄(⽤来标识不同设备的数值)hOutput = GetStdHandle(STD_OUTPUT_HANDLE);//设置标准输出上光标的位置为posSetConsoleCursorPosition(hOutput, pos);
}
void WelcomeToGame()
{SetPos(40, 14);printf("欢迎游玩贪吃蛇小游戏\n");SetPos(42, 20);system("pause");system("cls");SetPos(40, 14);wprintf(L"用 ↑ ↓ ← →,按F3加速 按F4减速\n");SetPos(40, 15);wprintf(L"加速分数更高\n");SetPos(42, 20);system("pause");system("cls");SetPos(0, 0);
}
void CreateMap()
{//上int i;for(i = 0;i<29;i++)wprintf(L"%lc", WALL);//左for (i = 0; i <= 25; i++){SetPos(0, i);wprintf(L"%lc", WALL);}//右for (i = 0; i <= 25; i++){SetPos(56, i);wprintf(L"%lc", WALL);}//下SetPos(0, 26);for (i = 0; i < 29; i++)wprintf(L"%lc", WALL);
}
void InitSnake(pSnake ps)
{int i = 0;pSnakeNode cur = NULL;for (i = 0; i < 5; i++){cur = (pSnakeNode)malloc(sizeof(SnakeNode));if (cur == NULL){perror("InitSnake()::malloc()");}cur->next = NULL;cur->x = POS_X + 2 * i;cur->y = POS_Y;//头插法插入链表if (ps->_pSnake == NULL){ps->_pSnake = cur;}else{cur->next = ps->_pSnake;ps->_pSnake = cur;}}cur = ps->_pSnake;while (cur){SetPos(cur->x,cur->y);wprintf(L"%lc", BODY);cur = cur->next;}//方向ps->_dir = RIGHT;//默认向右ps->_score = 0;ps->_food_weight = 10;ps->_sleep_time = 200;//msps->_status = OK;
}
void CreatteFood(pSnake ps)
{int x = 0;int y = 0;//x 2~54//y 1~25
again:do {x = rand() % 53 + 2;y = rand() % 25 + 1;} while ((x % 2) != 0);//x y 不能生成在蛇身上pSnakeNode cur = ps->_pSnake;while(cur){if (x == cur->x && y == cur->y){goto again;}cur = cur->next;}//创建食物结点pSnakeNode pFood = (pSnakeNode)malloc(sizeof(SnakeNode));if (pFood == NULL){perror("CreatFood::malloc()");return;}pFood->x = x;pFood->y = y;pFood->next = NULL;SetPos(x, y);wprintf(L"%lc", FOOD);ps->_pFood = pFood;}
void GameStart(pSnake ps)
{//设置窗口大小system("mode con cols=100 lines=30");system("title 贪吃蛇");//光标隐藏HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE);//影藏光标操作CONSOLE_CURSOR_INFO CursorInfo;GetConsoleCursorInfo(houtput, &CursorInfo);//获取控制台光标信息CursorInfo.bVisible = false; //隐藏控制台光标SetConsoleCursorInfo(houtput, &CursorInfo);//设置控制台光标状态//打印欢迎界面 //功能介绍WelcomeToGame();//绘制地图CreateMap();//创建蛇InitSnake(ps);//创建食物CreatteFood(ps);//设置游戏相关信息
}
void printfHelpInfo()
{SetPos(64, 20);wprintf(L"%ls",L"不能穿墙,不能啃自己");SetPos(64, 21);printf("欢迎游玩贪吃蛇小游戏\n");SetPos(64, 22);wprintf(L"用 ↑ ↓ ← →,按F3加速 按F4减速\n");SetPos(64, 23);wprintf(L"加速分数更高\n");SetPos(64, 24);wprintf(L"空格是暂停哦");SetPos(64, 25);wprintf(L"By 我");
}
void Pause()
{while (1){Sleep(200);if (KEY_PRESS(VK_SPACE))break;}
}
int NextIsFood(pSnakeNode pNextNode, pSnake ps)
{return (ps->_pFood->x == pNextNode->x && ps->_pFood->y == pNextNode->y);
}
void EatFood(pSnakeNode pNextNode, pSnake ps)
{//头插法ps->_pFood->next = ps->_pSnake;ps->_pSnake = ps->_pFood;//释放NEXT的结点free(pNextNode);pNextNode = NULL;pSnakeNode cur = ps->_pSnake;//打印蛇while (cur){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}ps->_score += ps->_food_weight;//重新创建食物CreatteFood(ps);
}
void NoFood(pSnakeNode pNextNode, pSnake ps)
{pNextNode->next = ps->_pSnake;ps->_pSnake = pNextNode;pSnakeNode cur = ps->_pSnake;while (cur->next->next != NULL){SetPos(cur->x, cur->y);wprintf(L"%lc", BODY);cur = cur->next;}SetPos(cur->next->x, cur->next->y);printf(" ");free(cur->next);cur->next = NULL;cur = NULL;
}
void KillByWall(pSnake ps)
{if (ps->_pSnake->x == 0 || ps->_pSnake->x == 56 || ps->_pSnake->y == 0 || ps->_pSnake->y == 26)ps->_status = KILL_BY_WALL;
}
void KillBySelf(pSnake ps)
{pSnakeNode cur = ps->_pSnake->next;while(cur){if (ps->_pSnake->x == cur->x && ps->_pSnake->y == cur->y)ps->_status = KILL_BY_SELF;cur = cur->next;}
}
void SnakeMove(pSnake ps)
{//蛇要去的下一个结点pSnakeNode pNextNode = (pSnakeNode)malloc(sizeof(SnakeNode));if (pNextNode == NULL){perror("SNAKENODDE :: malloc()");return;}switch (ps->_dir){case UP:pNextNode->x = ps->_pSnake->x;pNextNode->y = ps->_pSnake->y - 1;break;case DOWM:pNextNode->x = ps->_pSnake->x;pNextNode->y = ps->_pSnake->y + 1;break;case LEFT:pNextNode->x = ps->_pSnake->x - 2;pNextNode->y = ps->_pSnake->y;break;case RIGHT:pNextNode->x = ps->_pSnake->x + 2;pNextNode->y = ps->_pSnake->y;break;}//检测是否吃到了食物if (NextIsFood(pNextNode,ps)){EatFood(pNextNode, ps); pNextNode = NULL;}else{NoFood(pNextNode, ps);}KillByWall(ps);KillBySelf(ps);
}
void GameRun(pSnake ps)
{//打印帮助信息printfHelpInfo();do{SetPos(64, 10);printf("总分:%8d\n",ps->_score);SetPos(64, 11);printf("当前食物分数:%4d\n", ps->_food_weight);//调用宏if (KEY_PRESS(VK_UP) && ps->_dir != DOWM){ps->_dir = UP;}else if (KEY_PRESS(VK_DOWN) && ps->_dir != UP){ps->_dir = DOWM;}else if (KEY_PRESS(VK_LEFT) && ps->_dir != RIGHT){ps->_dir = LEFT;}else if (KEY_PRESS(VK_RIGHT) && ps->_dir != LEFT){ps->_dir = RIGHT;}else if (KEY_PRESS(VK_SPACE)){Pause();}else if (KEY_PRESS(VK_F3))//加速{if (ps->_food_weight <= 200){ps->_sleep_time -= 30;ps->_food_weight *= 2;}}else if (KEY_PRESS(VK_F4))//减速{if (ps->_food_weight >= 2){ps->_sleep_time += 30;ps->_food_weight /= 2;}}else if (KEY_PRESS(VK_ESCAPE)){ps->_status = END_NORMAL;}SnakeMove(ps);//走一步啊Sleep(ps->_sleep_time);//打印总分数和食物的分值} while (ps->_status == OK);
}
void GameEnd(pSnake ps)
{SetPos(24, 12);switch (ps->_status){case END_NORMAL:printf("已主动结束游戏");break;case KILL_BY_WALL:printf("您撞墙了");break;case KILL_BY_SELF:printf("您撞到了自己");break;}SetPos(0, 27);//释放链表pSnakeNode cur = ps->_pSnake;while (cur){pSnakeNode del = cur;cur = cur->next;free(del);}
}
mian.c
#define _CRT_SECURE_NO_WARNINGS
#include"snake.h"
void test()
{char ch = 'n';do {system("cls");//创建贪吃蛇Snake snake = { 0 };//初始化游戏GameStart(&snake);//运行游戏GameRun(&snake);//游戏结束GameEnd(&snake);SetPos(20, 20);printf("还玩么?玩的话输入Y(先删除空格):");scanf("%c", &ch);} while (ch == 'Y');
}
int main()
{//设置本地化setlocale(LC_ALL, "");srand((unsigned int)time(NULL));test();return 1;
}