一、项目概述
我们的目标是创建一个基本的贪吃蛇游戏,它具有以下功能:
蛇能够根据玩家的键盘输入改变方向。
当蛇吃到食物时,蛇的长度增加,同时分数增加。
蛇可以在窗口边缘“穿墙”移动。
游戏界面包括一个蛇和一个随机出现的食物。
支持游戏暂停功能。
二、环境配置
为了实现这个项目,我们需要准备以下开发工具:
-
Visual Studio Code 或其他任何C/C++ IDE。
-
Turbo C++ 或者安装了相应库的现代IDE,因为代码中使用了
graphics.h
,该头文件通常与Turbo C++一起使用。 -
MinGW 或者其他编译器,用来编译C代码。
注意:graphics.h
库不是标准C库的一部分,在某些现代环境中可能不可用。如果不能使用graphics.h
,可以考虑使用如SDL、OpenGL等其他图形库来替代。
三、代码详解
1. 数据结构定义
首先,定义了两个结构体:snake
和 Food
。其中snake
包含蛇的位置信息和方向等属性;Food
则表示食物的位置和颜色等信息。
struct snake {
int size;
int dir;
int speed;
POINT coor[SNAKE_NUM];
};
struct Food {
int score;
int x;
int y;
int r;
bool flag;
DWORD color;
};
2. 初始化游戏
初始化函数GameInit()
负责设置游戏的基本参数,如图形窗口的大小、蛇的初始位置和速度等。
void GameInit() {
initgraph(640, 480, SHOWCONSOLE);
srand(GetTickCount());
snake.size = 3;
snake.speed = 10;
snake.dir = RIGHT;
...
}
3. 绘制游戏画面
GameDraw()
函数负责绘制当前的游戏状态,包括背景色、蛇和食物的位置。
void GameDraw() {
BeginBatchDraw();
setbkcolor(RGB(28, 115, 119));
cleardevice();
// 绘制蛇和食物
...
EndBatchDraw();
}
4. 控制蛇的移动
snakeMove()
函数根据当前的方向更新蛇的位置,并实现了蛇穿过屏幕边缘的功能。
void snakeMove() {
for (int i = snake.size - 1; i > 0; i--) {
snake.coor[i] = snake.coor[i - 1];
}
switch (snake.dir) {
case UP: ...
case DOWN: ...
case LEFT: ...
case RIGHT: ...
}
}
5. 用户输入处理
keyControl()
函数监听键盘输入并改变蛇的方向。
void keyControl() {
if (_kbhit()) {
switch (_getch()) {
case 'w': ...
case 's': ...
case 'a': ...
case 'd': ...
case ' ': // 暂停游戏
while (1) {
if (_getch() == ' ') return;
}
}
}
}
6. 吃食物逻辑
Eatfood()
函数检查蛇是否吃到了食物,如果是,则增加蛇的长度和玩家的分数。
void Eatfood() {
if (food.flag && ... && ...) {
food.flag = false;
snake.size++;
}
if (!food.flag) {
food.x = rand() % 640;
...
food.flag = true;
}
if (!food.flag) {
food.score++;
printf("得分: %d", food.score);
}
}
四、主循环
最后,在main()
函数中创建了一个无限循环,用于不断更新游戏状态和渲染画面。
int main() {
GameInit();
GameDraw();
while (1) {
GameDraw();
snakeMove();
keyControl();
Eatfood();
Sleep(100);
}
return 0;
}
完整代码:
#include<stdio.h>
#include<graphics.h>
#include<conio.h>
#include<stdlib.h>
#define SNAKE_NUM 500 //蛇的最大节数
enum DIR //蛇的方向
{
UP,
DOWN,
LEFT,
RIGHT,
};
//蛇的结构
struct snake
{
int size;//蛇的节数
int dir;//蛇的方向
int speed;//蛇的速度
POINT coor[SNAKE_NUM];//坐标
}snake;
//食物结构
struct Food
{
int score;
int x;
int y;
int r; //食物大小
bool flag;//食物是否被吃
DWORD color;
}food;
//数据初始化
void GameInit()
{ //显示控制台
initgraph(640, 480,SHOWCONSOLE);//图形窗口
//设置随机数种子
srand(GetTickCount());
//初始化蛇 一开始有三节
snake.size = 3;
snake.speed = 10;
snake.dir = RIGHT;
for (int i = 0; i < snake.size ; i++)
{
snake.coor[i].x = 40-10*i;
snake.coor[i].y = 10;
}
//初始化食物 rand()随机生产一个整数
//随机数种子需要头文件stdlib.h
food.x = rand() % 640;
food.y = rand() % 480;
food.color = RGB(rand() % 256, rand() % 256, rand() % 256);
food.r = rand() % 10 + 5;
food.flag = true;
}
void GameDraw()
{
//双缓冲绘图
BeginBatchDraw();
setbkcolor(RGB(28, 115, 119));//设置背景颜色
cleardevice();
//绘制蛇
setfillcolor(YELLOW);
for (int i = 0; i < snake.size; i++)
{
solidcircle(snake.coor[i].x, snake.coor[i].y, 5);
}
//绘制食物
if (food.flag)
{
solidcircle(food.x, food.y, food.r);
}
EndBatchDraw();
}
//移动蛇
void snakeMove()
{
//移动即蛇头改变
//让身体跟随蛇头移动
for (int i = snake.size-1; i > 0; i--)
{
snake.coor[i] = snake.coor[i - 1];
}
switch (snake.dir)
{
case UP:
snake.coor[0].y-=snake.speed;
if (snake.coor[0].y + 10 <= 0)//超出上面的边界
{
snake.coor[0].y = 480;
}
break;
case DOWN:
snake.coor[0].y+=snake.speed;
if (snake.coor[0].y - 10 >= 480)
{
snake.coor[0].y = 0;
}
break;
case LEFT:
snake.coor[0].x-=snake.speed;
if (snake.coor[0].x + 10 <= 0)
{
snake.coor[0].x = 640;
}
break;
case RIGHT:
snake.coor[0].x+=snake.speed;
if (snake.coor[0].x - 10 >= 640)
{
snake.coor[0].x = 0;
}
break;
}
}
//通过按键改变蛇的方向
void keyControl()
{
//判断有没有按键,如果有按键就返回真
if (_kbhit())
{
//72 80 75 77上下左右键值
switch (_getch())
{
case 'w':
case 'W':
case 72:
//改变方向
if (snake.dir != DOWN)
{
snake.dir = UP;
}
break;
case 's':
case 'S':
case 80:
if (snake.dir != UP)
{
snake.dir = DOWN;
}
break;
case 'a':
case 'A':
case 75:
if (snake.dir !=RIGHT)
{
snake.dir = LEFT;
}
break;
case 'd':
case 'D':
case 77:
if (snake.dir != LEFT)
{
snake.dir = RIGHT;
}
break;
case' '://游戏暂停逻辑
while (1)
{
if (_getch() == ' ')
return;
}
break;
}
}
}
void Eatfood()
{ //判断食物是否存在
if (food.flag && snake.coor[0].x >=food.x-food.r && snake.coor[0].x<= food.x+food.r&&
snake.coor[0].y>=food.y-food.r && snake.coor[0].y<=food.y+food.r)
{
food.flag = false;
snake.size++;
}//若食物消失,则重新生成
if (!food.flag)
{
food.x = rand() % 640;
food.y = rand() % 480;
food.color = RGB(rand() % 256, rand() % 256, rand() % 256);
food.r = rand() % 10 + 5;
food.flag = true;
}
//吃食物加分
if (!food.flag)
{
food.score++;
printf("得分:", food.score);
}
}
int main()
{
GameInit();
GameDraw();
while (1)
{
GameDraw();
snakeMove();
keyControl();
Eatfood();
Sleep(100);
}
return 0;
}