我使用 raylib 库用 C++ 编写了一个蛇程序。我的游戏在一定时间(几分钟)后完全冻结。
这是我的程序的完整代码:
#include <iostream>
#include "raylib.h"
#include "raymath.h"
#include <deque>
using namespace std;
// Constant Values
const int cell_size = 40; // Cell size has to be equal to assets dimension in pixels
const int cell_count_x = 20, cell_count_y = 15;
const int game_width = cell_size * cell_count_x;
const int game_height = cell_size * cell_count_y;
const int FPS = 60;
const int offset = cell_size * 2;
const int font_size = 40;
// Classes
class Food {
public:
Vector2 position;
Texture texture;
Food(deque<Vector2> snake_body) {
Image image = LoadImage("Graphics/apple.png");
texture = LoadTextureFromImage(image);
UnloadImage(image);
position = GetRandomPos(snake_body);
}
~Food() {
UnloadTexture(texture);
}
void Draw() {
DrawTexture(texture, offset + position.x * cell_size, offset + position.y * cell_size, WHITE);
}
Vector2 GetRandomPos(deque<Vector2> snake_body) {
float x = GetRandomValue(0, cell_count_x - 1);
float y = GetRandomValue(0, cell_count_y - 1);
Vector2 position = { x, y };
while (CheckPos(snake_body, position) == false) {
float x = GetRandomValue(0, cell_count_x - 1);
float y = GetRandomValue(0, cell_count_y - 1);
Vector2 position = { x, y };
}
return position;
}
bool CheckPos(deque<Vector2> snake_body, Vector2 position) {
for (int i = 0; i < snake_body.size(); i++)
if (Vector2Equals(snake_body[i], position))
return false;
return true;
}
};
class Snake {
public:
deque<Vector2> body = { Vector2{cell_count_x / 3, cell_count_y / 3}, Vector2{cell_count_x / 3 - 1, cell_count_y / 3} , Vector2{cell_count_x / 3 - 1, cell_count_y / 3} };
Vector2 direction = { 1, 0 };
bool fruit_collision = false;
void Draw() {
for (int i = 0; i < body.size(); i++) {
float x = body[i].x;
float y = body[i].y;
Rectangle body_part = Rectangle{ offset + x * cell_size, offset + y * cell_size, (float)cell_size, (float)cell_size };
DrawRectangleRounded(body_part, 0.5, 10, DARKGREEN);
}
}
void UpdateMovement() {
if (fruit_collision)
fruit_collision = false;
else
body.pop_back();
body.push_front(Vector2Add(body[0], direction));
}
void UpdateDirection() {
if (IsKeyPressed(KEY_UP) && direction.y != 1)
direction = { 0, -1 };
if (IsKeyPressed(KEY_DOWN) && direction.y != -1)
direction = { 0, 1 };
if (IsKeyPressed(KEY_LEFT) && direction.x != 1)
direction = { -1, 0 };
if (IsKeyPressed(KEY_RIGHT) && direction.x != -1)
direction = { 1, 0 };
}
void Reset() {
body = { Vector2{cell_count_x / 3, cell_count_y / 3}, Vector2{cell_count_x / 3 - 1, cell_count_y / 3} , Vector2{cell_count_x / 3 - 1, cell_count_y / 3} };
direction = { 1, 0 };
}
};
class Game {
public:
Snake snake = Snake();
Food food = Food(snake.body);
double last_update_time = 0;
int score = 0, max_score = 0;
Sound food_sound, death_sound;
Game() {
InitAudioDevice();
food_sound = LoadSound("Sounds/food_sound.mp3");
death_sound = LoadSound("Sounds/death_sound.mp3");
}
~Game() {
UnloadSound(food_sound);
UnloadSound(death_sound);
CloseAudioDevice();
}
void Draw() {
food.Draw();
snake.Draw();
}
void DisplayText() {
DrawText("Snake Game", offset, offset / 2, font_size, DARKGREEN);
DrawText("Score: ", offset, offset + game_height + 5, font_size, DARKGREEN);
DrawText(TextFormat("%i", score), offset + 150, offset + game_height + 5, font_size, DARKGREEN);
DrawText("Max Score: ", offset + game_width - 260, offset + game_height + 5, font_size, DARKGREEN);
DrawText(TextFormat("%i", max_score), offset + game_width - 15, offset + game_height + 5, font_size, DARKGREEN);
}
void Update() {
snake.UpdateDirection();
if (EventTriggered(0.2))
snake.UpdateMovement();
CheckCollisionWithFood();
CheckCollisionWithEdge();
CheckCollisionWithBody();
}
void CheckCollisionWithFood() {
if (Vector2Equals(snake.body[0], food.position)) {
food.position = food.GetRandomPos(snake.body);
snake.fruit_collision = true;
score++;
PlaySound(food_sound);
}
}
void CheckCollisionWithEdge() {
if (snake.body[0].x >= cell_count_x || snake.body[0].x == -1 || snake.body[0].y >= cell_count_y || snake.body[0].y == -1)
GameOver();
}
void CheckCollisionWithBody() {
for (int i = 2; i < snake.body.size(); i++)
if (Vector2Equals(snake.body[0], snake.body[i]))
GameOver();
}
void GameOver() {
snake.Reset();
food.position = food.GetRandomPos(snake.body);
if (score > max_score)
max_score = score;
score = 0;
PlaySound(death_sound);
}
bool EventTriggered(double interval) {
double current_time = GetTime();
if (current_time - last_update_time >= interval) {
last_update_time = current_time;
return true;
}
return false;
}
};
int main()
{
InitWindow(game_width + offset * 2, game_height + offset * 2, "Snake");
SetTargetFPS(FPS);
// Game Class
Game game = Game();
// Main Loop
while (WindowShouldClose() == false) {
BeginDrawing();
// Update
game.Update();
// Draw
ClearBackground(GREEN);
DrawRectangleLinesEx(Rectangle{ offset - 5, offset - 5, cell_size * cell_count_x + 10, cell_size * cell_count_y + 10 }, 5, DARKGREEN);
game.Draw();
game.DisplayText();
EndDrawing();
}
CloseWindow();
return 0;
}
问题出在
GetRandomPos
中,您声明了一个新的 position
,它遮盖了您打算重新分配的 position
:
Vector2 position = { x, y };
while (CheckPos(snake_body, position) == false) { // position 1
float x = GetRandomValue(0, cell_count_x - 1);
float y = GetRandomValue(0, cell_count_y - 1);
Vector2 position = { x, y }; // position 2
}
每当选择蛇体顶部的随机位置时,这都会使游戏陷入无限循环。
只需重新分配即可:
Vector2 position = { x, y };