imx6ull 单核CPU软件渲染,无硬件GPU加速,贴图会让CPU满负荷运行,所以做了优化。
纯色方块 + 降低到30fps + 不透明粒子 + 点阵数字,软渲染下最低开销。
重要提示:开发板 显示游戏画面的方法,参考前面的 mame 模拟器的文章,烧录或者挂载 Ubuntu 20.04.5 LTS 最小根文件系统,然后安装 xorg 、xserver-xorg-video-fbdev 、 xinit,才能显示画面,buildroot 制作的最小系统安装的 xorg 无法显示游戏画面,也可能是我没配置对,很耗费时间。
|------|-------------------------------|
| 游戏区域 | 40×24 格,800×480 全屏 |
| 普通食物 | 2 个,始终刷新 |
| 毒方块 | 3-7 个,2×2 紫色,15 秒存活,15-25 秒刷新 |
| 中毒 | 强制加速 6 秒,7 级+ 更猛,蛇身变紫 |
| 升级 | 每 5 分升1级,12 级封顶 |
| 分数显示 | 吃1个食物 加1分 |
| 粒子特效 | 吃食物 金色爆发,不透明金色,life 控制消失 |
| 蛇眼 | 方向自适应 |
| 帧率 | 30fps |
开发板,开启高性能模式, CPU 占用率 可再降低 10%左右。
**1.**先看看现在的 CPU 频率策略:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
如果输出是 ondemand ,说明 CPU 在动态调频。
**2.**开发板,临时开启高性能模式(792MHz):
echo performance > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
注意:performance 高性能模式会增加功耗和发热。
**3.**再次查看策略:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
cat /sys/devices/system/cpu/cpu*/cpufreq/scaling_cur_freq
4. CPU 改回 ondemand 模式:
echo ondemand > /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
验证:
cat /sys/devices/system/cpu/cpu0/cpufreq/scaling_governor
查看当前 CPU 温度(单位通常是毫摄氏度,除以 1000 即为摄氏度)
cat /sys/class/thermal/thermal_zone0/temp
例如:显示 53660 -> 53660 / 1000 = 53.66 °C
下面是贪吃蛇代码:
SnakeGame.cpp
#include <SDL2/SDL.h>
#include <deque>
#include <cstdlib>
#include <ctime>
#include <cstdio>
#include <vector>
#include <algorithm>
#include "DigitFont.h"
/*
控制方向: WSAD 或 方向键
暂停: P
重新开始: 结束后,按 R
退出游戏: ESC
*/
// 在老式的 C/C++ 代码中,定义常量通常用宏定义 #define
// 现代写法,使用 constexpr 替代宏 #define ,类型更安全
constexpr int Width = 40;
constexpr int Height = 24;
constexpr int CELL = 20; // 每格像素
constexpr int WIN_W = Width * CELL; // 800
constexpr int WIN_H = Height * CELL; // 480
namespace Color // 颜色常量
{
// 背景 深灰
constexpr Uint8 BG_R = 10, BG_G = 10, BG_B = 10;
// 边框 灰色
constexpr Uint8 BORDER_R = 60, BORDER_G = 60, BORDER_B = 60;
// 食物 亮红色
constexpr Uint8 FOOD_R = 255, FOOD_G = 80, FOOD_B = 80;
// 蛇头 翠绿色
constexpr Uint8 HEAD_R = 0, HEAD_G = 200, HEAD_B = 100;
// 蛇身 暗绿色
constexpr Uint8 BODY_R = 0, BODY_G = 150, BODY_B = 60;
// 蛇身 中毒效果
constexpr Uint8 POISON_R = 160, POISON_G = 0, POISON_B = 200;
}
// 在老式的 C/C++ 代码中,定义枚举用 enum
// 现代写法(强类型枚举), 使用 enum class 防止命名污染, 使用时需要加前缀:Direction::UP
enum class Direction
{
UP,DOWN,LEFT,RIGHT
};
// 游戏状态枚举
enum class GameState {
PLAYING,
PAUSED,
GAME_OVER
};
struct Point
{
int x;
int y;
};
// 粒子结构体,用于吃食物特效
struct Particle {
float x, y; // 坐标
float vx, vy; // 速度
int life; // 生命周期
};
// 蛇
class Snake
{
public:
std::deque<Point> body;
Direction dir;
Snake() : dir(Direction::RIGHT) { Reset(); }
void Reset() {
body.clear();
dir = Direction::RIGHT;
// 初始位置 居中
int startX = Width / 2;
int startY = Height / 2;
body.push_back({startX, startY}); // 蛇头
body.push_back({startX - 1, startY});
body.push_back({startX - 2, startY});
}
// 获取蛇头
Point Head() const { return body.front(); }
void Move(bool grow) {
Point next = Head(); // 获取头部
// 计算下一步
switch (dir) {
case Direction::UP: next.y--; break;
case Direction::DOWN: next.y++; break;
case Direction::LEFT: next.x--; break;
case Direction::RIGHT: next.x++; break;
}
// 蛇头移动
body.push_front(next);
// 没吃到食物:删尾巴,保持长度
if(!grow) {
body.pop_back();
}
}
// 撞自己检测
bool CollidesSelf() const {
for(size_t i = 1; i < body.size(); i++){
if(body[i].x == body[0].x && body[i].y == body[0].y)
return true;
}
return false;
}
// 撞墙检测
bool CollidesWall() const {
return body[0].x < 0 || body[0].x >= Width ||
body[0].y < 0 || body[0].y >= Height;
}
// 检查某个坐标是否被蛇身占据 ( 食物是否出现在蛇身上 )
bool Occupies(int x, int y) const {
for(const auto& seg : body) {
if(seg.x == x && seg.y == y)
return true;
}
return false;
}
};
// 食物
class FoodManager
{
public:
std::vector<Point> m_normalFoods; // 普通食物
std::vector<Point> m_poisonBlocks; // 毒方块
Uint32 m_poisonSpawnTime = 0; // 毒方块出现时间
bool m_poisonActive = false;
// 2个食物
void FoodInit(const Snake& snake) {
m_normalFoods.clear();
SpawnOne(snake);
SpawnOne(snake);
}
void SpawnOne(const Snake& snake) {
Point food;
do {
food.x = rand() % Width;
food.y = rand() % Height;
} while (snake.Occupies(food.x, food.y) || IsOnAnyFood(food));
m_normalFoods.push_back(food);
}
// 检查蛇头是否吃到某个普通食物,返回索引,-1 表示没吃到
int CheckEat(const Point& head) {
for(size_t i = 0; i < m_normalFoods.size() ; i++) {
if (head.x == m_normalFoods[i].x && head.y == m_normalFoods[i].y) {
return i;
}
}
return -1;
}
void RemoveAndRespawn(int index, const Snake& snake) {
m_normalFoods.erase(m_normalFoods.begin() + index);
// SpawnOne(snake);
if(m_normalFoods.empty()) {
FoodInit(snake);
}
}
// 毒方块逻辑: 每 15-25 秒随机刷新一波
void UpdatePoison(const Snake& snake, Uint32 now) {
if(!m_poisonActive) {
Uint32 interval = 15000 + (rand() %10000);
if(now - m_poisonSpawnTime > interval) {
SpawnPoisonBlocks(snake);
m_poisonSpawnTime = now;
m_poisonActive = true;
}
}
// 15 秒后消失
if(m_poisonActive && now - m_poisonSpawnTime > 15000) {
m_poisonBlocks.clear();
m_poisonActive = false;
m_poisonSpawnTime = now;
}
}
bool IsOnAnyPoison(int x, int y) {
for (auto& p : m_poisonBlocks) {
if (x >= p.x && x < p.x + 2 && y >= p.y && y < p.y + 2)
return true;
}
return false;
}
// 随即生成 大的毒方块 ( )
void SpawnPoisonBlocks(const Snake& snake) {
m_poisonBlocks.clear();
int count = 3 + rand() % 5; // 3-7 个
for (int i = 0; i < count; i++) {
Point p;
bool valid;
do {
valid = true;
p.x = rand() % (Width - 1);
p.y = rand() % (Height - 1);
// 检查 2×2 四个格子:不能和蛇身重叠,不能和其他食物/毒方块重叠
for (int dy = 0; dy < 2 && valid; dy++)
for (int dx = 0; dx < 2 && valid; dx++)
if (snake.Occupies(p.x + dx, p.y + dy) ||
IsOnAnyFood({p.x + dx, p.y + dy}) ||
IsOnAnyPoison(p.x + dx, p.y + dy))
valid = false;
} while (!valid);
m_poisonBlocks.push_back(p);
}
}
// 检查是否碰到毒方块
int CheckPoison(const Point& head) {
for (size_t i = 0; i < m_poisonBlocks.size(); i++) {
Point& p = m_poisonBlocks[i];
if (head.x >= p.x && head.x < p.x + 2 &&
head.y >= p.y && head.y < p.y + 2) {
return i;
}
}
return -1;
}
void RemovePoison(int index) {
m_poisonBlocks.erase(m_poisonBlocks.begin() + index);
}
private:
bool IsOnAnyFood(const Point& p) {
for(auto& food : m_normalFoods) {
if (food.x == p.x && food.y == p.y) {
return true;
}
}
for(auto& food : m_poisonBlocks) {
if (food.x == p.x && food.y == p.y) {
return true;
}
}
return false;
}
};
// 渲染
class Renderer
{
private:
SDL_Window* m_Win;
SDL_Renderer* m_Ren;
std::vector<Particle> m_Particles; // 粒子容器
public:
Renderer() {
// 初始化 SDL2 视频子系统
if (SDL_Init(SDL_INIT_VIDEO) < 0) {
fprintf(stderr,"SDL Init Error\n");
exit(1); // 初始化失败直接退出
}
// 创建一个窗口 ( 画框 )
m_Win = SDL_CreateWindow(
"Snake SDL2", // 窗口标题
SDL_WINDOWPOS_CENTERED, // 窗口 x 坐标: 居中 (自动计算)
SDL_WINDOWPOS_CENTERED, // 窗口 y 坐标: 居中
WIN_W, WIN_H, // 窗口宽度,窗口高度
SDL_WINDOW_SHOWN // 窗口状态标志: 显示窗口
);
if (!m_Win) {
fprintf(stderr,"SDL_CreateWindow Error\n");
exit(1);
}
// 创建渲染器, 渲染器是绑定在窗口上的"画笔",所有的绘图命令都通过它执行
// -1: 让 SDL 自动选择当前平台支持的渲染驱动
// SDL_RENDERER_ACCELERATED:使用硬件加速(显卡渲染),比软件渲染快得多
// SDL_RENDERER_PRESENTVSYNC:垂直同步(防止画面撕裂,限制帧率与屏幕刷新率一致)
m_Ren = SDL_CreateRenderer(m_Win,-1,
SDL_RENDERER_ACCELERATED | SDL_RENDERER_PRESENTVSYNC);
if(!m_Ren) {
fprintf(stderr,"SDL_CreateRenderer Error");
SDL_DestroyWindow(m_Win); // 清理已创建的窗口
exit(1);
}
}
~Renderer() {
SDL_DestroyRenderer(m_Ren); // 销毁画笔
SDL_DestroyWindow(m_Win);
SDL_Quit();
}
// 清全屏
void Clear() {
// 设置画笔颜色
SDL_SetRenderDrawColor(m_Ren, Color::BG_R, Color::BG_G, Color::BG_B, 255);
SDL_RenderClear(m_Ren);
}
void DrawGrid() {
SDL_SetRenderDrawColor(m_Ren, 30, 30, 30, 255); // 比背景稍亮
// 竖线
for (int x = 0; x <= Width; x++) {
SDL_RenderDrawLine(m_Ren, x * CELL, 0, x * CELL, WIN_H);
}
// 横线
for (int y = 0; y <= Height; y++) {
SDL_RenderDrawLine(m_Ren, 0, y * CELL, WIN_W, y * CELL);
}
}
void DrawBorder() {
SDL_SetRenderDrawColor(m_Ren, Color::BORDER_R, Color::BORDER_G, Color::BORDER_B, 255);
SDL_Rect r = {0, 0, WIN_W, WIN_H};
SDL_RenderDrawRect(m_Ren, &r); // 画空心矩形
}
// 食物 加脉冲动态效果, tick 程序启动后的毫秒数
void DrawFood(int x, int y, Uint32 tick) {
SDL_SetRenderDrawColor(m_Ren, Color::FOOD_R, Color::FOOD_G, Color::FOOD_B, 255);
int pulse = 3 * sin(tick * 0.01); // 大小波动 ±3 像素
int size = CELL - 4 + pulse; // CELL=20 → 16 + pulse → 13~19 像素
int offset = (CELL - size) / 2; // 居中偏移
SDL_Rect r = {x * CELL + offset, y * CELL + offset, size, size};
SDL_RenderFillRect(m_Ren, &r); // 画实心矩形
}
void DrawNormalFoods(FoodManager& food ) {
for(auto& f : food.m_normalFoods) {
DrawFood(f.x, f.y , SDL_GetTicks());
}
}
// 画 大的毒方块(紫色)
void DrawPoison(FoodManager& poison) {
for (auto& p : poison.m_poisonBlocks) {
SDL_SetRenderDrawColor(m_Ren, Color::POISON_R, Color::POISON_G, Color::POISON_B,255);
SDL_Rect r = {p.x * CELL, p.y * CELL, CELL*2 - 1, CELL*2 - 1};
SDL_RenderFillRect(m_Ren, &r);
}
}
void DrawSnake(const std::deque<Point>& body , Direction snakeDir, bool poisoned) {
for (size_t i = 0; i < body.size(); i++) {
int x = body[i].x * CELL;
int y = body[i].y * CELL;
if (i == 0) {
// 蛇头
SDL_SetRenderDrawColor(m_Ren, Color::HEAD_R, Color::HEAD_G, Color::HEAD_B, 255);
} else {
// 蛇身
if(poisoned)
SDL_SetRenderDrawColor(m_Ren, Color::POISON_R, Color::POISON_G, Color::POISON_B,255);
else
SDL_SetRenderDrawColor(m_Ren, Color::BODY_R, Color::BODY_G, Color::BODY_B, 255);
}
SDL_Rect r = {x, y, CELL - 1, CELL - 1};
SDL_RenderFillRect(m_Ren, &r); // 画实心矩形
// 画蛇头眼睛 (i == 0) , 根据 m_Snake.dir 来判断眼睛位置
if (i == 0) {
SDL_SetRenderDrawColor(m_Ren, 255, 255, 255, 255); // 白眼
const int eyeSize = 3; // 眼睛大小
const int margin = 4; // 眼睛距离边缘的距离
SDL_Rect eye1, eye2;
switch (snakeDir) {
case Direction::UP:
// 向上:眼睛在顶部的左右两边
eye1 = {x + margin, y + margin, eyeSize, eyeSize}; // 左眼
eye2 = {x + CELL - margin - eyeSize, y + margin, eyeSize, eyeSize}; // 右眼
break;
case Direction::DOWN:
// 向下:眼睛在底部的左右两边
eye1 = {x + margin, y + CELL - margin - eyeSize, eyeSize, eyeSize};
eye2 = {x + CELL - margin - eyeSize, y + CELL - margin - eyeSize, eyeSize, eyeSize};
break;
case Direction::LEFT:
// 向左:眼睛在左侧的上下两边
eye1 = {x + margin, y + margin, eyeSize, eyeSize}; // 上眼
eye2 = {x + margin, y + CELL - margin - eyeSize, eyeSize, eyeSize}; // 下眼
break;
case Direction::RIGHT:
// 向右:眼睛在右侧的上下两边
eye1 = {x + CELL - margin - eyeSize, y + margin, eyeSize, eyeSize};
eye2 = {x + CELL - margin - eyeSize, y + CELL - margin - eyeSize, eyeSize, eyeSize};
break;
}
SDL_RenderFillRect(m_Ren, &eye1);
SDL_RenderFillRect(m_Ren, &eye2);
}
}
}
// 添加粒子特效
void AddParticles(int x, int y, int count) {
for (int i = 0; i < count; i++) {
Particle p;
p.x = x * CELL + CELL / 2;
p.y = y * CELL + CELL / 2;
// 随机速度 (-3 到 3)
p.vx = (rand() % 60 - 30) / 10.0f;
p.vy = (rand() % 60 - 30) / 10.0f;
p.life = 30 + rand() % 20; // 存活时间
m_Particles.push_back(p);
}
}
// 更新并绘制粒子
void UpdateParticles() {
// 更新所有粒子
for (auto& p : m_Particles) {
p.x += p.vx;
p.y += p.vy;
p.life--;
}
// 移除死亡的
m_Particles.erase(
std::remove_if(m_Particles.begin(), m_Particles.end(),
[](const Particle& p) { return p.life <= 0; }),
m_Particles.end()
);
// 绘制存活粒子
SDL_SetRenderDrawColor(m_Ren, 255, 255, 100, 255); // 金色粒子
for (auto& p : m_Particles) {
SDL_Rect r = {(int)p.x, (int)p.y, 4, 4};
SDL_RenderFillRect(m_Ren, &r);
}
}
void DrawDigit(int x, int y, int digit, int scale) {
SDL_SetRenderDrawColor(m_Ren, 255, 255, 255, 255);
for (int row = 0; row < 8; row++)
for (int col = 0; col < 5; col++)
if (DIGIT[digit][row][col]) {
SDL_Rect r = {x + col*scale, y + row*scale, scale, scale};
SDL_RenderFillRect(m_Ren, &r);
}
}
void DrawScore(int x, int y, int num, int scale) {
char buf[16];
snprintf(buf, sizeof(buf), "%d", num);
for (int i = 0; buf[i]; i++)
DrawDigit(x + i*6*scale, y, buf[i]-'0', scale);
}
void Present() {
// 把画好的内容, 呈现到屏幕上
SDL_RenderPresent(m_Ren);
}
};
// 游戏
class Game
{
Snake m_Snake;
FoodManager m_Food;
Renderer m_Renderer;
int m_Score, m_Level;
Uint32 m_Speed;
Uint32 m_LastTick;
Uint32 m_PoisonTimer; // 中毒时间
bool m_Poisoned ;
bool m_Running;
GameState m_State;
// 本帧暂存的方向, 修复"自杀 Bug" :一帧内连续按两个键,蛇反向撞到自己
Direction m_PendingDir;
public:
Game() : m_Score(0),m_Level(1),m_Speed(200),m_LastTick(0),
m_PoisonTimer(0), m_Poisoned(false), m_Running(true),
m_State(GameState::PLAYING), m_PendingDir(m_Snake.dir)
{
srand(time(0)); // 初始化随机种子
m_Food.FoodInit(m_Snake); // 初始化食物
}
void Run() {
const Uint32 FRAME_TIME = 33; // 30fps
SDL_Event e;
m_LastTick = SDL_GetTicks(); // ms
while(m_Running) {
Uint32 frameStart = SDL_GetTicks();
HandleEvents(e); // 事件处理
if (m_State == GameState::PLAYING) { // 游戏暂停按键
Update();
}
else{
// 非游戏进行中(暂停/死亡),加延迟防止 CPU 空转
SDL_Delay(32);
}
Render(); // 渲染
Uint32 frameTime = SDL_GetTicks() - frameStart;
// 强制至少休息 5ms,防止把系统卡死
if (frameTime < FRAME_TIME) {
SDL_Delay(FRAME_TIME - frameTime);
} else {
// 如果卡顿了,也要让出 CPU 给系统 1ms
SDL_Delay(1);
}
}
}
private:
void HandleEvents(SDL_Event& e) {
// SDL_PollEvent 会从事件队列里取出事件(如键盘按下、鼠标移动、点击关闭按钮)
while(SDL_PollEvent(&e)) {
if (e.type == SDL_QUIT ) {
m_Running = false; // 点击关闭按钮,退出循环
return;
}
if (e.type == SDL_KEYDOWN) {
if(e.key.keysym.sym == SDLK_ESCAPE) {
m_Running = false;
return; // ESC 直接退出循环
}
if(m_State == GameState::PLAYING) {
HandlePlayingInput(e.key.keysym.sym);
}
else if (m_State == GameState::PAUSED) {
HandlePausedInput(e.key.keysym.sym);
}
else if (m_State == GameState::GAME_OVER) {
HandleGameOverInput(e.key.keysym.sym);
}
}
}
}
void HandlePlayingInput(SDL_Keycode key) {
switch (key) {
case SDLK_w: case SDLK_UP:
if (m_Snake.dir != Direction::DOWN)
m_PendingDir = Direction::UP;
break;
case SDLK_s: case SDLK_DOWN:
if (m_Snake.dir != Direction::UP)
m_PendingDir = Direction::DOWN;
break;
case SDLK_a: case SDLK_LEFT:
if (m_Snake.dir != Direction::RIGHT)
m_PendingDir = Direction::LEFT;
break;
case SDLK_d: case SDLK_RIGHT:
if (m_Snake.dir != Direction::LEFT)
m_PendingDir = Direction::RIGHT;
break;
case SDLK_p: m_State = GameState::PAUSED;
break;
}
}
void HandlePausedInput(SDL_Keycode key) {
if (key == SDLK_p) m_State = GameState::PLAYING;
}
void HandleGameOverInput(SDL_Keycode key) {
if (key == SDLK_r) ResetGame();
}
void Update() {
Uint32 now = SDL_GetTicks();
// 中毒时间 6秒
if(m_Poisoned && (now - m_PoisonTimer > 6000)) {
m_Poisoned = false;
UpdateLevel(); // 恢复当前等级速度
}
// 毒方块更新
m_Food.UpdatePoison(m_Snake, now);
// 中毒时 用中毒速度,否则用正常速度
Uint32 Speed = 60;
if (m_Level > 9)
Speed = 25;
else if(m_Level > 6)
Speed = 35;
Uint32 currentSpeed = m_Poisoned ? Speed : m_Speed;
if (now - m_LastTick < currentSpeed)
return;
m_LastTick = now;
// 预判下一步位置
m_Snake.dir = m_PendingDir;
Point nextPos = m_Snake.Head();
switch (m_Snake.dir) {
case Direction::UP: nextPos.y--; break;
case Direction::DOWN: nextPos.y++; break;
case Direction::LEFT: nextPos.x--; break;
case Direction::RIGHT: nextPos.x++; break;
}
int poisonIndex = m_Food.CheckPoison(nextPos);
if(poisonIndex >= 0 ) {
m_Poisoned = true;
m_PoisonTimer = now;
m_Food.RemovePoison(poisonIndex);
}
// 检测吃到哪个食物
int ateIndex = m_Food.CheckEat(nextPos);
bool ate = (ateIndex >= 0);
// 蛇吃到食物时 尾巴不删除 身体增长, 没吃到食物时 尾巴删除 移动
m_Snake.Move(ate);
// 碰撞墙壁检测,碰撞自身检测
if (m_Snake.CollidesWall() || m_Snake.CollidesSelf()) {
m_State = GameState::GAME_OVER;
return;
}
// 如果吃到食物,更新分数和食物位置
if(ate) {
m_Score ++;
// 粒子特效在被吃食物的位置
Point foodPos = m_Food.m_normalFoods[ateIndex];
// 生成粒子特效
m_Renderer.AddParticles(foodPos.x, foodPos.y, 20);
// 更新食物
m_Food.RemoveAndRespawn(ateIndex, m_Snake);
// 升级逻辑
UpdateLevel();
}
}
/*
绘制流程:三步走
1. Clear(清空画布):用背景色覆盖掉上一帧的内容。
2. Draw(绘制内容):画矩形、画线、画贴图。
3. Present(呈现):这一步最关键
*/
void Render() {
m_Renderer.Clear();
// m_Renderer.DrawGrid(); // 无硬件GPU,网格会增加 cpu 占用率
m_Renderer.DrawBorder();
m_Renderer.DrawNormalFoods(m_Food);
m_Renderer.DrawPoison(m_Food);
m_Renderer.DrawSnake(m_Snake.body, m_Snake.dir,m_Poisoned);
m_Renderer.UpdateParticles();
m_Renderer.DrawScore(385, 405, m_Score, 2);
m_Renderer.Present();
}
void ResetGame() {
m_Snake.Reset();
m_PendingDir = m_Snake.dir;
m_Food.FoodInit(m_Snake);
m_Score = 0;
m_Level = 1;
m_Speed = 200;
m_State = GameState::PLAYING;
m_LastTick = SDL_GetTicks();
}
void UpdateLevel() {
m_Level = m_Score / 5 + 1;
if (m_Level > 12) m_Level = 12;
m_Speed = 200 - (m_Level - 1) * 15; // 1级200ms → 12级35ms
}
};
int main()
{
Game game;
game.Run();
return 0;
}
数字点阵 DigitFont.h 文件代码:
#pragma once
// 5×8 点阵数字 0-9
static constexpr bool DIGIT[10][8][5] = {
// 0
{{0,1,1,1,0},{1,0,0,0,1},{1,0,0,0,1},{1,0,0,0,1},
{1,0,0,0,1},{1,0,0,0,1},{1,0,0,0,1},{0,1,1,1,0}},
// 1
{{0,0,1,0,0},{0,1,1,0,0},{0,0,1,0,0},{0,0,1,0,0},
{0,0,1,0,0},{0,0,1,0,0},{0,0,1,0,0},{0,1,1,1,0}},
// 2
{{0,1,1,1,0},{1,0,0,0,1},{0,0,0,0,1},{0,0,0,1,0},
{0,0,1,0,0},{0,1,0,0,0},{1,0,0,0,0},{1,1,1,1,1}},
// 3
{{1,1,1,1,0},{0,0,0,0,1},{0,0,0,0,1},{0,0,1,1,0},
{0,0,0,0,1},{0,0,0,0,1},{0,0,0,0,1},{1,1,1,1,0}},
// 4
{{1,0,0,0,1},{1,0,0,0,1},{1,0,0,0,1},{0,1,1,1,1},
{0,0,0,0,1},{0,0,0,0,1},{0,0,0,0,1},{0,0,0,0,1}},
// 5
{{1,1,1,1,1},{1,0,0,0,0},{1,0,0,0,0},{1,1,1,1,0},
{0,0,0,0,1},{0,0,0,0,1},{0,0,0,0,1},{1,1,1,1,0}},
// 6
{{0,1,1,1,0},{1,0,0,0,0},{1,0,0,0,0},{1,1,1,1,0},
{1,0,0,0,1},{1,0,0,0,1},{1,0,0,0,1},{0,1,1,1,0}},
// 7
{{1,1,1,1,1},{0,0,0,0,1},{0,0,0,1,0},{0,0,1,0,0},
{0,1,0,0,0},{0,1,0,0,0},{0,1,0,0,0},{0,1,0,0,0}},
// 8
{{0,1,1,1,0},{1,0,0,0,1},{1,0,0,0,1},{0,1,1,1,0},
{1,0,0,0,1},{1,0,0,0,1},{1,0,0,0,1},{0,1,1,1,0}},
// 9
{{0,1,1,1,0},{1,0,0,0,1},{1,0,0,0,1},{0,1,1,1,1},
{0,0,0,0,1},{0,0,0,0,1},{0,0,0,0,1},{0,1,1,1,0}}
};
在开发板直接编译 源码:
g++ -std=c++11 SnakeGame.cpp -o SnakeGame -lSDL2
g++ -std=c++11 -O2 SnakeGame.cpp -o SnakeGame -lSDL2 ( -O2 优化 )
在开发板的屏幕,运行游戏:
xinit ./SnakeGame -- /usr/bin/X :0