[GBA教程]pokeemerald新增NPC头像显示,并支持镜像翻转

头像系统实现

在这个文件夹创建:include\dialogue_portraits.h

#ifndef GUARD_DIALOGUE_PORTRAITS_H
#define GUARD_DIALOGUE_PORTRAITS_H

#include "global.h"

// 头像位置定义
#define PORTRAIT_LEFT_X         2   // 左侧头像位置
#define PORTRAIT_RIGHT_X        21  // 右侧头像位置
#define PORTRAIT_Y              7   // 对话框上方位置

// 头像状态枚举
enum PortraitState {
    PORTRAIT_STATE_NONE = 0,
    PORTRAIT_STATE_SHOWING,
    PORTRAIT_STATE_VISIBLE,
    PORTRAIT_STATE_HIDING
};

// 头像结构体
struct DialoguePortrait {
    u8 spriteId;           // 精灵ID
    u8 state;              // 当前状态
    u8 currentFrame;       // 当前帧
    u8 timer;              // 动画计时器
    u16 paletteTag;        // 调色板标签
    u16 gfxTag;            // 图形标签
};

// 函数声明
void InitDialoguePortraitSystem(void);
void CleanupDialoguePortraitSystem(void);
bool8 ShowDialoguePortrait(u8 portraitId, u8 side, u16 gfxTag, u16 paletteTag);
bool8 ShowDialoguePortraitWithFlip(u8 portraitId, u8 side, u16 gfxTag, u16 paletteTag, bool8 hFlip, bool8 vFlip);
void HideDialoguePortrait(u8 side);
void UpdateDialoguePortraits(void);
bool8 ArePortraitsActive(void);
void SetDialoguePortraitFlip(u8 side, bool8 hFlip, bool8 vFlip);

#endif // GUARD_DIALOGUE_PORTRAITS_H

在这个文件夹创建:src\dialogue_portraits.c

#include "global.h"

include "dialogue_portraits.h"

include "window.h"

include "menu.h"

include "sprite.h"

include "malloc.h"

include "task.h"

include "text_window.h"

include "constants/trainers.h"

include "data.h"

include "decompress.h"

include "constants/songs.h"

include "portrait_data.h"

// 自定义头像ID范围定义

define CUSTOM_PORTRAIT_ID_START 1000

define CUSTOM_PORTRAIT_ID_END 1999

// 头像系统全局变量
static EWRAM_DATA struct DialoguePortrait sPortraits[2] = {0};
static EWRAM_DATA bool8 sPortraitSystemInitialized = FALSE;

// 自定义头像资源声明
extern const u8 gHeadPortrait_001_Gfx[];
extern const u16 gHeadPortrait_001_Pal[];
extern const u8 gHeadPortrait_002_Gfx[];
extern const u16 gHeadPortrait_002_Pal[];

// 加载自定义头像资源
static bool8 LoadCustomPortrait(u16 portraitId, u16 gfxTag, u16 paletteTag)
{

u16 localId = portraitId - CUSTOM_PORTRAIT_ID_START + 1;

// 根据ID加载对应的自定义头像资源
const u8 *gfxData = NULL;
const u16 *palData = NULL;

switch (localId) {
    case 1:
        gfxData = gHeadPortrait_001_Gfx;
        palData = gHeadPortrait_001_Pal;
        break;
    case 2:
        gfxData = gHeadPortrait_002_Gfx;
        palData = gHeadPortrait_002_Pal;
        break;
    default:
        return FALSE;  // 不支持的自定义头像ID
}

if (!gfxData || !palData)
    return FALSE;

// 加载自定义头像图形
struct CompressedSpriteSheet spriteSheet = {
    .data = (const void *)gfxData,
    .size = 0x800,  // 64x64像素,4bpp
    .tag = portraitId + 0x3000  // 使用0x3000系列标签避免与训练师冲突
};
LoadCompressedSpriteSheet(&spriteSheet);

// 加载自定义头像调色板
struct SpritePalette spritePalette = {
    .data = (const void *)palData,
    .tag = portraitId + 0x4000  // 使用0x4000系列标签
};
LoadSpritePalette(&spritePalette);

*gfxTag = portraitId + 0x3000;
*paletteTag = portraitId + 0x4000;

return TRUE;

}

// 初始化头像系统
void InitDialoguePortraitSystem(void)
{

// 如果已经初始化,先清理
if (sPortraitSystemInitialized) {
    CleanupDialoguePortraitSystem();
}

// 初始化头像数据
memset(sPortraits, 0, sizeof(sPortraits));

// 初始化资源标签为无效值
for (int i = 0; i  1)
    return FALSE;

struct DialoguePortrait *portrait = &sPortraits[side];

// 如果已经有头像显示,先隐藏并清理
if (portrait->state != PORTRAIT_STATE_NONE) {
    HideDialoguePortrait(side);
}

// 加载头像图形资源
if (gfxTag >= CUSTOM_PORTRAIT_ID_START && gfxTag gfxTag, &portrait->paletteTag)) {
        return FALSE;
    }
} else if (gfxTag frontPic.data,
        .size = trainerSprite->frontPic.size,
        .tag = gfxTag + 0x1000  // 使用唯一标签避免冲突
    };
    LoadCompressedSpriteSheet(&spriteSheet);

    // 加载调色板数据
    struct SpritePalette spritePalette = {
        .data = trainerSprite->palette.data,
        .tag = gfxTag + 0x2000  // 使用唯一标签避免冲突
    };
    LoadSpritePalette(&spritePalette);

    // 更新标签以便后续使用
    portrait->gfxTag = gfxTag + 0x1000;
    portrait->paletteTag = gfxTag + 0x2000;
} else {
    // 对于无效的ID,直接返回失败
    return FALSE;
}

// 创建精灵来显示头像
struct SpriteTemplate spriteTemplate = {
    .tileTag = portrait->gfxTag,
    .paletteTag = portrait->paletteTag,
    .oam = &(const struct OamData){
        .y = 0,
        .affineMode = ST_OAM_AFFINE_OFF,
        .objMode = ST_OAM_OBJ_NORMAL,
        .bpp = ST_OAM_4BPP,
        .shape = SPRITE_SHAPE(64x64),
        .x = 0,
        .size = SPRITE_SIZE(64x64),
        .tileNum = 0,
        .priority = 1,
        .paletteNum = 0,
    },
    .anims = gDummySpriteAnimTable,
    .images = NULL,
    .affineAnims = gDummySpriteAffineAnimTable,
    .callback = SpriteCallbackDummy
};

// 计算精灵位置
u16 x, y;
if (side == 0) { // 左侧
    x = PORTRAIT_LEFT_X * 8 + 32;  // 窗口中心位置
} else { // 右侧
    x = PORTRAIT_RIGHT_X * 8 + 32;
}
y = PORTRAIT_Y * 8 + 32;

portrait->spriteId = CreateSprite(&spriteTemplate, x, y, 0);
if (portrait->spriteId == MAX_SPRITES) {
    // 创建精灵失败,清理资源
    FreeSpritePaletteByTag(portrait->paletteTag);
    FreeSpriteTilesByTag(portrait->gfxTag);
    portrait->gfxTag = 0xFFFF;
    portrait->paletteTag = 0xFFFF;
    return FALSE;
}

// 设置精灵属性
struct Sprite *sprite = &gSprites[portrait->spriteId];
sprite->oam.priority = 1;  // 在对话框之上
sprite->subpriority = 4;

// 设置状态
portrait->state = PORTRAIT_STATE_SHOWING;
portrait->currentFrame = 0;
portrait->timer = 0;

return TRUE;

}

// 显示头像(带翻转参数)
bool8 ShowDialoguePortraitWithFlip(u8 portraitId, u8 side, u16 gfxTag, u16 paletteTag, bool8 hFlip, bool8 vFlip)
{

if (!ShowDialoguePortrait(portraitId, side, gfxTag, paletteTag))
    return FALSE;

// 设置翻转状态
SetDialoguePortraitFlip(side, hFlip, vFlip);

return TRUE;

}

// 隐藏头像
void HideDialoguePortrait(u8 side)
{

if (!sPortraitSystemInitialized || side > 1)
    return;

struct DialoguePortrait *portrait = &sPortraits[side];

if (portrait->state == PORTRAIT_STATE_NONE)
    return;

// 销毁精灵
if (portrait->spriteId != 0xFF && portrait->spriteId spriteId]);
    portrait->spriteId = 0xFF;
}

// 释放资源
if (portrait->gfxTag != 0xFFFF) {
    FreeSpritePaletteByTag(portrait->paletteTag);
    FreeSpriteTilesByTag(portrait->gfxTag);
}

// 重置所有状态和标签
portrait->state = PORTRAIT_STATE_NONE;
portrait->currentFrame = 0;
portrait->timer = 0;
portrait->gfxTag = 0xFFFF;
portrait->paletteTag = 0xFFFF;

}

// 更新头像
void UpdateDialoguePortraits(void)
{

if (!sPortraitSystemInitialized)
    return;

for (int i = 0; i state) {
        case PORTRAIT_STATE_SHOWING:
            portrait->timer++;
            if (portrait->timer > 10) {  // 显示动画持续10帧
                portrait->state = PORTRAIT_STATE_VISIBLE;
            }
            break;

        case PORTRAIT_STATE_VISIBLE:
            // 可以在这里添加呼吸动画等效果
            portrait->timer++;
            if (portrait->timer > 60) {  // 每秒更新一次
                portrait->timer = 0;
                portrait->currentFrame = (portrait->currentFrame + 1) % 2;
            }
            break;

        case PORTRAIT_STATE_HIDING:
            portrait->timer++;
            if (portrait->timer > 10) {  // 隐藏动画持续10帧
                portrait->state = PORTRAIT_STATE_NONE;
            }
            break;

        default:
            break;
    }
}

}

// 设置头像翻转
void SetDialoguePortraitFlip(u8 side, bool8 hFlip, bool8 vFlip)
{

if (!sPortraitSystemInitialized || side > 1)
    return;

struct DialoguePortrait *portrait = &sPortraits[side];

// 检查是否有有效的精灵
if (portrait->spriteId == 0xFF || portrait->spriteId >= MAX_SPRITES)
    return;

// 检查精灵是否处于活动状态
if (portrait->state == PORTRAIT_STATE_NONE)
    return;

struct Sprite *sprite = &gSprites[portrait->spriteId];

// 设置精灵的翻转属性
sprite->hFlip = hFlip;
sprite->vFlip = vFlip;

// 直接设置OAM翻转位,不使用异或操作
sprite->oam.matrixNum &= 0x7;  // 清除翻转位
if (hFlip)
    sprite-&gt;oam.matrixNum |= (1 oam.matrixNum |= (1 </code></pre><p><strong>在这个文件夹创建:src\portrait_data.c</strong></p><pre class="enlighter-pre"><code class="gl">#include "global.h"

// 自定义头像资源定义
// 这些将由工具链从graphics/head/文件夹中的PNG和PAL文件自动生成

// 头像001 - 玩家头像
const u8 gHeadPortrait_001_Gfx[] = INCBIN_U8("graphics/head/head_001.4bpp.smol");
const u16 gHeadPortrait_001_Pal[] = INCBIN_U16("graphics/head/head_001.gbapal");

// 头像002 - 预留给其他角色
const u8 gHeadPortrait_002_Gfx[] = INCBIN_U8("graphics/head/head_002.4bpp.smol");
const u16 gHeadPortrait_002_Pal[] = INCBIN_U16("graphics/head/head_002.gbapal");

修改这个文件:src\field_message_box.c

#include "global.h"

include "menu.h"

include "string_util.h"

include "task.h"

include "text.h"

include "match_call.h"

include "field_message_box.h"

include "text_window.h"

include "script.h"

include "dialogue_portraits.h" //新增代码

void InitFieldMessageBox(void)

{

sFieldMessageBoxMode = FIELD_MESSAGE_BOX_HIDDEN;
gTextFlags.canABSpeedUpPrint = FALSE;
gTextFlags.useAlternateDownArrow = FALSE;
gTextFlags.autoScroll = FALSE;
gTextFlags.forceMidTextSpeed = FALSE;
InitDialoguePortraitSystem();   //新增代码

}

#define tState data[0]

static void Task_DrawFieldMessage(u8 taskId)
{

struct Task *task = &amp;gTasks[taskId];

switch (task-&gt;tState)
{
    case 0:
        if (gMsgIsSignPost)
            LoadSignPostWindowFrameGfx();
        else
            LoadMessageBoxAndBorderGfx();
        task-&gt;tState++;
        break;
    case 1:
       DrawDialogueFrame(0, TRUE);
       task-&gt;tState++;
       break;
    case 2:
        UpdateDialoguePortraits();   //新增代码
        if (RunTextPrintersAndIsPrinter0Active() != TRUE)
        {
            sFieldMessageBoxMode = FIELD_MESSAGE_BOX_HIDDEN;
            DestroyTask(taskId);
        }
}

}

void HideFieldMessageBox(void)
{

DestroyTask_DrawFieldMessage();
ClearDialogWindowAndFrame(0, TRUE);
CleanupDialoguePortraitSystem();  //新增代码
sFieldMessageBoxMode = FIELD_MESSAGE_BOX_HIDDEN;

}

这个文件添加代码:data\specials.inc

def_special Special_ShowDialoguePortrait

def_special Special_HideDialoguePortrait
def_special Special_UpdateDialoguePortraits
def_special Special_InitDialoguePortraitSystem
def_special Special_ShowDialoguePortrait
def_special Special_ShowDialoguePortraitWithFlip
def_special Special_HideDialoguePortrait
def_special Special_UpdateDialoguePortraits
def_special Special_CleanupDialoguePortraitSystem
def_special Special_SetDialoguePortraitFlip</code></pre><p><strong>这个文件添加代码:src\field_specials.c</strong></p><pre class="enlighter-pre"><code class="gl">#include "dialogue_portraits.h"   //新增代码</code></pre><pre class="enlighter-pre"><code class="gl">// 头像系统special函数实现

void Special_InitDialoguePortraitSystem(void)
{

InitDialoguePortraitSystem();

}

void Special_ShowDialoguePortrait(void)
{

u8 side = gSpecialVar_0x8004;      // 0=左侧,1=右侧
u8 portraitId = gSpecialVar_0x8005; // 头像ID
u16 gfxTag = gSpecialVar_0x8006;    // 图形标签
u16 paletteTag = gSpecialVar_0x8007; // 调色板标签

ShowDialoguePortrait(portraitId, side, gfxTag, paletteTag);

}

void Special_ShowDialoguePortraitWithFlip(void)
{

u8 side = gSpecialVar_0x8004;      // 0=左侧,1=右侧
u8 portraitId = gSpecialVar_0x8005; // 头像ID
u16 gfxTag = gSpecialVar_0x8006;    // 图形标签
u16 paletteTag = gSpecialVar_0x8007; // 调色板标签
bool8 hFlip = gSpecialVar_0x8008;   // 水平翻转
bool8 vFlip = gSpecialVar_0x8009;   // 垂直翻转

ShowDialoguePortraitWithFlip(portraitId, side, gfxTag, paletteTag, hFlip, vFlip);

}

void Special_HideDialoguePortrait(void)
{

u8 side = gSpecialVar_0x8004; // 0=左侧,1=右侧
HideDialoguePortrait(side);

}

void Special_UpdateDialoguePortraits(void)
{

UpdateDialoguePortraits();

}

void Special_CleanupDialoguePortraitSystem(void)
{

CleanupDialoguePortraitSystem();

}

void Special_SetDialoguePortraitFlip(void)
{

u8 side = gSpecialVar_0x8004;  // 0=左侧,1=右侧
bool8 hFlip = gSpecialVar_0x8005; // 水平翻转
bool8 vFlip = gSpecialVar_0x8006; // 垂直翻转

SetDialoguePortraitFlip(side, hFlip, vFlip);

}

新增文件:include\portrait_data.h

#ifndef GUARD_PORTRAIT_DATA_H

define GUARD_PORTRAIT_DATA_H

// 自定义头像资源声明
// 这些将由工具链从graphics/head/文件夹中的PNG和PAL文件生成

extern const u8 gHeadPortrait_001_Gfx[];
extern const u16 gHeadPortrait_001_Pal[];
extern const u8 gHeadPortrait_002_Gfx[];
extern const u16 gHeadPortrait_002_Pal[];

endif // GUARD_PORTRAIT_DATA_H

文件新增代码:include\constants\field_specials.h

// 头像系统Special函数常量

define SPECIAL_INIT_DIALOGUE_PORTRAIT_SYSTEM 0x200

define SPECIAL_SHOW_DIALOGUE_PORTRAIT 0x201

define SPECIAL_HIDE_DIALOGUE_PORTRAIT 0x202

define SPECIAL_UPDATE_DIALOGUE_PORTRAITS 0x203

define SPECIAL_CLEANUP_DIALOGUE_PORTRAIT_SYSTEM 0x204

文件新增代码:graphics_file_rules.mk

### Custom Trainer Portraits

Define custom graphics directory

CUSTOMGFXDIR := graphics/head

Convert PNG to 4bpp format for trainer portraits

$(CUSTOMGFXDIR)/head_001.4bpp: %.4bpp: %.png

$(GFX) $</code></pre><p><strong>脚本测试示例:</strong></p><pre class="enlighter-pre"><code class="gl">Text_PortraitFlipIntro:
.string "这是头像翻转功能演示。\n我们将展示各种翻转效果。$"

Text_PortraitNormal:

.string "这是正常方向的头像。$"

Text_PortraitHFlip:

.string "这是水平翻转的头像。\n头像现在面向左边。$"

Text_PortraitVFlip:

.string "这是垂直翻转的头像。\n头像现在上下颠倒。$"

Text_PortraitBothFlip:

.string "这是同时水平和垂直翻转的头像。\n相当于180度旋转。$"

Text_PortraitRestored:

.string "恢复正常方向的头像。$"

Text_DualPortraitIntro:

.string "现在演示双人对话中的翻转效果。$"

Text_LeftCharacterNormal:

.string "左边角色:你好!我是面向右边的。$"

Text_RightCharacterFlipped:

.string "右边角色:你好!我现在面向左边。$"

Text_BothFacingForward:

.string "两个角色都面向前方了!$"

Text_DynamicFlipIntro:

.string "演示动态翻转效果,模拟角色转头。$"

Text_FacingRight:

.string "面向右边...$"

Text_FacingLeft:

.string "面向左边...$"

Text_FacingRightAgain:

.string "又面向右边了!$"

Text_DemoComplete:

.string "头像翻转功能演示完成!$"

// 示例1:基本头像显示和翻转
EventScript_PortraitFlipBasic::

lock
faceplayer

// 初始化头像系统
special Special_InitDialoguePortraitSystem

msgbox Text_PortraitFlipIntro, MSGBOX_DEFAULT
waitmessage
waitbuttonpress

// 显示左侧头像(使用自定义头像ID)
setvar VAR_0x8004, 0      // 左侧
setvar VAR_0x8005, 0      // 头像ID 0 (未使用)
setvar VAR_0x8006, 1000   // 自定义头像ID: head_001.png
setvar VAR_0x8007, 0      // 调色板标签 (未使用)
special Special_ShowDialoguePortrait

msgbox Text_PortraitNormal, MSGBOX_DEFAULT
waitmessage
waitbuttonpress

// 水平翻转头像
setvar VAR_0x8004, 0      // 左侧
setvar VAR_0x8005, 1      // hFlip=TRUE
setvar VAR_0x8006, 0      // vFlip=FALSE
special Special_SetDialoguePortraitFlip

msgbox Text_PortraitHFlip, MSGBOX_DEFAULT
waitmessage
waitbuttonpress

// 垂直翻转头像
setvar VAR_0x8004, 0      // 左侧
setvar VAR_0x8005, 0      // hFlip=FALSE
setvar VAR_0x8006, 1      // vFlip=TRUE
special Special_SetDialoguePortraitFlip

msgbox Text_PortraitVFlip, MSGBOX_DEFAULT
waitmessage
waitbuttonpress

// 同时水平和垂直翻转
setvar VAR_0x8004, 0      // 左侧
setvar VAR_0x8005, 1      // hFlip=TRUE
setvar VAR_0x8006, 1      // vFlip=TRUE
special Special_SetDialoguePortraitFlip

msgbox Text_PortraitBothFlip, MSGBOX_DEFAULT
waitmessage
waitbuttonpress

// 恢复正常方向
setvar VAR_0x8004, 0      // 左侧
setvar VAR_0x8005, 0      // hFlip=FALSE
setvar VAR_0x8006, 0      // vFlip=FALSE
special Special_SetDialoguePortraitFlip

msgbox Text_PortraitRestored, MSGBOX_DEFAULT
waitmessage
waitbuttonpress

// 隐藏头像
setvar VAR_0x8004, 0      // 左侧
special Special_HideDialoguePortrait

// 清理头像系统
special Special_CleanupDialoguePortraitSystem

release
end

// 示例2:双人对话中的翻转效果
EventScript_PortraitFlipDual::

lock
faceplayer

// 初始化头像系统
special Special_InitDialoguePortraitSystem

msgbox Text_DualPortraitIntro, MSGBOX_DEFAULT
waitmessage
waitbuttonpress

// 显示两个头像
setvar VAR_0x8004, 0      // 左侧
setvar VAR_0x8005, 0      // 头像ID 0
setvar VAR_0x8006, 1001     // 训练师ID: Brendan
setvar VAR_0x8007, 0      // 调色板标签
special Special_ShowDialoguePortrait

setvar VAR_0x8004, 1      // 右侧
setvar VAR_0x8005, 1      // 头像ID 1
setvar VAR_0x8006, 1000     // 训练师ID: May
setvar VAR_0x8007, 0      // 调色板标签
special Special_ShowDialoguePortrait

// 左侧角色说话(正常面向右边)
msgbox Text_LeftCharacterNormal, MSGBOX_DEFAULT
waitmessage
waitbuttonpress

// 右侧角色说话(水平翻转面向左边)
setvar VAR_0x8004, 1      // 右侧
setvar VAR_0x8005, 1      // hFlip=TRUE
setvar VAR_0x8006, 0      // vFlip=FALSE
special Special_SetDialoguePortraitFlip

msgbox Text_RightCharacterFlipped, MSGBOX_DEFAULT
waitmessage
waitbuttonpress

// 两个角色都面向前方
setvar VAR_0x8004, 0      // 左侧
setvar VAR_0x8005, 0      // hFlip=FALSE
setvar VAR_0x8006, 0      // vFlip=FALSE
special Special_SetDialoguePortraitFlip

setvar VAR_0x8004, 1      // 右侧
setvar VAR_0x8005, 0      // hFlip=FALSE
setvar VAR_0x8006, 0      // vFlip=FALSE
special Special_SetDialoguePortraitFlip

msgbox Text_BothFacingForward, MSGBOX_DEFAULT
waitmessage
waitbuttonpress

// 隐藏头像
setvar VAR_0x8004, 0      // 左侧
special Special_HideDialoguePortrait

setvar VAR_0x8004, 1      // 右侧
special Special_HideDialoguePortrait

// 清理头像系统
special Special_CleanupDialoguePortraitSystem

release
end

// 示例3:动态翻转效果(模拟角色转头)
EventScript_PortraitFlipDynamic::

lock
faceplayer

// 初始化头像系统
special Special_InitDialoguePortraitSystem

msgbox Text_DynamicFlipIntro, MSGBOX_DEFAULT
waitmessage
waitbuttonpress

// 显示头像
setvar VAR_0x8004, 0      // 左侧
setvar VAR_0x8005, 0      // 头像ID 0
setvar VAR_0x8006, 1000   // 自定义头像ID
setvar VAR_0x8007, 0      // 调色板标签
special Special_ShowDialoguePortrait

// 正常方向(面向右边)
setvar VAR_0x8004, 0      // 左侧
setvar VAR_0x8005, 0      // hFlip=FALSE
setvar VAR_0x8006, 0      // vFlip=FALSE
special Special_SetDialoguePortraitFlip

msgbox Text_FacingRight, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
delay 30

// 水平翻转(面向左边)
setvar VAR_0x8004, 0      // 左侧
setvar VAR_0x8005, 1      // hFlip=TRUE
setvar VAR_0x8006, 0      // vFlip=FALSE
special Special_SetDialoguePortraitFlip

msgbox Text_FacingLeft, MSGBOX_DEFAULT
waitmessage
waitbuttonpress
delay 30

// 再次翻转回来
setvar VAR_0x8004, 0      // 左侧
setvar VAR_0x8005, 0      // hFlip=FALSE
setvar VAR_0x8006, 0      // vFlip=FALSE
special Special_SetDialoguePortraitFlip

msgbox Text_FacingRightAgain, MSGBOX_DEFAULT
waitmessage
waitbuttonpress

// 隐藏头像
setvar VAR_0x8004, 0      // 左侧
special Special_HideDialoguePortrait

// 清理头像系统
special Special_CleanupDialoguePortraitSystem

msgbox Text_DemoComplete, MSGBOX_DEFAULT
waitmessage
waitbuttonpress

release
end</code></pre><p>-----------------------------------------------分割线---------------------------------------------------</p><h2>脚本封装更新</h2><p>因为之前的写法过于臃肿,所以需要改进一下脚本的写法</p><p><strong>定义语义化宏常量:constants\portrait_constants.inc</strong></p><pre class="enlighter-pre"><code class="gl">// 头像系统常量定义

// 头像位置常量

define PORTRAIT_LEFT 0

define PORTRAIT_RIGHT 1

// 头像翻转常量

define FLIP_NONE 0

define FLIP_HORIZONTAL 1

define FLIP_VERTICAL 1

define FLIP_BOTH 1

// 头像系统变量别名

define PORTRAIT_POS VAR_0x8004

define PORTRAIT_ID VAR_0x8005

define PORTRAIT_GFX_TAG VAR_0x8006

define PORTRAIT_PAL_TAG VAR_0x8007

define PORTRAIT_H_FLIP VAR_0x8008

define PORTRAIT_V_FLIP VAR_0x8009

define PORTRAIT_FLIP_H VAR_0x8005

define PORTRAIT_FLIP_V VAR_0x8006

在这个文件constants\constants.inc新增一行:

.include "constants/portrait_constants.inc"

封装常用操作为宏

// ==================== Portrait System Macros ====================

// Portrait position constants
.set PORTRAIT_LEFT, 0
.set PORTRAIT_RIGHT, 1

// Portrait flip constants
.set FLIP_NONE, 0
.set FLIP_HORIZONTAL, 1
.set FLIP_VERTICAL, 1
.set FLIP_BOTH, 1

// Portrait system variable aliases
.set PORTRAIT_POS, VAR_0x8004
.set PORTRAIT_ID, VAR_0x8005
.set PORTRAIT_GFX_TAG, VAR_0x8006
.set PORTRAIT_PAL_TAG, VAR_0x8007
.set PORTRAIT_H_FLIP, VAR_0x8008
.set PORTRAIT_V_FLIP, VAR_0x8009
.set PORTRAIT_FLIP_H, VAR_0x8005
.set PORTRAIT_FLIP_V, VAR_0x8006

// Show portrait macro
.macro SHOW_PORTRAIT pos, id, gfx_tag, pal_tag

setvar PORTRAIT_POS, \pos
setvar PORTRAIT_ID, \id
setvar PORTRAIT_GFX_TAG, \gfx_tag
setvar PORTRAIT_PAL_TAG, \pal_tag
special Special_ShowDialoguePortrait

.endm

// Show flipped portrait macro
.macro SHOW_PORTRAIT_FLIP pos, id, gfx_tag, pal_tag, h_flip, v_flip

setvar PORTRAIT_POS, \pos
setvar PORTRAIT_ID, \id
setvar PORTRAIT_GFX_TAG, \gfx_tag
setvar PORTRAIT_PAL_TAG, \pal_tag
setvar PORTRAIT_H_FLIP, \h_flip
setvar PORTRAIT_V_FLIP, \v_flip
special Special_ShowDialoguePortraitWithFlip

.endm

// Hide portrait macro
.macro HIDE_PORTRAIT pos

setvar PORTRAIT_POS, \pos
special Special_HideDialoguePortrait

.endm

// Set portrait flip macro
.macro SET_PORTRAIT_FLIP pos, h_flip, v_flip

setvar PORTRAIT_POS, \pos
setvar PORTRAIT_FLIP_H, \h_flip
setvar PORTRAIT_FLIP_V, \v_flip
special Special_SetDialoguePortraitFlip

.endm

改进后的脚本示例:

// ==================== 头像系统测试脚本 ====================

EventScript_PortraitSystemTest::

lock
faceplayer
msgbox Text_PortraitTestIntro, MSGBOX_DEFAULT
call EventScript_PortraitBasicTest
call EventScript_PortraitFlipTest
call EventScript_PortraitCustomTest
call EventScript_PortraitDualTest
call EventScript_PortraitAdvancedTest
msgbox Text_PortraitTestComplete, MSGBOX_DEFAULT
release
end

// 基础功能测试
EventScript_PortraitBasicTest::

msgbox Text_BasicTestStart, MSGBOX_DEFAULT
special Special_InitDialoguePortraitSystem

SHOW_PORTRAIT PORTRAIT_LEFT, 1, 1, 1
delay 30
msgbox Text_LeftPortraitShown, MSGBOX_DEFAULT

SHOW_PORTRAIT PORTRAIT_RIGHT, 2, 2, 2
delay 30
msgbox Text_RightPortraitShown, MSGBOX_DEFAULT

HIDE_PORTRAIT PORTRAIT_LEFT
delay 15
msgbox Text_LeftPortraitHidden, MSGBOX_DEFAULT

HIDE_PORTRAIT PORTRAIT_RIGHT
delay 15
msgbox Text_RightPortraitHidden, MSGBOX_DEFAULT

special Special_CleanupDialoguePortraitSystem
return

// 翻转功能测试
EventScript_PortraitFlipTest::

msgbox Text_FlipTestStart, MSGBOX_DEFAULT
special Special_InitDialoguePortraitSystem

SHOW_PORTRAIT PORTRAIT_LEFT, 1, 1, 1
delay 30
msgbox Text_NormalPortrait, MSGBOX_DEFAULT

SET_PORTRAIT_FLIP PORTRAIT_LEFT, FLIP_HORIZONTAL, FLIP_NONE
delay 30
msgbox Text_HorizontalFlip, MSGBOX_DEFAULT

SET_PORTRAIT_FLIP PORTRAIT_LEFT, FLIP_NONE, FLIP_VERTICAL
delay 30
msgbox Text_VerticalFlip, MSGBOX_DEFAULT

SET_PORTRAIT_FLIP PORTRAIT_LEFT, FLIP_HORIZONTAL, FLIP_VERTICAL
delay 30
msgbox Text_BothFlip, MSGBOX_DEFAULT

SET_PORTRAIT_FLIP PORTRAIT_LEFT, FLIP_NONE, FLIP_NONE
delay 30
msgbox Text_NormalAgain, MSGBOX_DEFAULT

HIDE_PORTRAIT PORTRAIT_LEFT
delay 15

SHOW_PORTRAIT_FLIP PORTRAIT_RIGHT, 3, 3, 3, FLIP_HORIZONTAL, FLIP_NONE
delay 30
msgbox Text_DirectFlipPortrait, MSGBOX_DEFAULT

HIDE_PORTRAIT PORTRAIT_RIGHT
delay 15

special Special_CleanupDialoguePortraitSystem
return

// 自定义头像测试
EventScript_PortraitCustomTest::

msgbox Text_CustomTestStart, MSGBOX_DEFAULT
special Special_InitDialoguePortraitSystem

SHOW_PORTRAIT PORTRAIT_LEFT, 1, 1000, 2000
delay 30
msgbox Text_CustomPortrait1, MSGBOX_DEFAULT

SHOW_PORTRAIT_FLIP PORTRAIT_RIGHT, 2, 1001, 2001, FLIP_HORIZONTAL, FLIP_NONE
delay 30
msgbox Text_CustomPortrait2, MSGBOX_DEFAULT

HIDE_PORTRAIT PORTRAIT_LEFT
delay 15
HIDE_PORTRAIT PORTRAIT_RIGHT
delay 15

special Special_CleanupDialoguePortraitSystem
return

// 双头像对话测试
EventScript_PortraitDualTest::

msgbox Text_DualTestStart, MSGBOX_DEFAULT
special Special_InitDialoguePortraitSystem

SHOW_PORTRAIT PORTRAIT_LEFT, 1, 1, 1
SHOW_PORTRAIT PORTRAIT_RIGHT, 2, 2, 2
delay 30

msgbox Text_Dialogue1, MSGBOX_DEFAULT
delay 20

HIDE_PORTRAIT PORTRAIT_LEFT
delay 15
msgbox Text_Dialogue2, MSGBOX_DEFAULT
delay 20

SHOW_PORTRAIT PORTRAIT_LEFT, 1, 1, 1
delay 15
HIDE_PORTRAIT PORTRAIT_RIGHT
delay 15
msgbox Text_Dialogue3, MSGBOX_DEFAULT
delay 20

SHOW_PORTRAIT PORTRAIT_RIGHT, 2, 2, 2
delay 15
msgbox Text_Dialogue4, MSGBOX_DEFAULT
delay 20

HIDE_PORTRAIT PORTRAIT_LEFT
delay 15
HIDE_PORTRAIT PORTRAIT_RIGHT
delay 15

special Special_CleanupDialoguePortraitSystem
return

// 高级功能测试
EventScript_PortraitAdvancedTest::

msgbox Text_AdvancedTestStart, MSGBOX_DEFAULT
special Special_InitDialoguePortraitSystem

SHOW_PORTRAIT PORTRAIT_LEFT, 1, 1, 1
delay 30
msgbox Text_DynamicFlipStart, MSGBOX_DEFAULT

call EventScript_FlipAnimation
call EventScript_TrainerGallery

HIDE_PORTRAIT PORTRAIT_LEFT
delay 15

special Special_CleanupDialoguePortraitSystem
return

// 翻转动画效果
EventScript_FlipAnimation::

SET_PORTRAIT_FLIP PORTRAIT_LEFT, FLIP_HORIZONTAL, FLIP_NONE
delay 20

SET_PORTRAIT_FLIP PORTRAIT_LEFT, FLIP_NONE, FLIP_VERTICAL
delay 20

SET_PORTRAIT_FLIP PORTRAIT_LEFT, FLIP_HORIZONTAL, FLIP_VERTICAL
delay 20

SET_PORTRAIT_FLIP PORTRAIT_LEFT, FLIP_NONE, FLIP_NONE
delay 20

return

// 训练师头像画廊
EventScript_TrainerGallery::

SHOW_PORTRAIT PORTRAIT_RIGHT, 10, 10, 10
delay 30

HIDE_PORTRAIT PORTRAIT_RIGHT
delay 15

return

// ====================
// 文本定义
// ====================

Text_PortraitTestIntro::

.string "头像系统测试开始!\n"
.string "将测试所有头像功能。$"

Text_BasicTestStart::

.string "基础功能测试:\n"
.string "测试头像的显示和隐藏。$"

Text_LeftPortraitShown::

.string "左侧头像已显示。\n"
.string "这是训练师的头像。$"

Text_RightPortraitShown::

.string "右侧头像已显示。\n"
.string "这是另一个训练师。$"

Text_LeftPortraitHidden::

.string "左侧头像已隐藏。$"

Text_RightPortraitHidden::

.string "右侧头像已隐藏。\n"
.string "基础测试完成。$"

Text_FlipTestStart::

.string "翻转功能测试:\n"
.string "测试头像的各种翻转效果。$"

Text_NormalPortrait::

.string "这是正常的头像。$"

Text_HorizontalFlip::

.string "现在是水平翻转状态。\n"
.string "头像被左右翻转了。$"

Text_VerticalFlip::

.string "现在是垂直翻转状态。\n"
.string "头像被上下翻转了。$"

Text_BothFlip::

.string "现在是双向翻转状态。\n"
.string "头像同时进行了水平和垂直翻转。$"

Text_NormalAgain::

.string "恢复到正常状态。$"

Text_DirectFlipPortrait::

.string "这是直接显示的翻转头像。\n"
.string "一步到位,无需等待!$"

Text_CustomTestStart::

.string "自定义头像测试:\n"
.string "测试自定义头像资源。$"

Text_CustomPortrait1::

.string "这是自定义头像1。\n"
.string "使用自定义的图形和调色板。$"

Text_CustomPortrait2::

.string "这是自定义头像2。\n"
.string "并且带有水平翻转效果。$"

Text_DualTestStart::

.string "双头像对话测试:\n"
.string "模拟对话场景中的头像切换。$"

Text_Dialogue1::

.string "玩家:你好!\n"
.string "我是这个地区的训练师。$"

Text_Dialogue2::

.string "NPC:欢迎来到我们的城镇!\n"
.string "这里有很多强大的训练师。$"

Text_Dialogue3::

.string "玩家:听起来很有挑战性!\n"
.string "我很期待与他们对战。$"

Text_Dialogue4::

.string "NPC:祝你好运!\n"
.string "如果你需要帮助,随时来找我。$"

Text_AdvancedTestStart::

.string "高级功能测试:\n"
.string "测试动态效果和特殊功能。$"

Text_DynamicFlipStart::

.string "现在演示动态翻转效果:$"

Text_PortraitTestComplete::

.string "所有头像功能测试完成!\n"
.string "系统运行正常。$"

// ====================
// 使用说明
// ====================

/*
使用方法:

  1. 将此脚本添加到你的地图脚本文件中
  2. 创建一个NPC事件,调用 EventScript_PortraitSystemTest
  3. 与NPC对话即可开始测试

测试内容:

  • 基础显示/隐藏功能
  • 水平/垂直翻转效果
  • 自定义头像资源
  • 双头像对话场景
  • 动态翻转动画
  • 训练师头像画廊

注意事项:

  • 确保已正确实现头像系统的所有函数
  • 自定义头像需要预先准备好图形和调色板资源
  • 训练师ID需要根据实际情况调整
  • 可以根据需要调整delay的时间长度
    */
支持这篇文章点赞、收藏或分享给朋友
DISCUSSION

发表评论

留下你的想法

输入 @用户名 可以提及站内用户0 / 5000