Sprite (离屏画布)
类: LGFX_Sprite / M5Canvas(来自 M5GFX)
头文件: M5GFX.h(自动包含 LGFX_Sprite)
Sprite 是一个离屏绘图缓冲区。你可以使用与 M5Cardputer.Display 相同的 API 向其中绘制内容,然后一次性将其传送到屏幕上。这可以实现双缓冲渲染,消除闪烁,打造流畅 UI。
M5Canvas 是 LGFX_Sprite 的便捷子类,默认使用 PSRAM 分配。
M5Canvas vs LGFX_Sprite
大多数情况下用 M5Canvas。仅在需要通过 setPsram() 显式控制 PSRAM 时才用 LGFX_Sprite。
生命周期
M5Canvas sprite(&M5Cardputer.Display);
sprite.setColorDepth(16); // 必须在 createSprite 之前调用
sprite.createSprite(320, 240);
// ... 在 sprite 上绘图 ...
sprite.deleteSprite(); // 完成后清理
缓冲区管理
void setPsram(bool enabled); // 下次 createSprite 时使用 PSRAM
void* setColorDepth(color_depth_t depth); // 更改色深(会重建缓冲区)
void setBuffer(void* buffer, int32_t w, int32_t h, uint8_t bpp = 0); // 封装外部内存
void* getBuffer(); // 原始缓冲区指针
uint32_t bufferLength(); // 缓冲区大小(字节)
色深选项: 1, 4, 8, 16, 24, 32(每像素位数)。M5Cardputer 推荐 16。
Warning
setColorDepth() 和 setPsram() 必须在 createSprite() 之前调用。创建后更改色深会销毁并重建缓冲区。
传送到显示
void pushSprite(int32_t x, int32_t y); // 传送到父显示
void pushSprite(LovyanGFX* dst, int32_t x, int32_t y); // 传送到任意显示
void pushSprite(int32_t x, int32_t y, uint16_t transparent); // 带透明色
sprite.pushSprite(0, 0); // 完整画面传送到父显示 (0,0)
sprite.pushSprite(&M5Cardputer.Display, 10, 20); // 传送到 (10,20)
sprite.pushSprite(0, 0, TFT_BLACK); // TFT_BLACK 像素为透明
旋转/缩放传送
void pushRotated(float angle); // 旋转传送
void pushRotated(float angle, uint16_t transparent); // 带透明
void pushRotateZoom(float angle, float zoom_x, float zoom_y); // 旋转 + 缩放
void pushAffine(const float matrix[6]); // 仿射变换
继承的绘图方法
LGFX_Sprite 继承了 LGFXBase 的所有绘图方法,因此 显示屏 (M5GFX) 中的所有方法在 Sprite 上同样适用:
sprite.fillScreen(TFT_BLACK);
sprite.fillRect(10, 10, 100, 50, TFT_RED);
sprite.drawCircle(160, 120, 60, TFT_GREEN);
sprite.drawString("你好", 10, 10);
双缓冲渲染
M5Canvas backBuffer(&M5Cardputer.Display);
void setup() {
M5Cardputer.begin();
backBuffer.setColorDepth(16);
backBuffer.createSprite(320, 240);
}
void loop() {
M5Cardputer.update();
// 在后台缓冲区绘制所有内容
backBuffer.fillScreen(TFT_BLACK);
backBuffer.drawString("FPS 计数器", 10, 10);
// ... 更多绘图 ...
// 一次性传送 — 无闪烁
backBuffer.pushSprite(0, 0);
}
低色深精灵与调色板
内存紧张时,可使用 8 位(或更低)色深配合调色板:
M5Canvas sprite(&M5Cardputer.Display);
sprite.setColorDepth(8);
sprite.createSprite(320, 240);
sprite.createPalette();
sprite.setPaletteColor(0, TFT_BLACK);
sprite.setPaletteColor(1, TFT_WHITE);
sprite.setPaletteColor(2, TFT_RED);
sprite.fillScreen(0); // 使用调色板索引 0
sprite.drawString("Hi", 10, 10); // 文字颜色使用调色板
sprite.pushSprite(0, 0);
从 BMP 加载精灵
bool createFromBmpFile(const char* path); // 从 SD 卡加载
bool createFromBmp(const uint8_t* data, uint32_t len); // 从内存加载
这将用 BMP 内容替换精灵缓冲区(无需先调用 createSprite)。
快速示例:简单游戏循环
M5Canvas canvas(&M5Cardputer.Display);
void setup() {
M5Cardputer.begin();
canvas.setColorDepth(16);
canvas.createSprite(320, 240);
}
int x = 100, y = 100;
void loop() {
M5Cardputer.update();
// 清空后台缓冲区
canvas.fillScreen(TFT_BLACK);
// 移动玩家
auto& keys = M5Cardputer.Keyboard.keysState();
if (M5Cardputer.Keyboard.isKeyPressed('w')) y--;
if (M5Cardputer.Keyboard.isKeyPressed('s')) y++;
if (M5Cardputer.Keyboard.isKeyPressed('a')) x--;
if (M5Cardputer.Keyboard.isKeyPressed('d')) x++;
// 绘制游戏对象
canvas.fillRect(x, y, 16, 16, TFT_GREEN);
// 翻转到屏幕
canvas.pushSprite(0, 0);
}
void cleanup() {
canvas.deleteSprite();
}