【C语言】贪吃蛇
2018-10-06 20:56
92 查看
一,涉及知识点:
[code]结构体链表,动态分配内存,键盘输入检测,设置光标。
二,实现逻辑
[code]1,涉及多个结构体,分别定义蛇,方向,结点,位置坐标,游戏 2,结点串联形成链表,遍历获取成员坐标,打印符号得到蛇身。 3,不断的加头,去尾,重新遍历坐标,再打印形成蛇的移动。 4,食物产生的位置判定,不能越界,也不能与蛇身体重合。 5,蛇的转向判定,一条规则,不允许倒退。 6,转向的实现,跟行进方向决定新的关节坐标(当前头的上下左右) 7,死亡检测,是否头节点坐标是否与墙壁重合,是否与身体其他关节重合。 8,加速减速,设置刷新休眠时间实现。 9,可以设置光标,就能实现制定位置打印制定符号。
源码
[code]//Model.h 结构体头文件 #pragma once typedef enum Direction { UP, DOWN, LEFT, RIGHT }Direction; typedef struct Position { int x; int y; }Position; typedef struct Node { Position pos; struct Node *next; }Node; typedef struct Snake { Node *head; Node *tail; Direction direction; }Snake; typedef struct Game { Snake snake; Position food; int width; int height; }Game;
[code]//View.h #pragma once #include "Model.h" void SetPos(int X, int Y); void DisplayWall(int width, int height); void DisplaySnake(const Snake *pSnake); void DisplayFood(const Position *pFood); void CleanSnakeNode(const Position *pPos); void DisplaySnakeNode(const Position *pPos); void GameDescription1(); void GameDescription2();
[code]//View.c #include "View.h" #include "Model.h" #include <Windows.h> #include <stdio.h> void ViewInit() { HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); //CONSOLE_CURSOR_INFO 这个结构体包含的是控制台光标的信息 CONSOLE_CURSOR_INFO ConsoleCursorInfo; GetConsoleCursorInfo(hOutput, &ConsoleCursorInfo); ConsoleCursorInfo.bVisible = FALSE; SetConsoleCursorInfo(hOutput, &ConsoleCursorInfo); } //设置光标位置 void SetPos(int X, int Y) { HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); COORD coord = { X, Y }; SetConsoleCursorPosition(hOutput, coord); } static void TranslateSetPos(int x, int y) { int X = 2 * (x + 1); int Y = y + 1; SetPos(X, Y); } void DisplayWall(int width, int height) { ViewInit(); // 上 SetPos(0, 0); for (int i = 0; i < width + 2; i++) { printf("◆"); } // 下 SetPos(0, height + 1); for (int i = 0; i < width + 2; i++) { printf("◆"); } // 左 for (int i = 0; i < height + 2; i++) { SetPos(0, i); printf("◆"); } // 右 for (int i = 0; i < height + 2; i++) { SetPos(2 * (width + 1), i); printf("◆"); } } void DisplaySnake(const Snake *pSnake) { for (Node *node = pSnake->tail; node != NULL; node = node->next) { TranslateSetPos(node->pos.x, node->pos.y); printf("■"); } } void DisplayFood(const Position *pFood) { TranslateSetPos(pFood->x, pFood->y); printf("■"); } void CleanSnakeNode(const Position *pPos) { TranslateSetPos(pPos->x, pPos->y); printf(" "); } void DisplaySnakeNode(const Position *pPos) { TranslateSetPos(pPos->x, pPos->y); printf("■"); } //游戏说明界面 void GameDescription1() { SetPos(40, 14); printf("欢迎进入贪吃蛇游戏!\n\n"); system("pause"); system("color 5e"); system("cls"); SetPos(10, 14); printf("您将通过键盘控制蛇的移动: 上↑ 下↓ 左 ← 右→ 加速F1 减速F2 暂停space 退出Esc"); SetPos(10, 15); printf("吃到食物身体会变长\n"); SetPos(10, 16); printf("撞到身体或墙壁游戏都会结束\n"); system("pause"); system("cls"); } void GameDescription2() { SetPos(64, 15); printf("不能穿墙,不能咬到自己\n"); SetPos(64, 16); printf("用↑ ↓ ← → 控制蛇的移动."); SetPos(64, 17); printf("F1 为加速,F2 为减速\n"); SetPos(64, 18); printf("ESC :退出游戏 space:暂停游戏."); }
[code]//Controller.c #include "Model.h" #include "View.h" #include <stdlib.h> #include <stdio.h> #include <windows.h> #include <stdbool.h> #include <time.h> void SnakeInit(Snake *pSnake) { //链表中头结点是蛇的尾巴,尾结点是蛇的头 pSnake->tail = NULL; for (int i = 0; i < 3; i++){ Node *node = (Node *)malloc(sizeof(Node)); //从蛇头开始创建结点 node->pos.x = 7 + i; node->pos.y = 2; if (i == 0){ pSnake->head = node; } node->next = pSnake->tail; pSnake->tail = node; } pSnake->direction = LEFT; } bool IsOverLap(Position pos,Snake *pSnake) { Node *node; for (node = pSnake->tail; node != pSnake->head; node = node->next){ if (node->pos.x == pos.x&&node->pos.y == pos.y){ return true; } } return false; } //生成食物 Position GenerateFood(int width, int height, Snake *pSnake) { Position pos; SetPos(1, 1); do { pos.x = rand() % width; pos.y = rand() % height; } while (IsOverLap(pos, pSnake)); DisplayFood(&pos); return pos; } //初始化Game void GameInit(Game *pGame) { pGame->width = 28; pGame->height = 27; //初始化蛇 SnakeInit(&pGame->snake); //初始化食物 //pGame->food = GenerateFood(pGame->width, pGame->height, &pGame->snake); } //得到蛇即将要走的坐标 Position GetNextPosition(const Snake *pSnake) { Position next = pSnake->head->pos; switch (pSnake->direction){ case UP: next.y -= 1; break; case DOWN: next.y += 1; break; case LEFT: next.x -= 1; break; case RIGHT: next.x += 1; break; } return next; } //蛇头上加一格 void AddHead(Snake *pSnake, Position nextPos) { Node *node = (Node *)malloc(sizeof(Node)); node->pos = nextPos; node->next = NULL; pSnake->head->next = node; pSnake->head = node; DisplaySnakeNode(&nextPos);//注意这里传参 } //蛇尾减一格 void RemoveTail(Snake *pSnake) { Node *tail = pSnake->tail; pSnake->tail = pSnake->tail->next; CleanSnakeNode(&tail->pos); free(tail); } //判断蛇能不能吃到食物 bool IsEat(Position food, Position next) { return food.x == next.x&&food.y == next.y; } //判断蛇是否撞墙 bool KilledByWall(const Snake *pSnake,int width,int height) { int x = pSnake->head->pos.x; int y = pSnake->head->pos.y; if (x>=0 && x<width && y>=0 && y<=height){ return false; } return true; } //判断蛇是否撞到自己 bool KilledBySelf(const Snake *pSnake,Position nextPos) { Node *node = pSnake->tail; for (node = pSnake->tail; node != pSnake->head; node = node->next){ if (node->pos.x == nextPos.x&&node->pos.y == nextPos.y){ return true; } } return false; } //判断死没死 bool GameOver(const Snake *pSnake,Position nextPos,int width,int height) { if (KilledByWall(pSnake,width,height)){ printf("撞墙了\n"); return true; } if (KilledBySelf(pSnake,nextPos)){ printf("自杀了\n"); return true; } else{ return false; } } //暂停游戏 void PauseGame() { while (1) { Sleep(300); if (GetAsyncKeyState(VK_SPACE)) { break; } } } void GameRun() { Game game; int score = 0, //得分 add = 10, //加分 sleeptime = 200; //正常速度 GameInit(&game); GameDescription1(); DisplayWall(game.width,game.height); DisplaySnake(&game.snake); game.food = GenerateFood(game.width, game.height, &game.snake); GameDescription2(); while (1) { SetPos(64, 10); printf("得分:%d ", score); SetPos(64, 11); printf("当前食物分值:%d分", add); if (game.snake.direction != DOWN&&GetAsyncKeyState(VK_UP)){ game.snake.direction = UP; } else if (game.snake.direction != UP&&GetAsyncKeyState(VK_DOWN)){ game.snake.direction = DOWN; } else if (game.snake.direction != RIGHT&&GetAsyncKeyState(VK_LEFT)){ game.snake.direction = LEFT; } else if (game.snake.direction != LEFT&&GetAsyncKeyState(VK_RIGHT)){ game.snake.direction = RIGHT; } else if (GetAsyncKeyState(VK_F1)) //加速 { if (sleeptime > 50) { sleeptime -= 30; add = add + 2; if (sleeptime == 320) { add = 2;//防止减到1之后再加回来有错 } } } else if (GetAsyncKeyState(VK_F2)) //减速 { if (sleeptime < 350) { sleeptime = sleeptime + 30; add = add - 2; if (sleeptime == 350) { add = 1; //保证最低分为1 } } } else if (GetAsyncKeyState(VK_SPACE)){ //暂停 PauseGame(); } else if (GetAsyncKeyState(VK_ESCAPE)) { //退出 system("cls"); SetPos(18,12 ); printf("退出游戏\n"); break; } Position nextPos = GetNextPosition(&game.snake); if (IsEat(game.food,nextPos)){ //头上加一格 AddHead(&game.snake,nextPos); score += add; //重新生成一个食物 game.food = GenerateFood(game.width, game.height, &game.snake); } else{ //头上加一格 AddHead(&game.snake,nextPos); //尾巴减一格 RemoveTail(&game.snake); } if (GameOver(&game.snake,nextPos,game.width,game.height)){ break; } Sleep(sleeptime); } } //测试控制光标的位置 void DemoSetPos() { HANDLE hOutput = GetStdHandle(STD_OUTPUT_HANDLE); COORD coord; for (int i = 0; i < 6; i++) { coord.X = 2 * i; coord.Y = i; SetConsoleCursorPosition(hOutput, coord); printf("%02d", i); } } int main() { //DemoSetPos(); srand((unsigned)time(NULL)); system("title ★★贪吃蛇★★"); //改变命令窗口名字 GameRun(); system("pause"); system("cls"); return 0; }
阅读更多
相关文章推荐
- C语言:贪吃蛇,用指针数组和字符型数组编写。
- 再写贪吃蛇--C语言
- 小白入门——“贪吃蛇”的C语言实现(详细)
- 贪吃蛇C语言代码
- 小游戏——贪吃蛇(c语言实现)
- 纯C语言写的贪吃蛇源码
- C语言贪吃蛇
- C语言游戏:贪吃蛇
- c语言“贪吃蛇”
- C语言贪吃蛇代码
- 学习C语言进阶课程———贪吃蛇项目
- 用c语言编写小游戏:贪吃蛇
- 编写字符小游戏——贪吃蛇程序(c语言)
- c语言 贪吃蛇
- 【C语言编程设计】字符游戏——贪吃蛇
- c语言贪吃蛇详解5.GameOver功能与显示成绩
- 采用easyX插件进行C语言编写的贪吃蛇,自带播放音乐
- C语言编程实战——编写简单贪吃蛇程序
- 纯C语言做贪吃蛇,我成功了,哈哈................................
- Linux环境下C语言实现贪吃蛇游戏