16 KiB
用户界面系统
**本文档中引用的文件** - [GameUIConfig.ts](file://assets/script/game/common/config/GameUIConfig.ts) - [HInfoComp.ts](file://assets/script/game/map/HInfoComp.ts) - [MInfoComp.ts](file://assets/script/game/map/MInfoComp.ts) - [TopComp.ts](file://assets/script/game/map/TopComp.ts) - [VictoryComp.ts](file://assets/script/game/map/VictoryComp.ts) - [SIconComp.ts](file://assets/script/game/map/SIconComp.ts) - [GameEvent.ts](file://assets/script/game/common/config/GameEvent.ts) - [SingletonModuleComp.ts](file://assets/script/game/common/SingletonModuleComp.ts) - [MvvmInfo.md](file://doc/mvvm/MvvmInfo.md) - [VMBase.md](file://doc/mvvm/VMBase.md) - [gui.md](file://doc/core/gui/gui.md)目录
简介
本游戏采用基于Oops Framework的现代化UI系统架构,集成了MVVM设计模式和事件驱动的组件化开发方式。系统通过GameUIConfig.ts统一管理界面配置,支持多种UI层级和预制体路径配置,并通过MVVM框架实现数据与视图的自动绑定。
项目结构
UI系统的核心文件组织结构如下:
graph TB
subgraph "UI配置层"
A[GameUIConfig.ts] --> B[UIID枚举]
A --> C[UIConfigData配置]
end
subgraph "组件层"
D[HInfoComp.ts] --> E[英雄信息面板]
F[MInfoComp.ts] --> G[怪物信息组件]
H[TopComp.ts] --> I[顶部状态栏]
J[VictoryComp.ts] --> K[胜利界面]
L[SIconComp.ts] --> M[技能图标组件]
end
subgraph "框架层"
N[MVVM框架] --> O[ViewModel]
N --> P[VMBase组件]
Q[事件系统] --> R[GameEvent]
end
A --> D
A --> F
A --> H
A --> J
A --> L
N --> D
N --> F
N --> H
N --> J
N --> L
Q --> D
Q --> F
Q --> H
Q --> J
Q --> L
图表来源
章节来源
UI层级架构
层级类型定义
系统采用分层的UI管理架构,通过LayerType枚举定义不同的界面层级:
| 层级类型 | 描述 | 使用场景 |
|---|---|---|
| UI层 | 主界面层级,常驻显示 | 英雄信息面板、顶部状态栏 |
| PopUp层 | 弹出式界面 | 网络不稳定提示、Toast消息 |
| Dialog层 | 模态对话框 | 弹窗界面、确认对话框 |
配置数据结构
classDiagram
class UIConfig {
+LayerType layer
+string prefab
+string bundle
}
class UIID {
<<enumeration>>
Loading
Netinstable
Role_Controller
Victory
Guide
}
class GameUIConfig {
+UIConfigData : {[key : number] : UIConfig}
+registerUI(id : number, config : UIConfig) : void
+getUIConfig(id : number) : UIConfig
}
UIID --> GameUIConfig : "配置"
UIConfig --> GameUIConfig : "管理"
图表来源
章节来源
核心组件分析
HInfoComp - 英雄信息面板
英雄信息面板是最复杂的UI组件,负责展示和管理英雄选择、属性显示和交互功能。
组件架构
classDiagram
class HInfoComp {
+number h_uuid
+Node[] heroNodes
+Vec3 hero_pos
+boolean isMoving
+any moveTimeoutId
+update_data(uuid : number) : void
+load_all_hero(uuid : number) : void
+load_hui(uuid : number, pos_index : number) : Node
+next_hero() : void
+prev_hero() : void
+buy_hero() : void
+start_mission() : void
+moveHeroesLeft() : void
+moveHeroesRight() : void
+show_lock() : void
+claear_hero() : void
}
class CCComp {
+onLoad() : void
+start() : void
+update(deltaTime : number) : void
+reset() : void
}
HInfoComp --|> CCComp : "继承"
图表来源
英雄选择动画系统
组件实现了复杂的英雄选择动画系统,包括:
- 循环滚动算法:支持无限循环的英雄选择
- 平滑动画过渡:使用Tween实现流畅的移动效果
- 视觉焦点效果:3号位置英雄显示1.5倍放大效果
- 动画锁定机制:防止快速点击导致的动画冲突
数据绑定与更新
sequenceDiagram
participant User as 用户
participant HInfo as HInfoComp
participant SM as SingletonModule
participant VM as ViewModel
User->>HInfo : 点击英雄选择
HInfo->>HInfo : 验证动画状态
HInfo->>HInfo : 计算下一个英雄
HInfo->>SM : updateFihgtHero(uuid)
SM->>VM : 更新战斗英雄
VM->>HInfo : 通知数据变更
HInfo->>HInfo : update_data(uuid)
HInfo->>HInfo : 执行动画过渡
图表来源
章节来源
MInfoComp - 怪物信息组件
怪物信息组件负责显示当前关卡信息,采用简洁的设计模式。
组件特性
- 事件驱动更新:监听MISSION_UPDATE事件自动更新关卡信息
- 文本绑定:直接绑定到Label组件的字符串属性
- 生命周期管理:在onLoad中注册事件监听器,在start中初始化数据
章节来源
TopComp - 顶部状态栏
顶部状态栏组件专注于显示玩家资源信息,特别是金币数量的动画效果。
特色功能
- 资源动画效果:金币数量变化时触发缩放动画
- 事件响应:监听GOLD_UPDATE事件执行动画
- 轻量级设计:专注于单一功能,避免过度复杂化
章节来源
VictoryComp - 胜利界面
胜利界面组件处理战斗结算和奖励展示,包含复杂的奖励系统和动画效果。
界面流程
flowchart TD
A[战斗胜利] --> B[显示胜利界面]
B --> C[展示奖励信息]
C --> D{玩家选择}
D --> |继续| E[下一关卡]
D --> |重新开始| F[重置关卡]
D --> |双倍奖励| G[观看广告]
E --> H[清理数据]
F --> H
G --> I[验证广告]
I --> J{验证结果}
J --> |成功| K[获得双倍奖励]
J --> |失败| L[显示错误]
K --> H
H --> M[返回主界面]
图表来源
章节来源
SIconComp - 技能图标组件
技能图标组件负责显示技能的视觉图标,采用简单的数据绑定模式。
组件特点
- 资源动态加载:根据技能UUID动态加载对应的图标资源
- 路径配置:通过SkillSet配置技能的资源路径
- 轻量级实现:专注于单一职责,易于维护和扩展
章节来源
MVVM框架集成
架构概览
系统采用MVVM(Model-View-ViewModel)架构模式,通过Oops Framework的ViewModel模块实现数据与视图的自动绑定。
graph LR
subgraph "Model层"
A[数据模型] --> B[SingletonModuleComp]
B --> C[vmdata对象]
end
subgraph "ViewModel层"
D[ViewModel] --> E[VMManager]
E --> F[数据监听]
end
subgraph "View层"
G[UI组件] --> H[VMBase组件]
H --> I[数据绑定]
end
C --> D
F --> H
I --> G
图表来源
数据模型管理
系统通过SingletonModuleComp统一管理游戏数据,特别是VM数据模型:
classDiagram
class SingletonModuleComp {
+vmdata : any
+vmAdd() : void
+updateGold(gold : number) : void
+updateFihgtHero(heroId : number) : void
+addHero(hero_uuid : number) : void
}
class ViewModel {
+add(data : any, tag : string) : void
+get(tag : string) : ViewModel
+setValue(path : string, value : any) : void
+getValue(path : string) : any
}
SingletonModuleComp --> ViewModel : "管理"
图表来源
VMBase组件基类
所有UI组件都继承自VMBase组件,实现自动的数据绑定功能:
| 属性 | 类型 | 描述 |
|---|---|---|
| watchPath | string | 需要监听的数据路径 |
| watchPathArr | string[] | 多路径监听数组 |
| templateMode | boolean | 启用模板模式 |
| VM | VMManager | ViewModel管理器引用 |
章节来源
事件系统与数据绑定
事件类型定义
系统通过GameEvent枚举定义了完整的游戏事件体系:
graph TB
subgraph "战斗事件"
A[FightStart] --> B[FightEnd]
C[FightPause] --> D[FightResume]
end
subgraph "关卡事件"
E[MissionStart] --> F[MissionEnd]
G[MissionWin] --> H[MissionLoss]
end
subgraph "资源事件"
I[GOLD_UPDATE] --> J[DIAMOND_UPDATE]
K[MEAT_UPDATE] --> L[MISSION_UPDATE]
end
subgraph "选择事件"
M[HeroSelect] --> N[EnhancementSelect]
O[TalentSelect] --> P[FuncSelect]
end
图表来源
数据绑定流程
sequenceDiagram
participant Model as 数据模型
participant VM as ViewModel
participant View as UI组件
participant Event as 事件系统
Model->>VM : 数据变更
VM->>VM : 触发监听器
VM->>Event : 发送事件通知
Event->>View : 分发事件
View->>View : 更新UI显示
View->>Model : 响应用户交互
图表来源
章节来源
使用示例
注册新UI界面
以下是如何注册和使用新UI界面的完整示例:
// 1. 在GameUIConfig.ts中添加UI配置
export enum UIID {
// ... 现有UI ID
CustomPanel = 2001,
}
export var UIConfigData: { [key: number]: UIConfig } = {
// ... 现有UI配置
[UIID.CustomPanel]: {
layer: LayerType.UI,
prefab: "custom/prefab/panel"
},
};
// 2. 创建UI组件
@ccclass('CustomPanelComp')
export class CustomPanelComp extends CCComp {
protected onLoad(): void {
// 注册事件监听
oops.message.on(GameEvent.CustomEvent, this.onCustomEvent, this);
}
onCustomEvent(event: string, data: any): void {
// 处理自定义事件
this.updateDisplay(data);
}
updateDisplay(data: any): void {
// 更新UI显示
const label = this.node.getChildByName("content")
.getComponent(Label);
label.string = data.message;
}
}
// 3. 打开UI界面
const callbacks: UICallbacks = {
onAdded: (node: Node, params: any) => {
const comp = node.getComponent(CustomPanelComp);
// 初始化界面
},
onRemoved: (node: Node | null, params: any) => {
// 清理资源
}
};
oops.gui.open(UIID.CustomPanel, null, callbacks);
处理按钮点击事件
// 在UI组件中处理按钮点击
@ccclass('ButtonHandler')
export class ButtonHandler extends Component {
start(): void {
// 获取按钮节点
const button = this.node.getChildByName("action_button");
if (button) {
// 添加点击事件监听
button.on(Node.EventType.TOUCH_END, this.onButtonClick, this);
}
}
onButtonClick(event: EventTouch): void {
// 触发游戏事件
oops.message.dispatchEvent(GameEvent.ButtonClicked, {
buttonId: "action_button",
timestamp: Date.now()
});
// 执行业务逻辑
this.performAction();
}
performAction(): void {
// 实现具体业务逻辑
console.log("按钮被点击");
}
}
实现动态数据刷新
// 使用MVVM框架实现自动数据刷新
@ccclass('DynamicDataComp')
export class DynamicDataComp extends VMBase {
@property({ type: Label })
public displayLabel: Label = null!;
@property(String)
public watchPath: string = "global.player.health";
onValueChanged(newValue: any, oldValue: any, pathArray: string[]): void {
// 自动更新UI显示
this.displayLabel.string = `生命值: ${newValue}`;
// 可选:添加视觉反馈
if (newValue < oldValue) {
this.showDamageEffect();
}
}
showDamageEffect(): void {
// 显示伤害特效
tween(this.node)
.to(0.1, { color: Color.RED })
.to(0.1, { color: Color.WHITE })
.start();
}
}
性能优化考虑
组件复用策略
- 预制体池化:对于频繁创建销毁的UI组件,实现预制体池化机制
- 延迟加载:非关键UI组件采用延迟加载策略
- 内存管理:及时清理事件监听器和定时器
动画性能优化
- 批量动画:将多个动画合并为批量操作
- 硬件加速:利用CSS3变换实现硬件加速
- 帧率控制:限制动画帧率避免过度消耗CPU
数据绑定优化
- 路径简化:避免过深的数据绑定路径
- 防抖处理:对高频数据更新实施防抖机制
- 选择性更新:只更新发生变化的UI部分
故障排除指南
常见问题及解决方案
UI组件无法显示
问题症状:UI组件创建后不显示或显示异常
排查步骤:
- 检查预制体路径配置是否正确
- 验证UI层级设置是否符合预期
- 确认组件脚本是否正确注册
解决方案:
// 检查UI配置
console.log("UI配置:", UIConfigData[UIID.CustomPanel]);
// 验证预制体加载
oops.res.get(UIConfigData[UIID.CustomPanel].prefab, Prefab, (err, prefab) => {
if (err) {
console.error("预制体加载失败:", err);
}
});
数据绑定失效
问题症状:数据更新后UI不自动刷新
排查步骤:
- 检查watchPath路径是否正确
- 验证ViewModel是否正常工作
- 确认事件系统是否正常
解决方案:
// 手动测试数据绑定
VM.setValue("global.test.value", "测试数据");
console.log("当前值:", VM.getValue("global.test.value"));
动画卡顿
问题症状:UI动画播放不流畅
排查步骤:
- 检查动画复杂度
- 验证硬件性能
- 确认动画队列管理
解决方案:
// 优化动画实现
tween(target)
.to(0.2, { position: newPosition })
.call(() => {
// 动画完成后清理
this.cleanupAnimation();
})
.start();
章节来源
总结
本UI系统通过模块化的架构设计,实现了高度可维护和可扩展的界面管理方案。系统的主要优势包括:
- 统一的配置管理:通过GameUIConfig.ts集中管理所有UI配置
- MVVM架构:实现数据与视图的自动绑定,减少手动DOM操作
- 事件驱动:基于事件系统实现松耦合的组件通信
- 性能优化:通过合理的架构设计和优化策略保证良好的性能表现
- 易于扩展:模块化的设计使得添加新UI组件变得简单直观
该系统为游戏提供了稳定可靠的UI基础设施,支持复杂的交互逻辑和动态内容更新,是现代游戏开发中UI系统设计的优秀实践案例。