手搓 Ai-M61 肉鸽游戏:三选一卡牌_m61_32s #39
robot-cn
started this conversation in
Show and tell(技术分享)
Replies: 1 comment
|
nice~ |
0 replies
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Uh oh!
There was an error while loading. Please reload this page.
手搓 M61 肉鸽游戏:三选一卡牌 + 图形化 UI,满屏伤害数字
一、效果
![实战画面:Day 1 草地场景,Lv2、HP/EXP 条、伤害数字飘字]
一句话玩法:类"吸血鬼幸存者"自动攻击,攒经验升级弹三选一卡牌,撑过 7 天(现实 11 分钟)算胜利。游戏内按 GPIO24 确认键呼出属性面板(Level/HP/Weapon/Crit/DPS),同时世界暂停,再按一次恢复。
二、硬件清单
软件:bouffalo_sdk(官方 SDK,含 RISC-V GCC 工具链 + BL616 全套驱动)。
三、接线(照抄即可)
3.1 屏幕(ST7789,SPI0)
3.2 按键(5 个,active-low)
按键一端接 GPIO,另一端统一接 GND。按下读 0(LOW),松开被芯片内部上拉读 1(HIGH)。
四、博流 SDK 上的工程亮点
4.1 在博流 SDK 上从零打通 C++ 工具链
SDK 启用 CXX 后能直接拉
riscv64-unknown-elf-g++,但有几个"没有文档提"的坑需要自己补:CMakeLists.txt必须project(dappfife3)触发 SDK 的_project(... C CXX)宏,自动把 g++ 工具链链入;默认-std=c++11 -fno-rtti -fno-exceptions -nostdlib;start.S不调__libc_init_array(),所以 C++ 写的全局对象(TFT_eSprite screenBuffer;、全局tft;等)如果不手动构造,就是野指针。在main.c的board_init()后必须显式extern void __libc_init_array(void); __libc_init_array();,并补一个__dso_handle.c定义void *__dso_handle = 0;,否则链接期直接报undefined reference;Arduino.h的min/max/abs不能是宏(会破坏<vector>/<limits>/<cmath>的std::numeric_limits<>::min()等),改写为 C++ 模板;random重载不能放进extern "C"块(newlib 已有long random(void)会冲突);String operator+自由函数需要friend声明访问私有_append;st7789.h的 C 函数声明加extern "C"包裹,否则 C++ 端st7789_init会被 name-mangling,与 C 编译的st7789.c符号名对不上 → 链接期undefined reference。4.2 SPI + DMA 异步双缓冲送帧(关键性能优化)
游戏画面 = 240×240 RGB565 软件帧缓冲(malloc 115200 字节在堆上),全部图元在内存里画完再一次性推给屏幕。这里的"一次性推送"用到了博流 SDK 的 SPI0 + DMA 双缓冲:
st7789_draw_picture_dma()内部维护两片 buffer:bflb_dma启动 DMA、函数立即返回;ST7789_SPI_FREQ),整帧 115200 字节理论传输 5.75ms,实测比 80MHz 明显更稳(轮询开销被 DMA 吃掉)。FRAME_INTERVAL_MS = 10,串口看 FPS 稳定在 60+:DMA 送帧是这块设计的关键——没有 DMA 时一帧
2030ms,且主循环被 SPI 阻塞;上 DMA 后 CPU 与 SPI 平行,整帧延迟接近纯渲染时间。4.3 输入层 0 个 ADC / 0 个 PWM
原游戏是"模拟摇杆 + 1 按钮",但 BL616 ADC 通道被屏幕占了、且游戏玩法对 ADC 精度要求不高,直接砍掉:
bflb_gpio_init(key_gpio, pin, GPIO_INPUT | GPIO_PULLUP | GPIO_SMT_EN | GPIO_DRV_1)配成上拉输入;digitalRead()内部 lazy init:第一次调用才把 5 个脚一起配成输入(避免在 setup 阶段多耗一个外设依赖);readJoystickX/Y把方向键映射回摇杆语义,game/Utils.cpp的核心输入 API 零改动——这也是上一条 C++ 兼容层真正发挥作用的地方。4.4 代码分区与资源占用
-O3,Flash 占用约 5%shim 层的可复用性:把
shim/整个目录视为"Arduino on BL616"的移植层。以后再移植别的 TFT_eSPI / Arduino 小游戏,只需在game/替换业务 .cpp/.h,shim/与st7789.c不用动。4.5 博流 SDK 特性一览
board_init()bflb_mtimer_get_time_ms/us()millis()/micros()(64-bit cycle counter 高精度)bflb_gpio_init / bflb_gpio_readpinMode/digitalRead(无 ADC/PWM)bflb_spi + bflb_dmaCMake + project(dappfife3)printf+ 串口[FPS]诊断输出)五、编译 + 烧录(Windows)
工程目录开一个 cmd 窗口:
产物在
build/build_out/dappfife3_bl616.bin(约 226KB)。烧录后打开串口监视器(115200),固件每 5 秒打印一条真实帧率日志:
六、想改哪里?
6.1 换按键 —— 改两处,必须同步
①
game/Config.h的按键宏:②
shim/Arduino.cpp的初始化数组(顺序 = 上/下/左/右/确认):6.2 换屏幕引脚 ——
st7789.h顶部换分辨率或接非居中屏幕时,找
shim/TFT_eSPI.cpp的pushSprite(),里面(ST7789_WIDTH - _w) / 2就是水平居中偏移。七、小结
__libc_init_array/__dso_handle/ 头文件extern "C"),用 SPI0 + DMA 双缓冲实现非阻塞送帧,把整帧 ~30ms 的瓶颈压到 ~15ms;shim / game / 驱动三层切分,shim/整个目录是"Arduino on BL616"兼容层,下次移植别的 TFT_eSPI 项目可以直接复用。想要更多玩法(手动重击、真·暂停菜单、音效),评论区见,代码改动都集中在
app.cpp的状态机里,随时可以加。八、下载
游戏帖子源码.zip
All reactions