/** * @file TalentsComp.ts * @description 天赋加点页组件(UI 视图层,最小容器) * * 职责: * 1. 页头展示:可用天赋点 / 天赋等级(Lv.x)/ 当前等级经验进度。 * 2. 收集子树内全部 TalentItemComp(编辑器静态摆放),TALENT_UPDATE 事件驱动全量刷新。 * 3. 卡片点击统一打开 TIBox 天赋详情弹窗;加点校验(层位/前置/满级/点数)由 TIBoxComp 内聚, * 不满足条件时弹窗隐藏加点按钮,仅作详情查看。 * 4. 看广告重置入口:CommonPrompt 二次确认后调 smc.resetTalents() 退还全部点数。 * * 依赖: * - TalentSet(getTalentTierInvestedPoints/getTalentLevelExp)—— 配置与统计 * - TalentItemComp —— 单张迷你升级卡(编辑器静态摆放,按 uuid 自驱动渲染) * - TIBoxComp —— 天赋详情弹窗(UIID.TIBox) * - smc —— 天赋等级表/点数/升级/重置 */ import { _decorator, Label, Node, NodeEventType, ProgressBar } 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 { getTalentLevelExp, getTalentTierInvestedPoints, } from "../common/config/TalentSet"; import { GameEvent } from "../common/config/GameEvent"; import { UIID } from "../common/config/GameUIConfig"; import { TalentItemComp } from "./TalentItemComp"; import { smc } from "../common/SingletonModuleComp"; import { oops } from "db://oops-framework/core/Oops"; const { ccclass, property } = _decorator; /** TalentsComp —— 天赋加点页组件(最小容器:页头 + 编辑器静态卡片收集) */ @ccclass('TalentsComp') @ecs.register('Talents', false) export class TalentsComp extends CCComp { @property({ type: Label, tooltip: "页头可用天赋点" }) lbl_points: Label = null!; @property({ type: Label, tooltip: "天赋等级文案(Lv.x 样式)" }) lbl_lv: Label = null!; @property({ type: ProgressBar, tooltip: "当前等级经验进度条" }) progress_exp: ProgressBar = null!; @property({ type: Label, tooltip: "当前等级经验数值(当前经验/升级所需经验)" }) lbl_exp: Label = null!; @property({ type: Node, tooltip: "看广告重置按钮" }) btn_reset: Node = null!; /** 页内全部天赋卡(onLoad 时自动收集子树内所有 TalentItemComp,无需编辑器拖引) */ private talent_items: TalentItemComp[] = []; protected onLoad(): void { this.talent_items = this.node.getComponentsInChildren(TalentItemComp); for (const item of this.talent_items) { item.onTalentTap = (uuid: number) => this.onTalentTap(uuid); } this.btn_reset?.on(NodeEventType.TOUCH_END, this.onResetTap, this); } protected onEnable(): void { // 升级/重置/加点变动统一走 TALENT_UPDATE 事件驱动全量刷新 oops.message.on(GameEvent.TALENT_UPDATE, this.refreshUI, this); this.refreshUI(); } protected onDisable(): void { oops.message.off(GameEvent.TALENT_UPDATE, this.refreshUI, this); } protected onDestroy(): void { this.btn_reset?.targetOff(this); } /** 全量刷新:页头点数 + 天赋等级/经验 + 全部静态卡片 */ public refreshUI(): void { const levels = smc.getTalentLevels(); if (this.lbl_points) { // 剩余/总点数:总点数 = 剩余 + 各层已投入 const remaining = smc.getTalentPoints(); let invested = 0; for (let tier = 1; tier <= 5; tier++) { invested += getTalentTierInvestedPoints(levels, tier); } this.lbl_points.string = `${remaining}/${remaining + invested}`; } // 天赋等级(Lv.x)与当前等级经验进度 const talentLv = smc.getTalentLevel(); if (this.lbl_lv) this.lbl_lv.string = `Lv.${talentLv}`; if (this.progress_exp) { const needExp = getTalentLevelExp(talentLv); // 满级后进度条显示为满 this.progress_exp.progress = needExp > 0 ? Math.min(1, smc.getTalentExp() / needExp) : 1; } if (this.lbl_exp) { const needExp = getTalentLevelExp(talentLv); // 满级后显示为 0/0,避免分母为 0 this.lbl_exp.string = needExp > 0 ? `${smc.getTalentExp()}/${needExp}` : `0/0`; } for (const item of this.talent_items) { item.updateItem(); } } /** * 卡片点击统一入口:任何状态均打开 TIBox 天赋详情弹窗,加点按钮显隐由 TIBoxComp 校验 * @param uuid 天赋 uuid */ private onTalentTap(uuid: number): void { oops.gui.open(UIID.TIBox, { uuid }); } /** 看广告重置入口:CommonPrompt 二次确认(广告接入前先直接确认重置) */ private onResetTap(): void { oops.gui.open(UIID.Window, { title: "重置天赋", content: "观看广告后重置所有天赋等级,并全额退还已消耗的天赋点。是否继续?", okWord: "重置", cancelWord: "取消", needCancel: true, okFunc: () => smc.resetTalents(), }); } /** ECS 组件移除时销毁节点 */ reset() { this.node.destroy(); } }