【C语言】实践:贪吃蛇小游戏(附源码)(二)https://developer.aliyun.com/article/1621361
源代码
Snake.h
#pragma once #define _CRT_SECURE_NO_WARNINGS #include<stdio.h> #include<stdlib.h> #include<locale.h> #include<windows.h> #include<stdbool.h> #include<wchar.h> #include<time.h> #include<conio.h> //初始数据 #define SNAKE_X 24 #define SNAKE_Y 5 #define WALL L'□' #define SNAKENODE L'●' #define FOOD L'★' //蛇的节点 typedef struct Snakenode { int x; int y; struct Snakenode* next; }Snakenode; typedef Snakenode* pSnakenode; //蛇的方向 enum DIRECT { UP = 1, DOWN, LEFT, RIGHT }; //蛇的状态——游戏状态 //正常、撞墙、撞到自己、正常退出 enum GAME_STATE { OK, KILL_WALL, KILL_SELF, NORMAL_END }; //贪吃蛇的相关信息 typedef struct Snake { pSnakenode psnake; //指向蛇头部的指针 pSnakenode pfood; //指向食物的指针 enum DIRECT dir;//蛇的方向 enum GAME_STATE state;//蛇的状态 int food_scores;//每个食物的分数 int all_scores; //总分数 int sleep_time; //休息的时间 --即蛇的速度 }Snake; typedef Snake* pSnake; //设置光标位置 void SetPos(int x, int y); //游戏初始化 void GameStart(pSnake ps); //欢迎界面的输出 void WelcomeToGame(); //地图绘制 void CreatMap(); //创建贪吃蛇 void InitSnake(pSnake ps); //创建食物 void CreatFood(pSnake ps); //游戏运行 void GameRun(pSnake ps); //贪吃蛇的移动 void SnakeMove(pSnake ps); //判断下一个位置是不是食物 int NextIsFood(pSnakenode next , pSnake ps); //下一个位置是食物,吃掉食物 void IsFood(pSnakenode next, pSnake ps); //下一个位置不是食物 void NoFood(pSnakenode next, pSnake ps); //判断贪吃蛇是否撞墙 void KillByWall(pSnake ps); //判断贪吃蛇是否撞到自己 void KillBySelf(pSnake ps); //游戏结束 void GameOver(pSnake ps); void KeyFun();
Snake.c
#include"Snake.h" //设置光标位置 void SetPos(int x, int y) { HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE); COORD pos = { x,y }; SetConsoleCursorPosition(houtput, pos); } //欢迎界面打印 void WelcomeToGame() { //设置光标位置 SetPos(40, 15); printf("欢迎进入贪吃蛇小游戏\n"); SetPos(42, 20); system("pause"); system("cls");//清理屏幕 SetPos(20, 11); printf("请使用↑ 、 ↓ 、 ← 、 → 来控制贪吃蛇的移动,按F3加速、F4减速 "); SetPos(20, 13); printf("加速可以获得更多的分数"); SetPos(20, 15); system("pause"); system("cls"); //清理屏幕 } //地图绘制 void CreatMap() { //上 int i = 0; for (i = 0; i < 29; i++) { wprintf(L"%lc", WALL); } //下 SetPos(0, 26); for(i = 0; i < 29; i++) { wprintf(L"%lc", WALL); } //左 for (i = 1; i < 26; i++) { SetPos(0, i); wprintf(L"%lc", WALL); } //右 for (i = 1; i < 26; i++) { SetPos(56, i); wprintf(L"%lc", WALL); } //system("pause"); } //创建贪吃蛇 void InitSnake(pSnake ps) { //创建蛇的身体 pSnakenode pcur = NULL; int i = 0; int x, y;//蛇初始位置 do { x = rand() % 31 + 4; //x: 4 - 34 y = rand() % 20 + 2; //y: 1 - 25 } while (x % 2 != 0); for (i = 0; i < 5; i++) { pcur = (pSnakenode)malloc(sizeof(Snakenode)); if (pcur == NULL) { perror("InitSnake()::malloc()"); return; } pcur->next = NULL; //pcur->x = SNAKE_X + i * 2; //pcur->y = SNAKE_Y; pcur->x = x + i * 2; pcur->y = y; //头插到贪吃蛇链表中 if (ps->psnake == NULL) //链表为空 { ps->psnake = pcur; } else { pcur->next = ps->psnake; ps->psnake = pcur; } } //输出蛇的初始位置 pcur = ps->psnake; while (pcur) { SetPos(pcur->x, pcur->y); wprintf(L"%lc", SNAKENODE); pcur = pcur->next; } //初始化贪吃蛇的信息 ps->dir = RIGHT; //蛇的方向 ps->pfood = NULL; //指向食物 --NULL ps->state = OK; //状态 ps->food_scores = 10; //每个食物的得分 ps->all_scores = 0; //总分 ps->sleep_time = 200;//速度,即休息时间 单位是毫秒 //getchar(); } //创建食物 void CreatFood(pSnake ps) { int x, y;//随机生成坐标 x , y //x 2-54 //y 1-25 again: do { x = rand() % 53 + 2; y = rand() % 25 + 1; } while (x % 2 != 0); //x y 不能与贪吃蛇身体重复 pSnakenode pcur = ps->psnake; while (pcur) { if (x == pcur->x && y == pcur->y) { goto again; } pcur = pcur->next; } pSnakenode food = (pSnakenode)malloc(sizeof(pSnakenode)); if (food == NULL) { perror("CreatFood()::malloc"); return; } food->x = x; food->y = y; food->next = NULL; ps->pfood = food; SetPos(x, y); wprintf(L"%lc", FOOD); //getchar(); } //游戏初始化 void GameStart(pSnake ps) { //设置窗口名称大小,隐藏光标 system("title 贪吃蛇"); system("mode con cols=100 lines=33"); //隐藏光标 HANDLE houtput = GetStdHandle(STD_OUTPUT_HANDLE); CONSOLE_CURSOR_INFO CursorInfo; GetConsoleCursorInfo(houtput, &CursorInfo);//获得有关指定控制台屏幕缓冲区的光标大小和可见的信息 CursorInfo.bVisible = false; //隐藏控制台光标 SetConsoleCursorInfo(houtput, &CursorInfo);//设置控制台光标状态 //打印欢迎界面和功能介绍 WelcomeToGame(); //绘制地图 CreatMap(); //创建贪吃蛇 InitSnake(ps); //创建食物 CreatFood(ps); //system("pause"); } #define KEY_PRESS(VK) ( (GetAsyncKeyState(VK) & 0x1) ? 1 : 0 ) //暂停 void Pause() { while (1) { Sleep(200); if (KEY_PRESS(VK_SPACE)) break; } } //判断下一个位置是不是食物 int NextIsFood(pSnakenode next, pSnake ps) { return (next->x == ps->pfood->x && next->y == ps->pfood->y); } //下一个位置是食物 void IsFood(pSnakenode next, pSnake ps) { //把下一个位置的节点头插到贪吃蛇中 next->next = ps->psnake; ps->psnake = next; //打印贪吃蛇 pSnakenode cur = ps->psnake; while (cur) { SetPos(cur->x, cur->y); wprintf(L"%lc", SNAKENODE); cur = cur->next; } ps->all_scores += ps->food_scores; CreatFood(ps); //SetPos(ps->pfood->x, ps->pfood->y); //wprintf(L"%lc", FOOD); } //下一个位置不是食物 void NoFood(pSnakenode next, pSnake ps) { //把下一个位置的节点头插到贪吃蛇中 next->next = ps->psnake; ps->psnake = next; pSnakenode cur = ps->psnake; while (cur->next->next != NULL) { SetPos(cur->x, cur->y); wprintf(L"%lc", SNAKENODE); cur = cur->next; } SetPos(cur->next->x, cur->next->y); wprintf(L"%ls", L" "); free(cur->next); cur->next = NULL; } //贪吃蛇的移动 void SnakeMove(pSnake ps) { pSnakenode next = (pSnakenode)malloc(sizeof(Snakenode)); if (next == NULL) { perror("SnakeMove():malloc()"); exit(1); } switch (ps->dir) { case UP: next->x = ps->psnake->x; next->y = ps->psnake->y - 1; break; case DOWN: next->x = ps->psnake->x; next->y = ps->psnake->y + 1; break; case LEFT: next->x = ps->psnake->x - 2; next->y = ps->psnake->y; break; case RIGHT: next->x = ps->psnake->x + 2; next->y = ps->psnake->y; break; } //判断下一个位置是不是食物 if (NextIsFood(next, ps)) { IsFood(next, ps); } else { NoFood(next, ps); } } // void Printgame(pSnake ps) { SetPos(60, 15); printf("请使用↑ 、 ↓ 、 ← 、 → 来控制贪吃蛇"); SetPos(60, 16); printf("按F3加速、F4减速 "); SetPos(60, 18); printf("加速可以获得更高的分数 "); SetPos(60, 20); printf("ESC:退出游戏 space:暂停 "); SetPos(60, 10); printf("当前总得分:%d", ps->all_scores); SetPos(60, 12); printf("当前每个食物得分:%d", ps->food_scores); SetPos(60, 22); printf("努力学习的小廉"); } //判断贪吃蛇是否撞墙 void KillByWall(pSnake ps) { if (ps->psnake->x == 0 || ps->psnake->x == 56 || ps->psnake->y == 0 || ps->psnake->y == 26) ps->state = KILL_WALL; } //判断贪吃蛇是否撞到自己 void KillBySelf(pSnake ps) { pSnakenode pcur = ps->psnake->next; while (pcur) { if (pcur->x == ps->psnake->x && pcur->y == ps->psnake->y) { ps->state = KILL_SELF; break; } pcur = pcur->next; } } //游戏运行 void GameRun(pSnake ps) { do { Printgame(ps); //判断按键是否被按过 if (KEY_PRESS(VK_UP) && ps->dir != DOWN) { ps->dir = UP; } else if(KEY_PRESS(VK_DOWN) && ps->dir != UP){ ps->dir = DOWN; } 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_ESCAPE)) //游戏正常退出 { ps->state = NORMAL_END; break; } else if (KEY_PRESS(VK_F3)) { if (ps->sleep_time >= 100) { ps->sleep_time -= 50; ps->food_scores += 5;//设定食物分数最高25 } } else if (KEY_PRESS(VK_F4)) { if (ps->sleep_time < 300) { ps->sleep_time += 100; ps->food_scores -= 5;//⼀个⻝物分数最低是5分 } } Sleep(ps->sleep_time); //贪吃蛇的移动 SnakeMove(ps); //判断贪吃蛇是否撞墙 KillByWall(ps); //判断贪吃蛇是否撞到自己 KillBySelf(ps); } while (ps->state == OK); } //游戏结束 void GameOver(pSnake ps) { SetPos(8, 12); switch(ps->state) { case KILL_WALL: wprintf(L"Sorry,game over because you hit the wall !\n"); break; case KILL_SELF: wprintf(L"Sorry,game over because you hit youself !\n"); break; case NORMAL_END: wprintf(L"Game exits normally !"); break; } //释放贪吃蛇的节点内存 pSnakenode pcur = ps->psnake; while (pcur) { pSnakenode del = pcur; pcur = pcur->next; free(del); } ps->psnake = NULL; } void KeyFun() { while (_kbhit()) { int key = _getch(); } }
test.c
#include"Snake.h" void test() { Snake snake = { 0 }; int ch = 0; do { ch = 0; system("cls"); //游戏初始化 GameStart(&snake); //游戏运行 GameRun(&snake); //游戏结束 GameOver(&snake); KeyFun(); SetPos(30, 20); wprintf(L"再来一局吗? (Y/N)"); ch = getchar(); while (getchar() != '\n'); } while (ch == 'Y' || ch == 'y'); SetPos(0, 27); } int main() { //本地化 setlocale(LC_ALL, ""); srand((unsigned int)time(NULL)); test(); //KeyFun(); return 0; }
制作不易,如果本篇内容对你有帮助,可以一键三连支持一下!!!