当前位置: 首页 > news >正文

通过C语言设计的贪吃蛇游戏(控制台终端)

一、项目介绍

当前通过控制台终端实现一个贪吃蛇小游戏,实现游戏的绘制、更新、控制等功能。

二、实现效果

image-20230618211315514

image-20230618211408842

三、完整代码

下面贴出的代码在Windows系统上编译运行,需要使用conio.h头文件中的getch()函数来获取键盘输入,用于控制蛇的移动。可以通过按下’w’、‘s’、‘a’、'd’四个键来分别控制蛇的向上、向下、向左、向右移动。同时还有一个暂停函数Pause(),用于控制蛇的移动速度,可以根据需要调整暂停时间。

设计思路:

程序定义了一些常量,包括游戏界面的宽度和高度、不同状态下的符号表示等,并在全局变量中定义了蛇头、蛇身、食物等的位置、得分、长度、行进方向等参数。同时还定义了一个二维字符数组board,用于表示整个游戏界面。

在InitGame()函数中进行游戏初始化,设置游戏界面的边框、蛇头、蛇身、随机生成食物等操作。

DrawGame()函数用于绘制游戏画面,将board数组中的字符逐行输出,并在末尾输出得分。UpdateGame()函数用于更新游戏状态,包括蛇的移动、游戏结束判断等。CheckGameOver()函数用于检查游戏是否结束,包括墙壁碰撞、蛇身碰撞、得分达到上限等情况。GenerateFood()函数用于随机生成食物位置,调用rand()函数获取随机数并进行判断。Move()函数用于蛇的移动,根据当前行进方向进行移动。Control()函数用于用户操作,读取键盘输入并更新蛇的行进方向。Pause()函数用于控制游戏速度,通过调用Sleep()函数控制暂停时间。GameOver()函数用于输出最终得分和游戏结束信息,并直接退出程序。

image-20230618211229060

#include <stdio.h>
#include <stdlib.h>
#include <conio.h>  //需要使用getch()函数
#include <time.h>   //需要使用time()函数
#include <Windows.h>#define WIDTH 40    //游戏界面宽度
#define HEIGHT 20   //游戏界面高度//定义符号常量,表示各种不同的状态
#define BLANK ' '   //空白
#define WALL '*'    //墙壁
#define SNAKEHEAD '@'  //蛇头
#define SNAKEBODY 'o'  //蛇身
#define FOOD '$'    //食物//定义坐标结构体
struct Position
{int x;    //横坐标int y;    //纵坐标
};//定义枚举类型,表示游戏状态
enum GameState
{Over = -1,   //游戏结束Running = 0, //游戏进行中Win = 1      //游戏胜利
};int score = 0;   //得分
struct Position head;   //蛇头位置
struct Position body[WIDTH * HEIGHT];  //蛇身位置
struct Position food;   //食物位置
char board[WIDTH][HEIGHT];   //游戏界面
int length = 3;     //蛇身长度,初始为3
int direction = 0;  //蛇的行进方向,0表示向右,1表示向下,2表示向左,3表示向上//函数声明
void InitGame();    //初始化游戏界面和蛇的初始位置
void DrawGame();    //绘制游戏画面
void UpdateGame();  //更新游戏状态
enum GameState CheckGameOver();  //检查游戏是否结束
void GenerateFood();   //生成随机食物
void Move();     //蛇的移动
void Control();  //用户操作,控制蛇的移动
void Pause();    //游戏暂停
void GameOver(); //游戏结束int main()
{srand(time(NULL));   //用当前时间作为随机数种子,使每次运行的随机食物位置不同InitGame();   //初始化游戏DrawGame();   //绘制游戏画面while (1){UpdateGame();  //更新游戏DrawGame();    //绘制游戏画面Control();     //用户操作,控制蛇的移动Pause();       //游戏暂停     }return 0;
}//初始化游戏界面和蛇的初始位置
void InitGame()
{for (int i = 0; i < WIDTH; i++){for (int j = 0; j < HEIGHT; j++){if (i == 0 || j == 0 || i == WIDTH - 1 || j == HEIGHT - 1) //设置墙壁board[i][j] = WALL;elseboard[i][j] = BLANK;    //其他为空白}}//初始化蛇的位置,由一个蛇头和两节身体组成,初始位置在游戏界面的中心head.x = WIDTH / 2;head.y = HEIGHT / 2;board[head.x][head.y] = SNAKEHEAD;body[0].x = head.x - 1;body[0].y = head.y;board[body[0].x][body[0].y] = SNAKEBODY;body[1].x = head.x - 2;body[1].y = head.y;board[body[1].x][body[1].y] = SNAKEBODY;GenerateFood();   //生成随机食物
}//绘制游戏画面
void DrawGame()
{system("cls");   //清屏,避免前一帧的内容残留for (int i = 0; i < HEIGHT; i++){for (int j = 0; j < WIDTH; j++){printf("%c", board[j][i]);  //输出一个字符}printf("\n");    //每行输出完后,换行}printf("Score: %d\n", score);   //输出得分
}//更新游戏状态
void UpdateGame()
{Move();   //蛇的移动enum GameState state = CheckGameOver();  //检查游戏是否结束if (state != Running)  //如果游戏结束,则进行相应操作{GameOver();}
}//检查游戏是否结束
enum GameState CheckGameOver()
{//蛇头碰到墙壁,游戏结束if (board[head.x][head.y] == WALL)return Over;//蛇头碰到蛇身,游戏结束for (int i = 0; i < length; i++){if (head.x == body[i].x && head.y == body[i].y)return Over;}//吃到食物后,更新分数和蛇的长度,并生成新的食物if (head.x == food.x && head.y == food.y){score += 10;length++;GenerateFood();}//蛇的长度达到游戏界面总格子数减去墙壁的个数,也就是蛇填满游戏界面,游戏胜利if (length == (WIDTH - 2) * (HEIGHT - 2) - 4)return Win;return Running;   //游戏继续进行
}//生成随机食物
void GenerateFood()
{int x, y;do{x = rand() % (WIDTH - 2) + 1;    //随机x坐标,排除在边框上的墙壁位置y = rand() % (HEIGHT - 2) + 1;   //随机y坐标,排除在边框上的墙壁位置} while (board[x][y] != BLANK);   //如果随机到的位置不为空白,则重新随机food.x = x;food.y = y;board[x][y] = FOOD;  //在随机位置生成食物
}//蛇的移动
void Move()
{//更新蛇身的位置,从后往前移动for (int i = length - 1; i > 0; i--){body[i].x = body[i - 1].x;body[i].y = body[i - 1].y;board[body[i].x][body[i].y] = SNAKEBODY;}//更新蛇头的位置switch (direction)   //根据蛇头行进方向进行移动{case 0:  //向右head.x++;break;case 1:  //向下head.y++;break;case 2:  //向左head.x--;break;case 3:  //向上head.y--;break;}board[head.x][head.y] = SNAKEHEAD;   //更新蛇头位置board[body[length - 1].x][body[length - 1].y] = BLANK;  //清除蛇尾
}//用户操作,控制蛇的移动
void Control()
{if (kbhit())   //如果有按键按下{char ch = getch();   //获取按键字符switch (ch){case 'w':if (direction != 1)  //避免蛇头掉头direction = 3;break;case 's':if (direction != 3)direction = 1;break;case 'a':if (direction != 0)direction = 2;break;case 'd':if (direction != 2)direction = 0;break;case 'q':GameOver();  //按下'q'键退出游戏break;}}
}//游戏暂停
void Pause()
{Sleep(150);   //每次循环暂停一段时间,控制蛇的移动速度
}//游戏结束
void GameOver()
{system("cls");   //清屏,输出最终得分和游戏结束信息printf("Game over!\n");printf("Your score: %d\n", score);exit(0);  //直接退出程序
}
http://www.lryc.cn/news/111911.html

相关文章:

  • c++实现Qt信号和槽机制
  • 【Linux】五、进程
  • 使用 OpenCV 和 Python 卡通化图像-附源码
  • GitLab不同角色对应的权限
  • 手写一个简易的布隆过滤器
  • 阿里云快速部署开发环境 (Apache + Mysql8.0)
  • 侧边栏的打开与收起
  • 贝叶斯学习
  • Java并发系列之六:CountDownLatch
  • 24数据结构-图的基本概念与存储结构
  • 自然语言处理学习笔记(三)————HanLP安装与使用
  • CS 144 Lab Five -- the network interface
  • Mecha
  • Apache RocketMQ之集成RocketMQ_MQTT 安装部署协议
  • Oracle多行数据合并为一行数据,并将列数据转为字段名
  • MySQL5.7 与 MariaDB10.1 审计插件兼容性验证
  • PyTorch Lightning教程五:Debug调试
  • 末流211无科研保研经验分享
  • 日期选择器多选换行
  • NodeJS原型链污染ctfshow_nodejs
  • 18. SpringBoot 如何在 POM 中引入本地 JAR 包
  • vue2-$nextTick有什么作用?
  • python自动收集粘贴板
  • Vue3_语法糖—— <script setup>以及unplugin-auto-import自动引入插件
  • 2023-08-06力扣做过了的题
  • 进程间通信之管道
  • f12 CSS网页调试_css样式被划了黑线怎么办
  • vue-制作自动滚动效果
  • [国产MCU]-BL602-开发实例-DMA数据传输
  • Redis压缩列表