13 · 自定义 UI 面板
游戏需要存档界面、设置面板、CG 鉴赏等 UI。本章讲解如何用 C# 实现自定义 Overlay 面板。
Overlay 系统
灵泛引擎的 Overlay 系统允许在场景之上叠加 UI 面板。这些面板独立于 DSL 场景,由 C# 管理。
面板类型
| 面板 | 用途 | 触发方式 |
|---|---|---|
| 存档/读档面板 | 槽位选择、缩略图展示 | cmd="open_save" / cmd="open_load" |
| 设置面板 | 音量、文字速度、全屏 | cmd="open_settings" |
| 历史面板 | 对话历史列表 | cmd="open_history" |
| CG 鉴赏面板 | 已解锁 CG 展示 | cmd="open_gallery" |
| 快捷菜单 | 右键菜单 | 右键点击 |
button 的 cmd 参数
DSL 中的 button 通过 cmd= 触发 C# Overlay 命令:
dsl
button "保存" x=50% y=50% cmd="open_save"
button "设置" x=50% y=60% cmd="open_settings"
button "退出" x=50% y=70% cmd="do_exit"引擎将这些命令字符串映射到 C# 侧的处理器。
实现自定义面板
1. 创建面板控件
继承 Avalonia 的 UserControl:
csharp
public class SaveLoadPanel : UserControl
{
private readonly IGameController _game;
public SaveLoadPanel(IGameController game)
{
_game = game;
// 构建 UI:槽位列表、缩略图、按钮
var grid = new Grid();
// ... 添加 UI 元素
Content = grid;
}
public async Task SaveAsync(string slot)
{
await _game.SaveAsync(slot);
// 更新 UI 显示
}
}2. 注册到 OverlayManager
csharp
public class OverlayManager
{
private readonly SaveLoadPanel _savePanel;
public void ShowSavePanel()
{
_savePanel.IsVisible = true;
}
public void HideAll()
{
_savePanel.IsVisible = false;
}
}3. 处理 cmd 命令
在 MainWindow.cs 或命令处理器中,将 cmd 字符串映射到面板显示:
csharp
private void HandleCommand(string cmd)
{
switch (cmd)
{
case "open_save":
_overlayManager.ShowSavePanel();
break;
case "open_load":
_overlayManager.ShowLoadPanel();
break;
case "open_settings":
_overlayManager.ShowSettingsPanel();
break;
case "do_exit":
// 引擎不提供统一退出 API;退出由宿主层负责。
// Demo 标准做法(Avalonia):
if (Avalonia.Application.Current?.ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
desktop.Shutdown();
break;
}
}call_screen 方式
除了 cmd,还可以用 call_screen 调用 UI 场景并获取返回值:
dsl
label main:
call_screen "save_panel" store="result"
if {result == "saved"}
say "存档成功!" speaker="系统"
navigate "next"call_screen 会暂停当前剧情,显示 UI 场景,玩家操作完成后返回。
Demo 项目的面板实现
Demo 项目(src/Demo/LingFanEngine.Entry/UI/)包含完整的面板实现可供参考:
| 文件 | 功能 |
|---|---|
SaveLoadPanel.cs | 存档/读档界面 |
SettingsPanel.cs | 设置面板 |
HistoryPanel.cs | 对话历史 |
GalleryPanel.cs | CG 鉴赏 |
QuickMenuPanel.cs | 右键快捷菜单 |
DebugConsolePanel.cs | 调试控制台 |
OverlayManager.cs | Overlay 统一管理 |
参考实现
建议直接阅读 Demo 项目的这些文件,它们展示了完整的面板实现模式。
游戏内工具栏
Demo 项目还实现了一个游戏内工具栏,包含常用功能按钮:
csharp
public class GameToolbar : UserControl
{
// 返回 / 历史 / 跳过 / 自动 / 保存 / 快存 / 快读 / 设置
}工具栏通过快捷键和 UI 按钮触发:
| 快捷键 | 功能 |
|---|---|
| Ctrl+S | 存档 |
| Ctrl+L | 读档 |
| Esc | 关闭面板 |
| 右键 | 快捷菜单 |
| 滚轮上/下 | 回溯/前进 |
自定义 cmd 命令
你可以扩展 cmd 命令系统,添加自定义命令:
csharp
private void HandleCommand(string cmd)
{
switch (cmd)
{
case "open_shop":
_overlayManager.ShowShopPanel();
break;
case "open_inventory":
_overlayManager.ShowInventoryPanel();
break;
// ... 自定义命令
}
}然后在 DSL 中使用:
dsl
button "商店" cmd="open_shop"
button "背包" cmd="open_inventory"动手练习
实现一个简单的确认对话框:
csharp
public class ConfirmDialog : UserControl
{
public Task<bool> ShowAsync(string message)
{
var tcs = new TaskCompletionSource<bool>();
var text = new TextBlock { Text = message };
var yesBtn = new Button { Content = "是" };
var noBtn = new Button { Content = "否" };
yesBtn.Click += (_, _) => { tcs.SetResult(true); IsVisible = false; };
noBtn.Click += (_, _) => { tcs.SetResult(false); IsVisible = false; };
// 布局...
Content = new StackPanel { Children = { text, yesBtn, noBtn } };
IsVisible = true;
return tcs.Task;
}
}下一步
UI 面板掌握了!下一章学习自定义对话框模板——创建完全自定义的对话框外观。