Files
pixelheros/assets/script/game/map/TalentsComp.ts
panw ad0539d238 refactor(ui): 调整UI页面管理方式,改为节点显隐控制
1. 注释并禁用了Ranks、Heros、Talents三个UIID的全局弹窗配置
2. 将三个页面改为通过MissionHomeComp控制节点显隐切换
3. 移除了原有的gui.open/remove弹窗调用逻辑,改为设置active状态
4. 调整了组件生命周期,改用onEnable替代onAdded处理显示逻辑
5. 更新了对应组件的注释和文档说明
2026-05-27 16:18:26 +08:00

269 lines
9.3 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @file TalentsComp.ts
* @description 天赋系统页面组件UI 视图层)
*
* 职责:
* 1. 展示玩家等级、当前经验、进度条、金币。
* 2. 展示天赋列表及每个天赋的当前等级。
* 3. 处理天赋升级点击事件,扣除金币并保存。
* 4. 处理重置天赋(看广告)功能。
*
* 关键设计:
* - 通过 MissionHomeComp 页面切换显示,节点 active 控制显隐。
* - onAdded(args) 接收参数时刷新界面。
*
* 依赖:
* - MissionHomeComp —— 通过节点 active 显隐控制页面切换
* - smc.collection —— 玩家数据
* - TalentConfigTalentSet—— 天赋配置
*/
import { _decorator, Node, Label, Button, ProgressBar, instantiate, Prefab } from "cc";
import { ecs } from "../../../../extensions/oops-plugin-framework/assets/libs/ecs/ECS";
import { CCComp } from "../../../../extensions/oops-plugin-framework/assets/module/common/CCComp";
import { mLogger } from "../common/Logger";
import { smc } from "../common/SingletonModuleComp";
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
import { TalentConfig, TalentInfo, TalentType } from "../common/config/TalentSet";
import { TalentItemComp } from "./TalentItemComp";
const { ccclass, property } = _decorator;
/**
* TalentsComp —— 天赋系统界面组件
*
* 职责:
* 1. 展示玩家等级、当前经验、进度条、金币。
* 2. 展示天赋列表及每个天赋的当前等级。
* 3. 处理天赋升级点击事件,扣除金币并保存。
* 4. 处理重置天赋(看广告)功能。
*/
@ccclass('TalentsComp')
@ecs.register('Talents', false)
export class TalentsComp extends CCComp {
@property({ type: Node, tooltip: "标题节点" })
title_node: Node = null!;
@property({ type: Label, tooltip: "玩家等级文本,例如 'Lv.12'" })
lbl_level: Label = null!;
@property({ type: Label, tooltip: "经验文本,例如 '150/200'" })
lbl_exp: Label = null!;
@property({ type: ProgressBar, tooltip: "经验进度条" })
pb_exp: ProgressBar = null!;
@property({ type: Label, tooltip: "当前金币文本" })
lbl_points: Label = null!;
@property({ type: Node, tooltip: "天赋列表容器,用于动态添加天赋项" })
talents_content: Node = null!;
@property({ type: Prefab, tooltip: "" })
prefab_talent_item: Prefab = null!;
@property({ type: Button, tooltip: "看广告重置天赋按钮" })
btn_reset: Button = null!;
@property({ type: Button, tooltip: "返回按钮" })
btn_close: Button = null!;
/** 调试日志开关 */
debugMode: boolean = false;
/** 最大玩家等级 */
private readonly MAX_PLAYER_LEVEL = 30;
protected onLoad(): void {
if (this.btn_reset && this.btn_reset.node) {
this.btn_reset.node.on(Button.EventType.CLICK, this.onResetClicked, this);
}
if (this.btn_close && this.btn_close.node) {
this.btn_close.node.on(Button.EventType.CLICK, this.onCloseClicked, this);
}
}
protected onEnable(): void {
this.refreshUI();
}
/** 刷新整体界面 */
private refreshUI() {
this.updatePlayerInfo();
this.updateTalentList();
}
/** 更新玩家等级、经验、金币信息 */
private updatePlayerInfo() {
const collection = smc.collection;
let level = collection.player_level || 1;
let exp = collection.player_exp || 0;
// 限制最大等级
if (level > this.MAX_PLAYER_LEVEL) {
level = this.MAX_PLAYER_LEVEL;
}
if (this.lbl_level) this.lbl_level.string = `Lv.${level}`;
if (this.lbl_points) this.lbl_points.string = `金币: ${smc.vmdata.gold}`;
// 计算当前等级升级所需经验
let expRequired = this.getExpRequirement(level);
if (level >= this.MAX_PLAYER_LEVEL) {
if (this.lbl_exp) this.lbl_exp.string = "已满级";
if (this.pb_exp) this.pb_exp.progress = 1;
} else {
if (this.lbl_exp) this.lbl_exp.string = `${exp}/${expRequired}`;
if (this.pb_exp) this.pb_exp.progress = exp / expRequired;
}
}
/** 获取对应等级的升级所需经验 */
private getExpRequirement(level: number): number {
for (let config of TalentConfig.expRequirements) {
if (level <= config.maxLevel) {
return config.expPerLevel;
}
}
return TalentConfig.expRequirements[TalentConfig.expRequirements.length - 1].expPerLevel;
}
/** 动态生成或更新天赋列表 */
private updateTalentList() {
if (!this.talents_content || !this.prefab_talent_item) return;
const collection = smc.collection;
// 如果内容为空,则实例化预制体
if (this.talents_content.children.length === 0) {
TalentConfig.talents.forEach(talentInfo => {
let itemNode = instantiate(this.prefab_talent_item);
this.talents_content.addChild(itemNode);
let comp = itemNode.getComponent(TalentItemComp);
if (comp) {
comp.updateItem(talentInfo, collection.talents[talentInfo.id as TalentType], this.onUpgradeClicked.bind(this));
}
});
} else {
// 否则直接更新现有节点
TalentConfig.talents.forEach((talentInfo, index) => {
let itemNode = this.talents_content.children[index];
if (itemNode) {
let comp = itemNode.getComponent(TalentItemComp);
if (comp) {
comp.updateItem(talentInfo, collection.talents[talentInfo.id as TalentType], this.onUpgradeClicked.bind(this));
}
}
});
}
}
/** 点击升级按钮 */
private onUpgradeClicked(talentId: TalentType, currentLevel: number) {
const collection = smc.collection;
const talentInfo = TalentConfig.talents.find(t => t.id === talentId);
if (!talentInfo) {
oops.gui.toast("天赋配置不存在");
return;
}
if (currentLevel >= talentInfo.maxLevel) {
oops.gui.toast("该天赋已满级");
return;
}
const cost = talentInfo.costs[currentLevel] ?? 0;
if (smc.vmdata.gold >= cost) {
// 1. 扣除金币消耗
smc.updateGold(-cost);
// 2. 更新等级
collection.talents[talentId] = currentLevel + 1;
// 3. 同步数据(通过 SingletonModuleComp 新增的机制,这里会触发标记脏数据并自动尝试云端同步)
smc.updateCloudData();
// 4. 刷新 UI
this.refreshUI();
oops.gui.toast("天赋升级成功");
} else {
oops.gui.toast("金币不足");
}
}
/** 点击重置按钮 */
private onResetClicked() {
// 看广告回调(预留)
this.watch_ad().then(success => {
if (success) {
const collection = smc.collection;
// 计算已消耗金币并返还
let refundedGold = 0;
for (let id in collection.talents) {
let talentId = Number(id) as TalentType;
let level = collection.talents[talentId];
let talentInfo = TalentConfig.talents.find(t => t.id === talentId);
if (talentInfo) {
for (let i = 0; i < level; i++) {
refundedGold += talentInfo.costs[i] ?? 0;
}
}
}
// 重置天赋等级并返还金币
for (let k in collection.talents) {
collection.talents[k as any as TalentType] = 0;
}
if (refundedGold > 0) {
smc.updateGold(refundedGold);
}
// 同步到云端
smc.updateCloudData();
// 刷新界面
this.refreshUI();
oops.gui.toast("天赋已重置,金币已返还");
} else {
oops.gui.toast("广告观看失败,无法重置");
}
});
}
/** 模拟看广告回调实际项目中需要替换为真实的广告SDK调用 */
private watch_ad(): Promise<boolean> {
return new Promise((resolve) => {
// 模拟广告播放延迟
setTimeout(() => {
resolve(true);
}, 500);
});
}
/** 点击返回按钮 */
private onCloseClicked() {
this.node.active = false
}
protected onDestroy(): void {
super.onDestroy();
mLogger.log(this.debugMode, 'TalentsComp', "释放界面");
if (this.btn_reset && this.btn_reset.node && this.btn_reset.node.isValid) {
this.btn_reset.node.off(Button.EventType.CLICK, this.onResetClicked, this);
}
if (this.btn_close && this.btn_close.node && this.btn_close.node.isValid) {
this.btn_close.node.off(Button.EventType.CLICK, this.onCloseClicked, this);
}
}
/** ECS 组件移除时销毁节点 */
reset() {
this.node.destroy();
}
}