参考视频:C/C++游戏项目教程:C语言经典贪吃蛇!零基础小白看完一个半小时就能制作出经典游戏,最详细解析!_哔哩哔哩_bilibili
1. 任务分析
? ? ? ? 需要图形库:easyx,官方文档:EasyX 文档 - 使用教程
任务的几个步骤:
(1)界面的设置
(2)对蛇的设置
(3)按键对蛇进行操作
(4)增加食物模块
(5)游戏规则添加
本次只完成游戏的基本功能 注意:绘制图形后,重新绘制的图形会在原来的基础上进行绘制,需要使用 ?cleardevice() ?将之前的图形擦除
2. 界面设置
#define WIN_WIDTH 640 // 窗口宽度
#define WIN_HIGH 480 // 窗口高度
// 创建绘图窗口,大小为 640x480 像素,EW_SHOWCONSOLE显示控制台
// initgraph(640, 480, EW_SHOWCONSOLE);
initgraph(WIN_WIDTH, WIN_HIGH);
// 设置背景颜色
setbkcolor(RGB(28, 115, 119));
cleardevice(); // 画完后需要加一条该命令,可当做刷新屏幕
3. 蛇的设置
? ? ? ? 蛇的参数包括:身体节数、方向、坐标、速度,设置一个结构体
#define SNAKE_NUM 500 // 蛇的最大节数
#define SNAKE_COLOR RED // 蛇的颜色
#define SNAKE_BODY 5 // 蛇身体的半径
enum DIR // 蛇的方向
{
up, down, right, left
};
// 蛇的结构
struct Snake {
int size; // 蛇的节数
int dir; // 方向
int speed; // 速度
POINT coor[SNAKE_NUM]; // 坐标
};
/* POINT是库里就带有的结构体
typedef struct _POINTL
LONG x;
LONG y;
} POINTL, *PPOINTL;
*/
? ? ? ? 对蛇进行初始化
// 蛇的初始化
void snake_init(void)
{
snake.size = 3;
snake.dir = right;
snake.speed = 10;
for (int i = 0; i < snake.size; i++)
{
snake.coor[i].x = 200 - 10 * i;
snake.coor[i].y = 200;
}
}
4.按键实现蛇的移动
? ? ? ? 通过按键改变蛇的方向
// 通过按键改变蛇的方向
void keyControl(void)
{
// 判断有没有按键,有按键返回真
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() == ' ')
{
break;
}
}
break;
default:
break;
}
}
}
? ? ? ? 蛇的移动,蛇的移动可以只关注第一节身体,其余身体的下一次移动为上一节身体的坐标
// 蛇的移动
void snake_move(void)
{
for (int i = snake.size - 1; i > 0; i--)
{
snake.coor[i].x = snake.coor[i - 1].x;
snake.coor[i].y = snake.coor[i - 1].y;
}
switch (snake.dir)
{
case right:
snake.coor[0].x += 10;
break;
case left:
snake.coor[0].x -= 10;
break;
case up:
snake.coor[0].y -= 10;
break;
case down:
snake.coor[0].y += 10;
break;
}
}
5. 增加食物模块
? ? ? ? 定义一个食物的结构体
#define FOOD_COLOR YELLOW // 蛇和食物的颜色
#define FOOD_SIZE 5 // 食物半径
// 食物结构
struct Food {
POINT coor;
int r;
bool flag; // 食物是否被吃
};
? ? ? ? 对食物模块进行初始化
void food_init(void)
{
// 一般将时间作为种子
srand((unsigned int)time(NULL));
food.coor.x = rand() % WIN_WIDTH;
food.coor.y = rand() % WIN_HIGH;
food.flag = true;
}
? ? ? ? 判断是否吃了食物
// 判断是否吃了食物
void EatFood(void)
{
if (food.flag &&
snake.coor[0].x >= food.coor.x - SNAKE_BODY - FOOD_SIZE &&
snake.coor[0].x <= food.coor.x + SNAKE_BODY + FOOD_SIZE &&
snake.coor[0].y >= food.coor.y - SNAKE_BODY - FOOD_SIZE &&
snake.coor[0].y <= food.coor.y + SNAKE_BODY + FOOD_SIZE
)
{
food.flag = false;
snake.size++;
}
if (!food.flag)
{
food.coor.x = rand() % (WIN_WIDTH - 2 * FOOD_SIZE) + FOOD_SIZE;
food.coor.y = rand() % (WIN_HIGH - 2 * FOOD_SIZE) + FOOD_SIZE;
food.flag = true;
}
}
6. 源码
// snake.h
#define _CRT_SECURE_NO_WARNINGS // visual studio不支持scanf,需要在头文件前添加该宏定义
#ifndef _SNAKE_H_
#define _SNAKE_H_
#include<stdio.h>
#include<easyx.h>
#include<conio.h> // _getch()的头文件
#include<time.h>
/*
图形库:easyx
文件后缀要改成.cpp,使用c语言编译器会出错
1.设置界面
界面初始化
2.设置蛇
对蛇进行初始化,进行移动
3.按键对蛇进行操作
按照游戏规则对代码进行修改,撞击,移动等。
4.增加食物模块
*/
#define WIN_WIDTH 640 // 窗口宽度
#define WIN_HIGH 480 // 窗口高度
#define SNAKE_NUM 500 // 蛇的最大节数
#define SNAKE_COLOR RED
#define FOOD_COLOR YELLOW // 蛇和食物的颜色
#define SNAKE_BODY 5 // 蛇身体的半径
#define FOOD_SIZE 5 // 食物半径
enum DIR // 蛇的方向
{
up, down, right, left
};
// 蛇的结构
struct Snake {
int size; // 蛇的节数
int dir; // 方向
int speed; // 速度
POINT coor[SNAKE_NUM]; // 坐标
};
// 食物结构
struct Food {
POINT coor;
int r;
bool flag; // 食物是否被吃
};
void Game_init(void); // 游戏初始化
void snake_init(void); // 蛇的初始化
void food_init(); // 食物初始化
void Game_draw(void); // 绘制函数
void snake_move(void); // 蛇的移动
void keyControl(void); // 通过按键改变蛇的方向
void EatFood(void); // 判断食物是否被吃
void Snake_life(void); // 判断蛇是否活着
#endif
// main.cpp
#include"snake.h"
int main(void)
{
// 初始化界面
Game_init();
// 绘图
Game_draw();
while (1)
{
Sleep(80);
keyControl();
snake_move();
Snake_life();
EatFood();
cleardevice();
Game_draw();
}
while (1);
return 0;
}
// init.cpp
#include"snake.h"
extern struct Food food;
extern struct Snake snake;
void Game_init(void)
{
// 创建绘图窗口,大小为 640x480 像素,EW_SHOWCONSOLE显示控制台
// initgraph(640, 480, EW_SHOWCONSOLE);
initgraph(WIN_WIDTH, WIN_HIGH);
// 设置背景颜色
setbkcolor(RGB(28, 115, 119));
cleardevice();
snake_init();
food_init();
}
void food_init(void)
{
// 一般将时间作为种子
srand((unsigned int)time(NULL));
food.coor.x = rand() % WIN_WIDTH;
food.coor.y = rand() % WIN_HIGH;
food.flag = true;
}
// 蛇的初始化
void snake_init(void)
{
snake.size = 3;
snake.dir = right;
snake.speed = 10;
for (int i = 0; i < snake.size; i++)
{
snake.coor[i].x = 200 - 10 * i;
snake.coor[i].y = 200;
}
}
// 判断是否吃了食物
void EatFood(void)
{
if (food.flag &&
snake.coor[0].x >= food.coor.x - SNAKE_BODY - FOOD_SIZE &&
snake.coor[0].x <= food.coor.x + SNAKE_BODY + FOOD_SIZE &&
snake.coor[0].y >= food.coor.y - SNAKE_BODY - FOOD_SIZE &&
snake.coor[0].y <= food.coor.y + SNAKE_BODY + FOOD_SIZE
)
{
food.flag = false;
snake.size++;
}
if (!food.flag)
{
food.coor.x = rand() % (WIN_WIDTH - 2 * FOOD_SIZE) + FOOD_SIZE;
food.coor.y = rand() % (WIN_HIGH - 2 * FOOD_SIZE) + FOOD_SIZE;
food.flag = true;
}
}
// game.cpp
#include"snake.h"
struct Food food;
struct Snake snake;
void Game_draw(void)
{
// 双缓冲绘图
BeginBatchDraw();
// 设置蛇的颜色,绘制蛇
setfillcolor(SNAKE_COLOR);
for (int i = 0; i < snake.size; i++)
{
solidcircle(snake.coor[i].x, snake.coor[i].y, SNAKE_BODY);
}
// 绘制食物
setfillcolor(FOOD_COLOR);
if (food.flag)
{
solidcircle(food.coor.x, food.coor.y, FOOD_SIZE);
}
EndBatchDraw();
}
// 通过按键改变蛇的方向
void keyControl(void)
{
// 判断有没有按键,有按键返回真
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() == ' ')
{
break;
}
}
break;
default:
break;
}
}
}
// 蛇的移动
void snake_move(void)
{
for (int i = snake.size - 1; i > 0; i--)
{
snake.coor[i].x = snake.coor[i - 1].x;
snake.coor[i].y = snake.coor[i - 1].y;
}
switch (snake.dir)
{
case right:
snake.coor[0].x += 10;
break;
case left:
snake.coor[0].x -= 10;
break;
case up:
snake.coor[0].y -= 10;
break;
case down:
snake.coor[0].y += 10;
break;
}
}
// 检测蛇是否死亡
void Snake_life(void)
{
if (snake.coor[0].x > WIN_WIDTH || snake.coor[0].y<0 || snake.coor[0].y>WIN_HIGH || snake.coor[0].y < 0)
{
outtextxy(WIN_WIDTH / 2, WIN_HIGH / 2, "撞墙了,游戏结束!");
getchar();
}
for (int i = 1; i < snake.size; i++)
{
if (snake.coor[0].x < snake.coor[i].x + 2 * SNAKE_BODY &&
snake.coor[0].x > snake.coor[i].x - 2 * SNAKE_BODY &&
snake.coor[0].y < snake.coor[i].y + 2 * SNAKE_BODY &&
snake.coor[0].y > snake.coor[i].y - 2 * SNAKE_BODY)
{
outtextxy(WIN_WIDTH / 2, WIN_HIGH / 2, "咬到了自己,游戏结束!");
getchar();
}
}
}
|