SpriteBatch 将同一纹理的多个精灵合并为一次 Draw Call,大幅减少渲染状态切换,是 2D 游戏性能的关键。
逐个调用 xgeDraw 绘制精灵会产生大量 Draw Call。SpriteBatch 将使用同一纹理的 精灵顶点累积到动态 VBO 中,一次 Flush 完成所有绘制。 典型场景:Tilemap、粒子系统、UI 精灵。
| 函数 | 说明 |
|---|---|
int xgeSpriteBatchInit(xge_sprite_batch pBatch, xge_texture pTexture, int iCapacity, uint32_t iFlags) | 初始化批处理器 |
void xgeSpriteBatchFree(xge_sprite_batch pBatch) | 释放 |
void xgeSpriteBatchClear(xge_sprite_batch pBatch) | 清空累积 |
int xgeSpriteBatchAdd(xge_sprite_batch pBatch, const xge_draw_t* pDraw) | 添加精灵 |
int xgeSpriteBatchFlush(xge_sprite_batch pBatch) | 提交绘制 |
gcc -O2 -I. -o ch105.exe ch105_main.c build\xge.lib -lm -lws2_32 -liphlpapi -lgdi32 -luser32 -lshell32 -lopengl32 -lole32 -lwinmm -lavrt
.\ch105.exe
// 初始化(容量 1024 个精灵)
xge_sprite_batch_t batch;
xgeSpriteBatchInit(&batch, &tilesetTex,
1024, 0);
// 每帧:添加所有可见 Tile
xgeSpriteBatchClear(&batch);
for (int y = 0; y < mapH; y++) {
for (int x = 0; x < mapW; x++) {
xge_draw_t draw = { 0 };
draw.tSrc = (xge_rect_t){
tileId * 32, 0, 32, 32 };
draw.tDst = (xge_rect_t){
x * 32, y * 32, 32, 32 };
xgeSpriteBatchAdd(&batch, &draw);
}
}
// 一次提交(1 个 Draw Call)
xgeSpriteBatchFlush(&batch);
// 退出时释放
xgeSpriteBatchFree(&batch);将以下代码保存为 ch105_main.c,编译后运行即可看到 SpriteBatch Tilemap 批量绘制效果:
#include "xge.h"
#include <string.h>
#define MAP_W 25
#define MAP_H 18
#define TILE 32
static xge_sprite_batch_t g_batch;
static xge_texture_t g_tileset;
static xge_font g_font = NULL;
static int g_hasTex = 0;
static int onFrame(void* pUser) {
(void)pUser;
xgeClear(0x081114FF);
// 每帧清空并添加所有 Tile
xgeSpriteBatchClear(&g_batch);
for (int y = 0; y < MAP_H; y++)
for (int x = 0; x < MAP_W; x++) {
int tileId = (x + y) % 4;
xge_draw_t draw = { 0 };
draw.tSrc = (xge_rect_t){
tileId * TILE, 0, TILE, TILE };
draw.tDst = (xge_rect_t){
x * TILE, y * TILE, TILE, TILE };
xgeSpriteBatchAdd(&g_batch, &draw);
}
// 一次提交(1 个 Draw Call)
xgeSpriteBatchFlush(&g_batch);
xgeTextDraw(g_font, "SpriteBatch: 450 tiles, 1 draw call",
10.0f, 580.0f, 0xFFFFFFFF)
return XGE_OK;
}
int main(void) {
xge_desc_t d = {0};
d.iWidth = 800;
d.iHeight = 600;
d.sTitle = "ch105 - SpriteBatch Tilemap";
d.iFlags = XGE_INIT_VSYNC;
xgeInit(&d);
xgeFontLoad(&g_font, "Roboto.ttf", 16.0f);
// 创建 tileset 纹理(程序生成 4 种色块)
uint8_t px[128 * 32 * 4];
memset(px, 0, sizeof(px));
uint8_t colors[4][3] = {
{200,60,60}, {60,200,60},
{60,60,200}, {200,200,60}
};
for (int t = 0; t < 4; t++)
for (int y = 0; y < 32; y++)
for (int x = 0; x < 32; x++) {
int i = (y * 128 + t*32 + x) * 4;
px[i] = colors[t][0];
px[i+1] = colors[t][1];
px[i+2] = colors[t][2];
px[i+3] = 255;
}
xgeTextureCreateRGBA(&g_tileset, 128, 32, px);
g_hasTex = 1;
// 初始化批处理器
xgeSpriteBatchInit(&g_batch, &g_tileset,
1024, 0);
xgeRun(onFrame, NULL);
xgeSpriteBatchFree(&g_batch);
if (g_hasTex) xgeTextureFree(&g_tileset);
xgeFontFree(g_font);
xgeUnit();
return 0;
}