基于EasyX和Raylib的贪吃蛇
基于 EasyX
// 根据《C和C++游戏趣味编程》第七章 贪吃蛇 写出
#include <graphics.h>
#include <conio.h> // _kbhit()
#include <stdio.h>
#include <stdlib.h>
// 全局变量定义
#define HEIGHT 30 // 高度上一共30个小格子
#define WIDTH 40 // 宽度上一共40个小格子
#define BLOCK_SIZE 20 // 每个小格子的长宽大小
int blocks[HEIGHT][WIDTH] = { 0 }; // 记录所有的游戏数据
char moveDirection = 'd'; // move to right
bool fail = false; // 是否游戏失败
bool shouldExit = false;
int food_i;
int food_j;
// 初始化函数
void startup()
{
blocks[HEIGHT / 2][WIDTH / 2] = 1; // 画面中间画蛇头,数字为1
// 向左依次4个蛇身,数值依次为2, 3, 4, 5
for (int i = 1; i <= 4; i++)
{
blocks[HEIGHT / 2][WIDTH / 2 - i] = i + 1;
}
food_i = rand() % (HEIGHT - 5) + 2;
food_j = rand() % (WIDTH - 5) + 2;
initgraph(WIDTH * BLOCK_SIZE, HEIGHT * BLOCK_SIZE, SHOWCONSOLE);
SetWindowText(GetHWnd(), "Greedy Snake");
setlinecolor(RGB(200, 200, 200));
BeginBatchDraw();
}
void moveSnake()
{
for (int i = 0; i < HEIGHT; i++)
{
for (int j = 0; j < WIDTH; j++)
{
if (blocks[i][j] > 0) // 蛇身
{
blocks[i][j]++;
}
}
}
int oldTail_i;
int oldTail_j;
int oldHead_i;
int oldHead_j;
int max = 0;
for (int i = 0; i < HEIGHT; i++)
{
for (int j = 0; j < WIDTH; j++)
{
if (max < blocks[i][j])
{
max = blocks[i][j];
oldTail_i = i;
oldTail_j = j;
}
if (blocks[i][j] == 2) // 原来的蛇头
{
oldHead_i = i;
oldHead_j = j;
}
}
}
int newHead_i = oldHead_i;
int newHead_j = oldHead_j;
if (moveDirection == 'w') // up
{
newHead_i = oldHead_i - 1;
}
if (moveDirection == 'd') // right
{
newHead_j = oldHead_j + 1;
}
if (moveDirection == 'a') // left
{
newHead_j = oldHead_j - 1;
}
if (moveDirection == 's') // down
{
newHead_i = oldHead_i + 1;
}
// 撞墙、撞到自身, 都算失败
if ((newHead_j >= WIDTH || newHead_j < 0 || newHead_i >= HEIGHT || newHead_i < 0)
|| (blocks[newHead_i][newHead_j] > 0)
)
{
fail = true;
return;
}
blocks[newHead_i][newHead_j] = 1; // 生成新蛇头
if (newHead_i == food_i && newHead_j == food_j) // 蛇头吃到食物
{
// 重新生成食物
food_i = rand() % (HEIGHT - 5) + 2;
food_j = rand() % (WIDTH - 5) + 2;
}
else
{
blocks[oldTail_i][oldTail_j] = 0; // 没吃到食物时,旧蛇尾变成空白,蛇长度不变
}
}
// 绘制函数
void show()
{
cleardevice();
// 绘制每个方格
for (int i = 0; i < HEIGHT; i++)
{
for (int j = 0; j < WIDTH; j++)
{
if (blocks[i][j] > 0) // 大于0表示是蛇,这里让蛇的身体颜色色调渐变
{
setfillcolor(HSVtoRGB(blocks[i][j] * 10, 0.9, 1));
}
else // 元素为0表示为空,颜色为灰色
{
setfillcolor(RGB(150, 150, 150));
}
// 在对应位置处,以对应颜色绘制小方格
fillrectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, (j+1) * BLOCK_SIZE, (i+1) * BLOCK_SIZE);
}
}
// 绘制食物
setfillcolor(RGB(0, 255, 0));
fillrectangle(food_j * BLOCK_SIZE, food_i * BLOCK_SIZE, (food_j + 1) * BLOCK_SIZE, (food_i + 1) * BLOCK_SIZE);
if (fail)
{
setbkmode(TRANSPARENT); // 文字字体透明
settextcolor(RGB(255, 0, 0)); // 文字颜色
settextstyle(80, 0, _T("Consolas")); // 文字颜色、大小、样式
outtextxy(240, 220, _T("Game Over"));
}
FlushBatchDraw();
}
// 与输入无关的更新
void updateWithoutInput()
{
if (fail)
{
return;
}
static int waitIndex = 1; // 用于替代原有的用Sleep()来控制帧率的做法。
waitIndex++;
// 小蛇每隔10帧移动一次。
if (waitIndex == 10)
{
moveSnake();
waitIndex = 1;
}
}
// 和输入有关的更新
void updateWithInput()
{
if (kbhit())
{
char input = getch();
if (!fail)
{
if (input == 'a' || input == 's' || input == 'd' || input == 'w')
{
moveDirection = input;
}
}
if (input == 'q')
{
shouldExit = true;
}
}
}
int main()
{
startup();
while (!shouldExit)
{
show();
updateWithInput();
updateWithoutInput();
}
closegraph();
return 0;
}
基于 Raylib
// 根据《C和C++游戏趣味编程》第七章 贪吃蛇 写出
#include "raylib.h"
#include <stdio.h>
#include <stdlib.h>
#include "raylib_helper.hpp"
// 全局变量定义
#define HEIGHT 30 // 高度上一共30个小格子
#define WIDTH 40 // 宽度上一共40个小格子
#define BLOCK_SIZE 20 // 每个小格子的长宽大小
int blocks[HEIGHT][WIDTH] = { 0 }; // 记录所有的游戏数据
char moveDirection = 'd'; // move to right
bool fail = 0; // 是否游戏失败
int food_i;
int food_j;
// 初始化函数
void startup()
{
blocks[HEIGHT / 2][WIDTH / 2] = 1; // 画面中间画蛇头,数字为1
// 向左依次4个蛇身,数值依次为2, 3, 4, 5
for (int i = 1; i <= 4; i++)
{
blocks[HEIGHT / 2][WIDTH / 2 - i] = i + 1;
}
food_i = rand() % (HEIGHT - 5) + 2;
food_j = rand() % (WIDTH - 5) + 2;
InitWindow(WIDTH * BLOCK_SIZE, HEIGHT * BLOCK_SIZE, "greedy snake");
SetTargetFPS(60);
}
void show()
{
BeginDrawing();
{
ClearBackground(BLACK);
// 绘制每个方格
for (int i = 0; i < HEIGHT; i++)
{
for (int j = 0; j < WIDTH; j++)
{
if (blocks[i][j] > 0) // 大于0表示是蛇,这里让蛇的身体颜色色调渐变
{
Color fill_color = ColorFromHSV(blocks[i][j] * 10, 0.9, 1);
DrawRectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, fill_color);
}
else // 元素为0表示为空,颜色为灰色
{
DrawRectangle(j * BLOCK_SIZE, i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, make_color(150, 150, 150, 255));
}
// easyx 的 fillrectangle() 会自动绘制边框颜色, raylib 绘制矩形(内部填充)时则并不会绘制边框颜色。
DrawRectangleLines(j * BLOCK_SIZE, i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, make_color(200, 200, 200, 255));
}
}
// 绘制食物
DrawRectangle(food_j * BLOCK_SIZE, food_i * BLOCK_SIZE, BLOCK_SIZE, BLOCK_SIZE, GREEN);
if (fail)
{
DrawText("Game Over", 240, 200, 80, RED);
}
}
EndDrawing();
}
void moveSnake()
{
for (int i = 0; i < HEIGHT; i++)
{
for (int j = 0; j < WIDTH; j++)
{
if (blocks[i][j] > 0) // 蛇身
{
blocks[i][j]++;
}
}
}
int oldTail_i;
int oldTail_j;
int oldHead_i;
int oldHead_j;
int max = 0;
for (int i = 0; i < HEIGHT; i++)
{
for (int j = 0; j < WIDTH; j++)
{
if (max < blocks[i][j])
{
max = blocks[i][j];
oldTail_i = i;
oldTail_j = j;
}
if (blocks[i][j] == 2) // 原来的蛇头
{
oldHead_i = i;
oldHead_j = j;
}
}
}
int newHead_i = oldHead_i;
int newHead_j = oldHead_j;
if (moveDirection == 'w') // up
{
newHead_i = oldHead_i - 1;
}
if (moveDirection == 'd') // right
{
newHead_j = oldHead_j + 1;
}
if (moveDirection == 'a') // left
{
newHead_j = oldHead_j - 1;
}
if (moveDirection == 's') // down
{
newHead_i = oldHead_i + 1;
}
// 撞墙、撞到自身, 都算失败
if ((newHead_j >= WIDTH || newHead_j < 0 || newHead_i >= HEIGHT || newHead_i < 0)
|| (blocks[newHead_i][newHead_j] > 0)
)
{
fail = true;
return;
}
blocks[newHead_i][newHead_j] = 1; // 生成新蛇头
if (newHead_i == food_i && newHead_j == food_j) // 蛇头吃到食物
{
// 重新生成食物
food_i = rand() % (HEIGHT - 5) + 2;
food_j = rand() % (WIDTH - 5) + 2;
}
else
{
blocks[oldTail_i][oldTail_j] = 0; // 没吃到食物时,旧蛇尾变成空白,蛇长度不变
}
}
void updateWithoutInput()
{
if (fail)
{
return;
}
static int waitIndex = 1;
waitIndex++;
if (waitIndex == 10)
{
moveSnake();
waitIndex = 1;
}
}
// 相比于 easyx, 除了asdw键, 还可以使用方向键
void updateWithInput()
{
if (IsKeyDown(KEY_A) || IsKeyDown(KEY_LEFT))
moveDirection = 'a';
else if (IsKeyDown(KEY_S) || IsKeyDown(KEY_DOWN))
moveDirection = 's';
else if (IsKeyDown(KEY_D) || IsKeyDown(KEY_RIGHT))
moveDirection = 'd';
else if (IsKeyDown(KEY_W) || IsKeyDown(KEY_UP))
moveDirection = 'w';
}
int main()
{
startup();
while (!WindowShouldClose())
{
show();
updateWithInput();
updateWithoutInput();
}
CloseWindow();
}
Greatness is never a given, it must be earned.