Raylib的贪吃蛇

配置Raylib库

    • 工具链
    • 主函数模板
    • Draw: 绘制网格
    • Snake: 初始化
    • Draw:绘制蛇与果
    • Input:移动
    • Logic:游戏主要逻辑
    • Draw: 游戏结束

工具链

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官方样例

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/718971.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

TWM论文阅读笔记

这是ICLR2023的一篇world model论文&#xff0c;用transformer来做世界模型的sequence prediction。文章贡献是transformer-based world model&#xff08;不同于以往的如transdreamer的world model&#xff0c;本文的transformer-based world model在inference 的时候可以丢掉…

适用于世界上最先进的医疗应用的高压电阻器

我们的电阻器专为用于医疗诊断、治疗和预防的各种产品而设计。从小型植入式和非侵入性设备到大型诊断成像设备&#xff0c;医疗制造商之所以选择 EAK电阻器&#xff0c;是因为操作环境是高电压和磁场&#xff0c;准确性和稳定性至关重要。 EAK 专有的精密打印技术生产出非常适…

Python自动化(1)——获取窗口句柄

Python自动化(1)——获取窗口句柄 前言 在现代生活中&#xff0c;人们的工作往往有很大的重复性。可能一个工作&#xff0c;会有90%的相似性&#xff0c;这时候&#xff0c;就会思考能否通过程序来代替人工。 Python作为近几年来大火的编程语言&#xff0c;其便捷性和高效性&a…

大模型基础——从零实现一个Transformer(5)

大模型基础——从零实现一个Transformer(1)-CSDN博客 大模型基础——从零实现一个Transformer(2)-CSDN博客 大模型基础——从零实现一个Transformer(3)-CSDN博客 大模型基础——从零实现一个Transformer(4)-CSDN博客 一、前言 上一篇文章已经把Encoder模块和Decoder模块都已…

vue标签组

先看样式 再看代码 <div v-else class"relative"><n-tabs ref"tabsInstRef" v-model:value"selectValue" class"min-w-3xl myTabs"><n-tab-panev-for"(tab) in songsTags" :key"tab.name" displ…

【数据结构初阶】--- 堆

文章目录 一、什么是堆&#xff1f;树二叉树完全二叉树堆的分类堆的实现方法 二、堆的操作堆的定义初始化插入数据&#xff08;包含向上调整详细讲解&#xff09;向上调整删除堆顶元素&#xff08;包含向下调整详细讲解&#xff09;向下调整返回堆顶元素判断堆是否为空销毁 三、…

Docker安装(内网无网环境),亲测简单易懂

文章目录 前言一、安装环境二、安装步骤三、启动四、查看状态总结 前言 Docker安装&#xff08;内网无网环境&#xff09;&#xff0c;亲测简单易懂 一、安装环境 CentOS Linux release 7.x Docker版本&#xff1a;18.09.8 二、安装步骤 &#xff01;&#xff01;&#xf…

网络学习(三)TCP三次握手、四次挥手,及Wireshark抓包验证

目录 一、什么是 TCP 三次握手&#xff1f;二、什么是 TCP 四次挥手&#xff1f;三、Wireshark抓包验证3.1 如何捕获三次握手、四次挥手3.2 TCP 三次握手的记录3.3 数据传输3.4 TCP 四次挥手的记录 一、什么是 TCP 三次握手&#xff1f; TCP&#xff08;Transmission Control …

计算机组成原理之存储器(二)

文章目录 随机读写存储器RAM静态MOS存储单元与存储芯片动态MOS存储单元与存储芯片 半导体存储器逻辑设计存储器的读写以及刷新存储器的读写动态存储芯片的刷新 随机读写存储器RAM 静态MOS存储单元与存储芯片 静态RAM用半导体管的导通和截止来记忆&#xff0c;只要不掉电&#x…

2.线性神经网络

目录 1.线性回归一个简化模型线性模型&#xff1a;可以看做是单层神经网络衡量预估质量训练数据参数学习显示解总结 2.基础优化方法小批量随机梯度下降总结 3.Softmax回归&#xff1a;其实是一个分类问题回归VS分类从回归到多类分类---均方损失Softmax和交叉熵损失 4.损失函数L…

使用插件永久解决IDEA使用Shift+F10失效问题(不需要换老版本输入法)

在日常编程中&#xff0c;使用快捷键可以大大提高开发效率。然而&#xff0c;有时候我们会遇到IDEA 中&#xff0c;ShiftF10 快捷键失效。这个蛋疼的问题现在终于可以得到解决&#xff0c;上个月在逛V2EX的时候看见一位大佬做的插件。 大佬链接&#xff1a;https://www.v2ex.c…

编程精粹—— Microsoft 编写优质无错 C 程序秘诀 02:设计并使用断言

这是一本老书&#xff0c;作者 Steve Maguire 在微软工作期间写了这本书&#xff0c;英文版于 1993 年发布。2013 年推出了 20 周年纪念第二版。我们看到的标题是中译版名字&#xff0c;英文版的名字是《Writing Clean Code ─── Microsoft’s Techniques for Developing》&a…

51单片机宏定义的例子

代码 demo.c #include "hardware.h"void delay() {volatile unsigned int n;for(n 0; n < 50000; n); }int main(void) {IO_init();while(1){PINSET(LED);delay();PINCLR(LED);delay();}return 0; }cfg.h #ifndef _CFG_H_ #define _CFG_H_// #define F_CPU …

nacos注册中心配置中心集群搭建

文章目录 学习连接1.Nacos安装与简单使用1.1. Nacos安装指南Windows安装下载安装包解压端口配置启动访问 Linux安装安装JDK上传安装包解压端口配置启动 1.2.服务注册到nacos使用步骤引入依赖配置nacos地址重启 示例父工程pom.xmluser-servicepom.xmlapplication.ymlUserApplica…

Jupyter Notebook 中 %run 魔法命令

目录 基本用法运行 Python 脚本运行 Jupyter Notebook 的其他单元格传递命令行参数 示例运行 Python 脚本示例运行其他 Jupyter Notebook 示例传递命令行参数示例 注意事项与 import 命令的区别%runimport 结论 %run 是 Jupyter Notebook 中的一个强大工具&#xff0c;它允许你…

【机器学习】第4章 决策树算法(重点)

一、概念 1.原理看图&#xff0c;非常简单&#xff1a; &#xff08;1&#xff09;蓝的是节点&#xff0c;白的是分支&#xff08;条件&#xff0c;或者说是特征&#xff0c;属性&#xff0c;也可以直接写线上&#xff0c;看题目有没有要求&#xff09;&#xff0c; &#xff0…

MySQL----InooDB行级锁、间隙锁

行级锁 行锁&#xff0c;也称为记录锁&#xff0c;顾名思义就是在记录上加的锁。 注意&#xff1a; InnoDB行锁是通过给索引上的索引项加锁来实现的&#xff0c;而不是给表的行记录加锁实现的&#xff0c;这就意味着只有通过索引条件检索数据&#xff0c;InnoDB才使用行级锁…

【开发工具】git服务器端安装部署+客户端配置

自己安装一个轻量级的git服务端&#xff0c;仅仅作为代码维护&#xff0c;尤其适合个人代码管理。毕竟代码的版本管理是很有必要的。 这里把git服务端部署在centos系统里&#xff0c;部署完成后可以通过命令行推拉代码&#xff0c;进行版本和用户管理。 一、服务端安装配置 …

【Kubernetes】k8s--安全机制

机制说明 Kubernetes 作为一个分布式集群的管理工具&#xff0c;保证集群的安全性是其一个重要的任务。API Server 是集群内部各个组件通信的中介&#xff0c; 也是外部控制的入口。所以 Kubernetes 的安全机制基本就是围绕保护 API Server 来设计的。 比如 kubectl 如果想向 …

新版FMEA培训内容中关于团队协作的部分可以怎么展开?

团队协作&#xff0c;作为新版FMEA的核心要素之一&#xff0c;其重要性不言而喻。在FMEA的分析过程中&#xff0c;团队成员的密切合作与沟通是确保分析全面性和准确性的关键。通过团队协作&#xff0c;不同领域的专家能够共同参与到潜在故障模式的识别、评估与预防中来&#xf…