贪吃蛇是一个流行度非常高的游戏,玩法十分简单,从最初的方块机上就有这个游戏了,后来出现的手机中也是加入了这个游戏,无聊的时候可以打发时间玩一会。这个游戏可谓是非常的简单,容易上手,所以直到现在,还能看到它的身影。大多数学习编程的同学在学习编程语言后,也都会想着写一个自己的游戏,可能大部分同学也是抱着这样的想法开始学习的编程,那么简单的贪吃蛇游戏就成了很好的练手项目,所以可以在网上看到很多各种编程语言的贪吃蛇游戏代码。
每当看到网上这些贪吃蛇代码的时候,就觉得也不是很难,逻辑也简单,看看就会了,所以也没有实际动手去编写一下(不知道有没有人和我一样)。可是每当有时间的时候,看一些练手项目的时候大概率会看到贪吃蛇这个游戏,然后就会看到各路大神编写的代码,有100多行完成的,有200多行完成的,还有14行就完成的,就感觉挺厉害的。这个时候我就在想,我自己写这个游戏的话,需要多少行代码能够完成呢?反正14行我是搞不定的,估计200行左右还是可能的。正好最近时间上比较闲,所以就动手来写一下,也不要总看不练。
代码是使用C++进行编写的,图形界面绘制选择的是EasyX。EasyX Graphics Library 是针对 Visual C++ 的免费绘图库,支持 VC6.0 ~ VC2022,简单易用,官网地址是:EasyX Graphics Library for C++,有兴趣的同学可以去看一下。至于需求逻辑方面就没有什么好说的了。那么接下来,直接上代码。
#include <graphics.h>
#include <time.h>
#include <conio.h>
#include <vector>
#include <array>
#define WIN_SIZE 600
#define BLOCK_SIZE 40
#define SPEED 100
#define LEN (WIN_SIZE / BLOCK_SIZE)
// 声明节点结构体,用于表示蛇身体和食物的坐标
struct Node
{
int x;
int y;
};
// 声明方向
enum Direction
{
UP, DOWN, LEFT, RIGHT
};
// 声明数组值类型
enum BlockType
{
// 0:空白,1:蛇身,2:食物
NONE = 0, SNAKE, FOOD
};
// 绘制指定节点并设置所在二维数组
void drawNode(const Node& node, std::array<std::array<UINT8, LEN>, LEN>& arr,
BlockType type = SNAKE)
{
setfillcolor(RED);
fillrectangle(node.x * BLOCK_SIZE, node.y * BLOCK_SIZE,
node.x * BLOCK_SIZE + BLOCK_SIZE, node.y * BLOCK_SIZE + BLOCK_SIZE);
arr[node.y][node.x] = type;
}
// 清除指定节点并清除二维数组对应数据
void clearNode(const Node& node, std::array<std::array<UINT8, LEN>, LEN>& arr)
{
setfillcolor(WHITE);
fillrectangle(node.x * BLOCK_SIZE, node.y * BLOCK_SIZE,
node.x * BLOCK_SIZE + BLOCK_SIZE, node.y * BLOCK_SIZE + BLOCK_SIZE);
arr[node.y][node.x] = NONE;
}
// 绘制界面方格
void drawBlock()
{
setbkcolor(WHITE);
setlinecolor(GREEN);
cleardevice();
for (int i = BLOCK_SIZE; i <= WIN_SIZE; i += BLOCK_SIZE)
{
line(i, 0, i, WIN_SIZE);
line(0, i, WIN_SIZE, i);
}
}
// 绘制蛇身并设置蛇身所在二维数组
void drawSnake(const std::vector<Node>& snake, std::array<std::array<UINT8, LEN>, LEN>& arr)
{
for (Node node : snake)
{
drawNode(node, arr);
}
}
// 随机生成食物
void randFood(std::array<std::array<UINT8, LEN>, LEN>& arr)
{
int x, y;
do
{
x = rand() % LEN;
y = rand() % LEN;
} while (arr[y][x] == SNAKE);
drawNode({x, y}, arr, FOOD);
}
// 移动,如果碰到蛇身或墙壁则游戏结束
bool move(std::vector<Node>& snake, std::array<std::array<UINT8, LEN>, LEN>& arr,
Direction& direction)
{
Node first = snake.back();
Node second = snake.at(snake.size() - 2);
Node node = first;
switch (direction)
{
case UP:
node.y--;
break;
case DOWN:
node.y++;
break;
case LEFT:
node.x--;
break;
case RIGHT:
node.x++;
break;
}
// 判断是否可以移动,移动方向不能为当前方向的反方向
if (!((node.x == second.x && (direction == LEFT || direction == RIGHT)) ||
(node.y == second.y && (direction == UP || direction == DOWN))))
{
if (node.x < 0 || node.x >= LEN ||
node.y < 0 || node.y >= LEN ||
arr[node.y][node.x] == SNAKE)
{
// 装到墙壁或蛇身则游戏结束
return false;
}
else if (arr[node.y][node.x] == FOOD)
{
arr[node.y][node.x] == SNAKE;
snake.push_back(node);
randFood(arr);
}
else
{
arr[node.y][node.x] == SNAKE;
snake.push_back(node);
clearNode(snake.front(), arr);
snake.erase(snake.begin());
drawNode(node, arr);
}
}
return true;
}
// 游戏
void game()
{
using namespace std;
// 蛇身
vector<Node> snake = { {0, 0}, {1, 0}, {2, 0} };
// 二维数组,记录蛇身和食物是否在某位置上
array<array<UINT8, LEN>, LEN> arr;
for (auto& ar : arr) {
memset(&ar, NONE, size(ar));
}
// 默认起始向右移动
Direction direction = RIGHT;
drawBlock();
drawSnake(snake, arr);
randFood(arr);
// 定义消息变量
ExMessage m;
while (move(snake, arr, direction))
{
// 获取一条按键消息
peekmessage(&m, EX_KEY);
switch (m.vkcode)
{
case VK_UP:
direction = direction == DOWN ? DOWN : UP;
break;
case VK_DOWN:
direction = direction == UP ? UP : DOWN;
break;
case VK_LEFT:
direction = direction == RIGHT ? RIGHT : LEFT;
break;
case VK_RIGHT:
direction = direction == LEFT ? LEFT : RIGHT;
break;
}
Sleep(150);
}
settextstyle(36, 0, _T("Consolas"));
settextcolor(RED);
outtextxy(100, 250, "GAME OVER,按s键开始游戏");
}
int main()
{
// 创建绘图窗口
initgraph(WIN_SIZE, WIN_SIZE);
// 设置随机种子
srand((unsigned)time(NULL));
while (true)
{
game();
while ('s' != _getch());
}
closegraph();
return 0;
}
代码量和我开始预计的差不多,200行出头,程序应该还有可以优化的地方。这里贴出代码是为了给大家提供一个思路,有兴趣的也可以自己尝试着写一写这个贪吃蛇,看看用多少行代码可以完成,也是对自己编程能力的锻炼。最后,让我们看一下编写的这个贪吃蛇的运行效果。
欢迎关注我的公众号