Raylib的贪吃蛇

工具链

mkdir snake
cd snake
  • CMakeLists.txt
cmake_minimum_required(VERSION 3.10)
project(snake)
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
find_package(raylib CONFIG REQUIRED)
add_executable(snake main.cpp)
target_link_libraries(snake PRIVATE raylib)
  • CMakePresets.json
{
  "version": 2,
  "configurePresets": [
    {
      "name": "default",
      "generator": "Ninja",
      "binaryDir": "${sourceDir}/build",
      "cacheVariables": {
        "CMAKE_TOOLCHAIN_FILE": "$env{VCPKG_ROOT}/scripts/buildsystems/vcpkg.cmake"
      }
    }
  ]
}

主函数模板

main

#include "raylib.h"

#define SNAKE_LENGTH 256
#define SQUARE_SIZE 31

typedef struct Snake {
  Vector2 position;
  Vector2 size;
  Color color;
  Vector2 speed;
} Snake;

typedef struct Fruit {
  Vector2 position;
  Vector2 size;
  Color color;
  bool active;
} Fruit;

static const int screenWidth = 800;
static const int screenHeight = 450;

static int framesCounter = 0;
static bool allowMove = false;
static bool gameOver = false;

static Snake snake[SNAKE_LENGTH];
static Vector2 snakePosition[SNAKE_LENGTH];
static Vector2 offset;
static int nTail;
static Fruit fruit;

static void InitGame(void);
static void Draw(void);
static void Input(void);
static void Logic(void);
int main(void) {
  InitWindow(screenWidth, screenHeight, "snake game with raylib");
  SetTargetFPS(60);
  InitGame();
  while (!WindowShouldClose()) {
    Draw();
    Input();
    Logic();
  }
  CloseWindow();
  return 0;
}
void InitGame(void) {
  framesCounter = 0;
  allowMove = true;
  gameOver = false;
  nTail = 1;
  offset.x = screenWidth % SQUARE_SIZE;
  offset.y = screenHeight % SQUARE_SIZE;
  // @TODO: init snake
  // @TODO: init fruit
}
// Draw game (one frame)
void Draw(void) {
  BeginDrawing();
  ClearBackground(RAYWHITE);
  if (!gameOver) {
    // @TODO: Draw grid lines
    // @TODO: Draw fruit to pick
  } else {
    // @TODO: print help message
  }
  EndDrawing();
}

void Input(void) {}
void Logic(void) {}
vcpkg new --application
vcpkg add port raylib
cmake --preset=default
cmake --build build

Draw: 绘制网格

    DrawLineV(
        Vector2{SQUARE_SIZE * 1 + offset.x / 2, offset.y / 2},
        Vector2{SQUARE_SIZE * 1 + offset.x / 2, screenHeight - offset.y / 2},
        LIGHTGRAY);
    DrawLineV(
        Vector2{offset.x / 2, SQUARE_SIZE * 2 + offset.y / 2},
        Vector2{screenWidth - offset.x / 2, SQUARE_SIZE * 2 + offset.y / 2},
        LIGHTGRAY);
    for (int i = 0; i < screenWidth / SQUARE_SIZE + 1; i++) {
      DrawLineV(
          Vector2{SQUARE_SIZE * i + offset.x / 2, offset.y / 2},
          Vector2{SQUARE_SIZE * i + offset.x / 2, screenHeight - offset.y / 2},
          LIGHTGRAY);
    }
    for (int i = 0; i < screenHeight / SQUARE_SIZE + 1; i++) {
      DrawLineV(
          Vector2{offset.x / 2, SQUARE_SIZE * i + offset.y / 2},
          Vector2{screenWidth - offset.x / 2, SQUARE_SIZE * i + offset.y / 2},
          LIGHTGRAY);
    }

Snake: 初始化

  // @TODO: init snake
  for (int i = 0; i < SNAKE_LENGTH; i++) {
    snake[i].position = Vector2{offset.x / 2, offset.y / 2};
    snake[i].size = Vector2{SQUARE_SIZE, SQUARE_SIZE};
    snake[i].speed = Vector2{SQUARE_SIZE, 0};
    if (i == 0)
      snake[i].color = DARKBLUE;
    else
      snake[i].color = BLUE;
  }
  for (int i = 0; i < SNAKE_LENGTH; i++) {
    snakePosition[i] = Vector2{0.0f, 0.0f};
  }
  // @TODO: init fruit
  fruit.size = Vector2{SQUARE_SIZE, SQUARE_SIZE};
  fruit.color = SKYBLUE;
  fruit.active = false;
  fruit.position = Vector2{
      GetRandomValue(0, (screenWidth / SQUARE_SIZE) - 1) * SQUARE_SIZE +
          offset.x / 2,
      GetRandomValue(0, (screenHeight / SQUARE_SIZE) - 1) * SQUARE_SIZE +
          offset.y / 2};

Draw:绘制蛇与果

    // Draw snake
    for (int i = 0; i < nTail; i++)
      DrawRectangleV(snake[i].position, snake[i].size, snake[i].color);
    // Draw fruit to pick
    DrawRectangleV(fruit.position, fruit.size, fruit.color);

Input:移动

  if (!gameOver) {
    // Player control
    if (IsKeyPressed(KEY_RIGHT) && (snake[0].speed.x == 0) && allowMove) {
      snake[0].speed = Vector2{SQUARE_SIZE, 0};
      allowMove = false;
    }
    if (IsKeyPressed(KEY_LEFT) && (snake[0].speed.x == 0) && allowMove) {
      snake[0].speed = Vector2{-SQUARE_SIZE, 0};
      allowMove = false;
    }
    if (IsKeyPressed(KEY_UP) && (snake[0].speed.y == 0) && allowMove) {
      snake[0].speed = Vector2{0, -SQUARE_SIZE};
      allowMove = false;
    }
    if (IsKeyPressed(KEY_DOWN) && (snake[0].speed.y == 0) && allowMove) {
      snake[0].speed = Vector2{0, SQUARE_SIZE};
      allowMove = false;
    }
  }

Logic:游戏主要逻辑

  if (!gameOver) {
    for (int i = 0; i < nTail; i++)
      snakePosition[i] = snake[i].position;
    if ((framesCounter % 5) == 0) {
      for (int i = 0; i < nTail; i++) {
        if (i == 0) {
          snake[0].position.x += snake[0].speed.x;
          snake[0].position.y += snake[0].speed.y;
          allowMove = true;
        } else
          snake[i].position = snakePosition[i - 1];
      }
    }
    // Wall behaviour
    if (((snake[0].position.x) > (screenWidth - offset.x)) ||
        ((snake[0].position.y) > (screenHeight - offset.y)) ||
        (snake[0].position.x < 0) || (snake[0].position.y < 0)) {
      gameOver = true;
    }
    // Collision with yourself
    for (int i = 1; i < nTail; i++) {
      if ((snake[0].position.x == snake[i].position.x) &&
          (snake[0].position.y == snake[i].position.y))
        gameOver = true;
    }
    // Fruit position calculation
    if (!fruit.active) {
      fruit.active = true;
      fruit.position = Vector2{
          GetRandomValue(0, (screenWidth / SQUARE_SIZE) - 1) * SQUARE_SIZE +
              offset.x / 2,
          GetRandomValue(0, (screenHeight / SQUARE_SIZE) - 1) * SQUARE_SIZE +
              offset.y / 2};
      for (int i = 0; i < nTail; i++) {
        while ((fruit.position.x == snake[i].position.x) &&
               (fruit.position.y == snake[i].position.y)) {
          fruit.position = Vector2{
              GetRandomValue(0, (screenWidth / SQUARE_SIZE) - 1) * SQUARE_SIZE +
                  offset.x / 2,
              GetRandomValue(0, (screenHeight / SQUARE_SIZE) - 1) *
                      SQUARE_SIZE +
                  offset.y / 2};
          i = 0;
        }
      }
    }
    // Collision
    if ((snake[0].position.x < (fruit.position.x + fruit.size.x) &&
         (snake[0].position.x + snake[0].size.x) > fruit.position.x) &&
        (snake[0].position.y < (fruit.position.y + fruit.size.y) &&
         (snake[0].position.y + snake[0].size.y) > fruit.position.y)) {
      snake[nTail].position = snakePosition[nTail - 1];
      nTail += 1;
      fruit.active = false;
    }
    framesCounter++;
  } else {
    if (IsKeyPressed(KEY_ENTER)) {
      InitGame();
      gameOver = false;
    }
  }

游戏

Draw: 游戏结束

    DrawText("PRESS [ENTER] TO PLAY AGAIN",
             GetScreenWidth() / 2 -
                 MeasureText("PRESS [ENTER] TO PLAY AGAIN", 20) / 2,
             GetScreenHeight() / 2 - 50, 20, GRAY);

over


该例子来自raylib官方样例

  • 4
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值