在src/scrcmd.c 文件末尾添加 ShowCG 相关的函数和数据结构。
#define PLAY_CG (0)
#define PLAY_MESSAGE (1)
#define WAIT_BUTTON (2)
#define PLAY_FADE (3)
#define PLAY_END (4)
#define PAUSE_TIME (5)
static const struct BgTemplate sBgTemplates[] =
{
{
.bg = 0,
.charBaseIndex = 3,
.mapBaseIndex = 31,
.screenSize = 0,
.paletteMode = 0,
.priority = 0,
.baseTile = 0
},
{
.bg = 2,
.charBaseIndex = 0,
.mapBaseIndex = 29,
.screenSize = 0,
.paletteMode = 1,
.priority = 3,
.baseTile = 0
},
};
static const struct WindowTemplate sWindowTemplates[] =
{
{
.bg = 0,
.tilemapLeft = 3,
.tilemapTop = 15,
.width = 24,
.height = 4,
.paletteNum = 15,
.baseBlock = 0x010
},
DUMMY_WIN_TEMPLATE,
};
//tilemap单独提供下载,放在对应文件夹即可
//添加CG图
static const u8 sDefaultCG_TileMap[] = INCBIN_U8("graphics/cg/raw.bin.lz");
static const u8 sCGA1_Tiles[] = INCBIN_U8("graphics/cg/CG1.8bpp.lz");
static const u8 sCGA1_Pal[] = INCBIN_U8("graphics/cg/CG1.gbapal");
static const u8 sCGA2_Tiles[] = INCBIN_U8("graphics/cg/CG2.8bpp.lz");
static const u8 sCGA2_Pal[] = INCBIN_U8("graphics/cg/CG2.gbapal");
//CG图编号
static const u8* sCGTable[][10] =
{
[0] = {sCG1_Tiles, sCG1_Pal},
[1] = {sCG2_Tiles, sCG2_Pal},
};
static const u8 sText_Color[] = {0, 1, 2};
//对话表编号
static const u8* sCGMessage[] =
{
[0] = COMPOUND_STRING("?:如果时间能永远\n停留在这个时刻就好了。\p洛汐:是啊。"),
[1] = COMPOUND_STRING("洛汐:你知道启明星吗?\n就是在太阳升起前,\l最后那颗最亮的星星。\p?:当然知道啊。"),
};
//CG表编号
static const u8 sCGAnimList[][60] =
{
[0] = {
PLAY_CG, 0, // 播放CG
PLAY_MESSAGE, 0, // 播放对话
WAIT_BUTTON, 0, // 等待按钮
PLAY_CG, 1, // 播放cg
PLAY_MESSAGE, 1, // 播放对话
WAIT_BUTTON, 0, // 等待按钮
PLAY_END // 结束
},
};
static void VblankCB_ShowCG(void)
{
LoadOam();
ProcessSpriteCopyRequests();
TransferPlttBuffer();
}
static void CB2_ShowCGWait(void)
{
RunTasks();
DoScheduledBgTilemapCopiesToVram();
UpdatePaletteFade();
}
static void CB2_ShowCG(void)
{
SetVBlankCallback(NULL);
SetGpuReg(REG_OFFSET_DISPCNT, 0);
SetGpuReg(REG_OFFSET_BG3CNT, 0);
SetGpuReg(REG_OFFSET_BG2CNT, 0);
SetGpuReg(REG_OFFSET_BG1CNT, 0);
SetGpuReg(REG_OFFSET_BG0CNT, 0);
ChangeBgX(0, 0, BG_COORD_SET);
ChangeBgY(0, 0, BG_COORD_SET);
ChangeBgX(1, 0, BG_COORD_SET);
ChangeBgY(1, 0, BG_COORD_SET);
ChangeBgX(2, 0, BG_COORD_SET);
ChangeBgY(2, 0, BG_COORD_SET);
ChangeBgX(3, 0, BG_COORD_SET);
ChangeBgY(3, 0, BG_COORD_SET);
DmaFill16(3, 0, VRAM, VRAM_SIZE);
DmaFill32(3, 0, OAM, OAM_SIZE);
DmaFill16(3, 0, PLTT, PLTT_SIZE);
u8 cgindex = sCGAnimList[gSpecialVar_0x8004][1];
LZ77UnCompVram((void*)sDefaultCG_TileMap, (void *)(BG_SCREEN_ADDR(29)));
LZ77UnCompVram((void*)sCGTable[cgindex][0], (void *)(BG_CHAR_ADDR(0)));
ResetBgsAndClearDma3BusyFlags(0);
InitBgsFromTemplates(0, sBgTemplates, ARRAY_COUNT(sBgTemplates));
ScanlineEffect_Stop();
ResetTasks();
ResetSpriteData();
ResetPaletteFade();
FreeAllSpritePalettes();
ResetAllPicSprites();
InitWindows(sWindowTemplates);
DeactivateAllTextPrinters();
LoadPalette((void*)sCGTable[cgindex][1], BG_PLTT_ID(0), 15 * 32);
LoadPalette(GetOverworldTextboxPalettePtr(), BG_PLTT_ID(15), PLTT_SIZE_4BPP);
BeginNormalPaletteFade(PALETTES_ALL, 0, 0x10, 0, 0);
EnableInterrupts(DISPSTAT_VBLANK);
SetVBlankCallback(VblankCB_ShowCG);
SetMainCallback2(CB2_ShowCGWait);
u8 taskID = CreateTask(Task_ReadCMD, 0);
gTasks[taskID].data[0] = 2;
SetGpuReg(REG_OFFSET_WININ, WININ_WIN0_BG_ALL | WININ_WIN0_OBJ | WININ_WIN0_CLR);
SetGpuReg(REG_OFFSET_WINOUT, WINOUT_WIN01_BG_ALL | WINOUT_WIN01_OBJ);
SetGpuReg(REG_OFFSET_WIN0H, WIN_RANGE(10, 230));
SetGpuReg(REG_OFFSET_WIN0V, WIN_RANGE(115, 155));
SetGpuReg(REG_OFFSET_DISPCNT, DISPCNT_OBJ_ON | DISPCNT_OBJ_1D_MAP | DISPCNT_WIN0_ON);
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG1 | BLDCNT_TGT1_BG2 | BLDCNT_TGT1_BG3 | BLDCNT_EFFECT_DARKEN);
SetGpuReg(REG_OFFSET_BLDY, 7);
ShowBg(0);
ShowBg(2);
}
static void Task_ChangeCG(u8 taskId)
{
if (!gPaletteFade.active)
{
LZ77UnCompVram((void*)sDefaultCG_TileMap, (void *)(BG_SCREEN_ADDR(29)));
LZ77UnCompVram((void*)sCGTable[gTasks[taskId].data[1]][0], (void *)(BG_CHAR_ADDR(0)));
LoadPalette((void*)sCGTable[gTasks[taskId].data[1]][1], BG_PLTT_ID(0), 15 * 32);
BeginNormalPaletteFade(PALETTES_ALL, 0, 0x10, 0, 0);
gTasks[taskId].func = Task_ReadCMD;
}
}
static void Task_PlayMessage(u8 taskId)
{
if (RunTextPrintersAndIsPrinter0Active())
return;
if (JOY_NEW(A_BUTTON | B_BUTTON))
{
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG1 | BLDCNT_TGT1_BG2 | BLDCNT_TGT1_BG3 | BLDCNT_EFFECT_NONE);
HideBg(0);
FillWindowPixelBuffer(0, PIXEL_FILL(0));
PutWindowTilemap(0);
CopyWindowToVram(0, COPYWIN_FULL);
gTasks[taskId].func = Task_ReadCMD;
}
}
static void Task_WaitFadeAndButton(u8 taskId)
{
if (JOY_NEW(A_BUTTON | B_BUTTON))
{
gTasks[taskId].func = Task_ReadCMD;
}
}
static void Task_ReadCMD(u8 taskId)
{
if (gPaletteFade.active)
return;
u8 animID = sCGAnimList[gSpecialVar_0x8004][gTasks[taskId].data[0]++];
u8 animParam = sCGAnimList[gSpecialVar_0x8004][gTasks[taskId].data[0]++];
if (animID == PLAY_END)
{
DestroyTask(taskId);
SetMainCallback2(CB2_ReturnToFieldContinueScriptPlayMapMusic);
}
else
{
if (animID == PLAY_CG)
{
BeginNormalPaletteFade(PALETTES_ALL, 0, 0, 0x10, 0);
gTasks[taskId].data[1] = animParam;
gTasks[taskId].func = Task_ChangeCG;
}
else if (animID == PAUSE_TIME)
{
gTasks[taskId].func = TaskDummy;
}
else if (animID == WAIT_BUTTON)
{
gTasks[taskId].func = Task_WaitFadeAndButton;
}
else
{
FillWindowPixelBuffer(0, PIXEL_FILL(0));
AddTextPrinterParameterized4(0, FONT_NORMAL, 0, 0, 0, 0, sText_Color, GetPlayerTextSpeedDelay(), sCGMessage[animParam]);
PutWindowTilemap(0);
CopyWindowToVram(0, COPYWIN_FULL);
ScheduleBgCopyTilemapToVram(0);
SetGpuReg(REG_OFFSET_BLDCNT, BLDCNT_TGT1_BG1 | BLDCNT_TGT1_BG2 | BLDCNT_TGT1_BG3 | BLDCNT_EFFECT_DARKEN);
ShowBg(0);
gTasks[taskId].func = Task_PlayMessage;
}
}
}
void ShowCG(void)
{
SetMainCallback2(CB2_ShowCG);
}
在 src/scrcmd.c 文件顶部添加函数声明
static void Task_ReadCMD(u8 taskId);
在 src/scrcmd.c 文件中添加头文件的包含
#include "bg.h"
#include "scanline_effect.h"
#include "trainer_pokemon_sprites.h"
在 data/specials.inc 文件中注册 ShowCG 特殊函数,以便脚本可以调用它。
def_special ShowCG
在graphics文件夹创建cg文件夹,将你的cg图放进去即可
脚本示例:
setvar 0x8004 3 //CG表编号
special ShowCG
waitstate
raw.bin
© 版权声明
文章版权归作者所有,未经允许请勿转载。
THE END
![[GBA教程]实现静态CG图显示-宝可梦营地](https://pokedream.cn/wp-content/uploads/2026/02/QQ20260206-151033.png)

![[GBA教程]pokeemerald新增NPC头像显示,并支持镜像翻转-宝可梦营地](https://pokedream.cn/wp-content/uploads/2026/01/QQ20260114-144714.png)
![[GBA]宝可梦 彼岸花绽放之夜 v1.0正式版-宝可梦营地](https://pokedream.cn/wp-content/uploads/2026/01/1.png)
![[GBA教程]黑幕文字的实现-宝可梦营地](https://pokedream.cn/wp-content/uploads/2026/02/QQ20260205-171045.png)
![[GBA教程]pokeemerald三层地图块详解-宝可梦营地](https://pokedream.cn/wp-content/uploads/2026/01/QQ20260115-154539.png)
![[GBA教程]pokeemerald新增自定义多项选择框-宝可梦营地](https://pokedream.cn/wp-content/uploads/2026/01/1F90AAF66BB1765251BED3AB10ACDD15.png)
![[GBA教程]pokeemerald动态地图块实操记录-宝可梦营地](https://pokedream.cn/wp-content/uploads/2026/01/QQ20260123-171516.png)

![[NDS中文]宝可梦白2加强v1.0.1测试版-宝可梦营地](https://pokedream.cn/wp-content/uploads/2025/12/pokew2.png)

![[NDS]心金魂银自用debug内置修改器-宝可梦营地](https://pokedream.cn/wp-content/uploads/2026/01/game_patched__13041.png)
![[GBA教程]pokeemerald实现动态地图色板功能-宝可梦营地](https://pokedream.cn/wp-content/uploads/2025/12/LittlerootTown.png)
![[记录]GBA反编译上踩过的一些坑-宝可梦营地](https://pokedream.cn/wp-content/uploads/2025/12/water.jpg)
暂无评论内容