refactor(talent): 拆分天赋项组件并适配精灵图标
将原TalentsComp内的单个天赋项UI更新逻辑抽离为独立的TalentItemComp组件实现代码解耦,更新天赋配置将emoji图标替换为精灵图集资源键,重构TalentsComp的天赋列表渲染逻辑适配新的组件化方案
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -44,27 +44,27 @@ export const TalentConfig = {
|
|||||||
|
|
||||||
// 所有天赋定义(使用数组维护)
|
// 所有天赋定义(使用数组维护)
|
||||||
talents: [
|
talents: [
|
||||||
{ id: TalentType.Attack, name: "攻击", icon: "⚔️", desc: "+{value}%",
|
{ id: TalentType.Attack, name: "攻击", icon: "1006", desc: "+{value}%",
|
||||||
maxLevel: 5, values: [3, 6, 9, 12, 15], costs: [1, 1, 2, 2, 3] },
|
maxLevel: 5, values: [3, 6, 9, 12, 15], costs: [1, 1, 2, 2, 3] },
|
||||||
{ id: TalentType.Hp, name: "生命", icon: "❤️", desc: "+{value}%",
|
{ id: TalentType.Hp, name: "生命", icon: "1006", desc: "+{value}%",
|
||||||
maxLevel: 5, values: [5, 10, 15, 20, 25], costs: [1, 1, 2, 2, 3] },
|
maxLevel: 5, values: [5, 10, 15, 20, 25], costs: [1, 1, 2, 2, 3] },
|
||||||
{ id: TalentType.Critical, name: "暴击率", icon: "🔥", desc: "+{value}%",
|
{ id: TalentType.Critical, name: "暴击率", icon: "1006", desc: "+{value}%",
|
||||||
maxLevel: 5, values: [2, 4, 6, 8, 10], costs: [1, 1, 2, 2, 3] },
|
maxLevel: 5, values: [2, 4, 6, 8, 10], costs: [1, 1, 2, 2, 3] },
|
||||||
{ id: TalentType.WindFury, name: "风怒率", icon: "⚡", desc: "+{value}%",
|
{ id: TalentType.WindFury, name: "风怒率", icon: "1006", desc: "+{value}%",
|
||||||
maxLevel: 5, values: [2, 4, 6, 8, 10], costs: [1, 1, 2, 2, 3] },
|
maxLevel: 5, values: [2, 4, 6, 8, 10], costs: [1, 1, 2, 2, 3] },
|
||||||
{ id: TalentType.Freeze, name: "冰冻率", icon: "❄️", desc: "+{value}%",
|
{ id: TalentType.Freeze, name: "冰冻率", icon: "1006", desc: "+{value}%",
|
||||||
maxLevel: 5, values: [2, 4, 6, 8, 10], costs: [1, 1, 2, 2, 3] },
|
maxLevel: 5, values: [2, 4, 6, 8, 10], costs: [1, 1, 2, 2, 3] },
|
||||||
{ id: TalentType.Puncture, name: "穿刺", icon: "🗡️", desc: "+{value}",
|
{ id: TalentType.Puncture, name: "穿刺", icon: "1006", desc: "+{value}",
|
||||||
maxLevel: 5, values: [0.2, 0.4, 0.6, 0.8, 1.0], costs: [1, 1, 2, 2, 3] },
|
maxLevel: 5, values: [0.2, 0.4, 0.6, 0.8, 1.0], costs: [1, 1, 2, 2, 3] },
|
||||||
{ id: TalentType.DeadTrigger, name: "亡语额外触发", icon: "🛡️", desc: "+{value}次",
|
{ id: TalentType.DeadTrigger, name: "亡语额外触发", icon: "1006", desc: "+{value}次",
|
||||||
maxLevel: 1, values: [1], costs: [25] },
|
maxLevel: 1, values: [1], costs: [25] },
|
||||||
{ id: TalentType.Summon, name: "召唤额外触发", icon: "🛡️", desc: "+{value}次",
|
{ id: TalentType.Summon, name: "召唤额外触发", icon: "1006", desc: "+{value}次",
|
||||||
maxLevel: 1, values: [1], costs: [25] },
|
maxLevel: 1, values: [1], costs: [25] },
|
||||||
{ id: TalentType.BuyDiscount, name: "购买优惠", icon: "🛒", desc: "-{value}金币",
|
{ id: TalentType.BuyDiscount, name: "购买优惠", icon: "1006", desc: "-{value}金币",
|
||||||
maxLevel: 1, values: [1], costs: [10] },
|
maxLevel: 1, values: [1], costs: [10] },
|
||||||
{ id: TalentType.RefreshDiscount, name: "刷新优惠", icon: "🔄", desc: "-{value}金币",
|
{ id: TalentType.RefreshDiscount, name: "刷新优惠", icon: "1006", desc: "-{value}金币",
|
||||||
maxLevel: 1, values: [1], costs: [10] },
|
maxLevel: 1, values: [1], costs: [10] },
|
||||||
{ id: TalentType.SellBonus, name: "出售返还", icon: "💰", desc: "+{value}金币",
|
{ id: TalentType.SellBonus, name: "出售返还", icon: "1006", desc: "+{value}金币",
|
||||||
maxLevel: 1, values: [1], costs: [10] }
|
maxLevel: 1, values: [1], costs: [10] }
|
||||||
] as TalentInfo[]
|
] as TalentInfo[]
|
||||||
};
|
};
|
||||||
|
|||||||
115
assets/script/game/map/TalentItemComp.ts
Normal file
115
assets/script/game/map/TalentItemComp.ts
Normal file
@@ -0,0 +1,115 @@
|
|||||||
|
/**
|
||||||
|
* @file TalentItemComp.ts
|
||||||
|
* @description 单个天赋项组件
|
||||||
|
*/
|
||||||
|
import { _decorator, Node, Label, Button, resources, SpriteAtlas, Sprite } 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 { TalentInfo, TalentType } from "../common/config/TalentSet";
|
||||||
|
import { smc } from "../common/SingletonModuleComp";
|
||||||
|
|
||||||
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
|
@ccclass('TalentItemComp')
|
||||||
|
@ecs.register('TalentItem', false)
|
||||||
|
export class TalentItemComp extends CCComp {
|
||||||
|
|
||||||
|
@property({ type: Label, tooltip: "天赋名称" })
|
||||||
|
lbl_name: Label = null!;
|
||||||
|
|
||||||
|
@property({ type: Node, tooltip: "图标节点" })
|
||||||
|
icon_node: Node = null!;
|
||||||
|
|
||||||
|
@property({ type: Label, tooltip: "描述" })
|
||||||
|
lbl_desc: Label = null!;
|
||||||
|
|
||||||
|
@property({ type: Label, tooltip: "等级进度" })
|
||||||
|
lbl_level: Label = null!;
|
||||||
|
|
||||||
|
@property({ type: Label, tooltip: "升级消耗" })
|
||||||
|
lbl_cost: Label = null!;
|
||||||
|
|
||||||
|
@property({ type: Button, tooltip: "升级按钮" })
|
||||||
|
btn_upgrade: Button = null!;
|
||||||
|
|
||||||
|
@property({ type: Node, tooltip: "背景" })
|
||||||
|
item_bg: Node = null!;
|
||||||
|
|
||||||
|
@property({ type: Node, tooltip: "图标背景" })
|
||||||
|
icon_bg: Node = null!;
|
||||||
|
|
||||||
|
private _talentId: TalentType = TalentType.Attack;
|
||||||
|
private _onClickCallback: ((talentId: TalentType, currentLevel: number) => void) | null = null;
|
||||||
|
private _currentLevel: number = 0;
|
||||||
|
|
||||||
|
protected onLoad(): void {
|
||||||
|
if (this.btn_upgrade && this.btn_upgrade.node) {
|
||||||
|
this.btn_upgrade.node.on(Button.EventType.CLICK, this.onUpgradeClicked, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新天赋项显示
|
||||||
|
* @param talentInfo 天赋配置数据
|
||||||
|
* @param currentLevel 当前等级
|
||||||
|
* @param onClickCallback 点击升级按钮的回调
|
||||||
|
*/
|
||||||
|
public updateItem(talentInfo: TalentInfo, currentLevel: number, onClickCallback: (talentId: TalentType, currentLevel: number) => void) {
|
||||||
|
this._talentId = talentInfo.id;
|
||||||
|
this._currentLevel = currentLevel;
|
||||||
|
this._onClickCallback = onClickCallback;
|
||||||
|
|
||||||
|
if (this.lbl_name) {
|
||||||
|
this.lbl_name.string = talentInfo.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.icon_node && talentInfo.icon) {
|
||||||
|
resources.load("gui/uicons", SpriteAtlas, (err, atlas) => {
|
||||||
|
if (err || !atlas) return;
|
||||||
|
const frame = atlas.getSpriteFrame(talentInfo.icon!);
|
||||||
|
if (frame && this.icon_node && this.icon_node.isValid) {
|
||||||
|
const sprite = this.icon_node.getComponent(Sprite) || this.icon_node.addComponent(Sprite);
|
||||||
|
sprite.spriteFrame = frame;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.lbl_desc) {
|
||||||
|
let currentVal = currentLevel === 0 ? 0 : talentInfo.values[currentLevel - 1];
|
||||||
|
this.lbl_desc.string = talentInfo.desc.replace('{value}', currentVal.toString());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.lbl_level) {
|
||||||
|
this.lbl_level.string = `${currentLevel}/${talentInfo.maxLevel}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
let isMax = currentLevel >= talentInfo.maxLevel;
|
||||||
|
let cost = isMax ? 0 : (talentInfo.costs[currentLevel] ?? 0);
|
||||||
|
let canUpgrade = !isMax && smc.vmdata.gold >= cost;
|
||||||
|
|
||||||
|
if (this.lbl_cost) {
|
||||||
|
this.lbl_cost.string = isMax ? "已满级" : `${cost}`;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (this.btn_upgrade) {
|
||||||
|
this.btn_upgrade.interactable = canUpgrade;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private onUpgradeClicked() {
|
||||||
|
if (this._onClickCallback) {
|
||||||
|
this._onClickCallback(this._talentId, this._currentLevel);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected onDestroy(): void {
|
||||||
|
if (this.btn_upgrade && this.btn_upgrade.node && this.btn_upgrade.node.isValid) {
|
||||||
|
this.btn_upgrade.node.off(Button.EventType.CLICK, this.onUpgradeClicked, this);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/** ECS 组件移除时销毁节点 */
|
||||||
|
reset() {
|
||||||
|
this.node.destroy();
|
||||||
|
}
|
||||||
|
}
|
||||||
9
assets/script/game/map/TalentItemComp.ts.meta
Normal file
9
assets/script/game/map/TalentItemComp.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "fa67fd78-9a5e-4a57-b8a7-50475a5ed963",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -25,6 +25,7 @@ import { mLogger } from "../common/Logger";
|
|||||||
import { smc } from "../common/SingletonModuleComp";
|
import { smc } from "../common/SingletonModuleComp";
|
||||||
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
|
import { oops } from "../../../../extensions/oops-plugin-framework/assets/core/Oops";
|
||||||
import { TalentConfig, TalentInfo, TalentType } from "../common/config/TalentSet";
|
import { TalentConfig, TalentInfo, TalentType } from "../common/config/TalentSet";
|
||||||
|
import { TalentItemComp } from "./TalentItemComp";
|
||||||
|
|
||||||
const { ccclass, property } = _decorator;
|
const { ccclass, property } = _decorator;
|
||||||
|
|
||||||
@@ -59,7 +60,7 @@ export class TalentsComp extends CCComp {
|
|||||||
@property({ type: Node, tooltip: "天赋列表容器,用于动态添加天赋项" })
|
@property({ type: Node, tooltip: "天赋列表容器,用于动态添加天赋项" })
|
||||||
talents_content: Node = null!;
|
talents_content: Node = null!;
|
||||||
|
|
||||||
@property({ type: Prefab, tooltip: "天赋项预制体\n预制体结构要求:\n- 根节点\n - lbl_name (Label): 天赋名称\n - lbl_desc (Label): 天赋描述\n - lbl_level (Label): 当前等级\n - lbl_cost (Label): 升级消耗\n - btn_upgrade (Button): 升级按钮\n - pb_level (ProgressBar或一组节点): 等级进度展示(可选)" })
|
@property({ type: Prefab, tooltip: "" })
|
||||||
prefab_talent_item: Prefab = null!;
|
prefab_talent_item: Prefab = null!;
|
||||||
|
|
||||||
@property({ type: Button, tooltip: "看广告重置天赋按钮" })
|
@property({ type: Button, tooltip: "看广告重置天赋按钮" })
|
||||||
@@ -143,57 +144,25 @@ export class TalentsComp extends CCComp {
|
|||||||
TalentConfig.talents.forEach(talentInfo => {
|
TalentConfig.talents.forEach(talentInfo => {
|
||||||
let itemNode = instantiate(this.prefab_talent_item);
|
let itemNode = instantiate(this.prefab_talent_item);
|
||||||
this.talents_content.addChild(itemNode);
|
this.talents_content.addChild(itemNode);
|
||||||
this.updateTalentItem(itemNode, talentInfo, collection.talents[talentInfo.id as TalentType]);
|
let comp = itemNode.getComponent(TalentItemComp);
|
||||||
|
if (comp) {
|
||||||
|
comp.updateItem(talentInfo, collection.talents[talentInfo.id as TalentType], this.onUpgradeClicked.bind(this));
|
||||||
|
}
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
// 否则直接更新现有节点
|
// 否则直接更新现有节点
|
||||||
TalentConfig.talents.forEach((talentInfo, index) => {
|
TalentConfig.talents.forEach((talentInfo, index) => {
|
||||||
let itemNode = this.talents_content.children[index];
|
let itemNode = this.talents_content.children[index];
|
||||||
if (itemNode) {
|
if (itemNode) {
|
||||||
this.updateTalentItem(itemNode, talentInfo, collection.talents[talentInfo.id as TalentType]);
|
let comp = itemNode.getComponent(TalentItemComp);
|
||||||
|
if (comp) {
|
||||||
|
comp.updateItem(talentInfo, collection.talents[talentInfo.id as TalentType], this.onUpgradeClicked.bind(this));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 更新单个天赋项的显示 */
|
|
||||||
private updateTalentItem(itemNode: Node, talentInfo: TalentInfo, currentLevel: number) {
|
|
||||||
let lblName = itemNode.getChildByName("lbl_name")?.getComponent(Label);
|
|
||||||
let lblDesc = itemNode.getChildByName("lbl_desc")?.getComponent(Label);
|
|
||||||
let lblLevel = itemNode.getChildByName("lbl_level")?.getComponent(Label);
|
|
||||||
let lblCost = itemNode.getChildByName("lbl_cost")?.getComponent(Label);
|
|
||||||
let btnUpgradeNode = itemNode.getChildByName("btn_upgrade");
|
|
||||||
let btnUpgrade = btnUpgradeNode?.getComponent(Button);
|
|
||||||
|
|
||||||
if (lblName) {
|
|
||||||
lblName.string = (talentInfo.icon ? `${talentInfo.icon} ` : '') + talentInfo.name;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lblDesc) {
|
|
||||||
let currentVal = currentLevel === 0 ? 0 : talentInfo.values[currentLevel - 1];
|
|
||||||
lblDesc.string = talentInfo.desc.replace('{value}', currentVal.toString());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (lblLevel) lblLevel.string = `${currentLevel}/${talentInfo.maxLevel}`;
|
|
||||||
|
|
||||||
let isMax = currentLevel >= talentInfo.maxLevel;
|
|
||||||
let cost = isMax ? 0 : (talentInfo.costs[currentLevel] ?? 0);
|
|
||||||
let canUpgrade = !isMax && smc.vmdata.gold >= cost;
|
|
||||||
|
|
||||||
if (lblCost) {
|
|
||||||
lblCost.string = isMax ? "已满级" : `${cost}`;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (btnUpgrade) {
|
|
||||||
btnUpgrade.interactable = canUpgrade;
|
|
||||||
// 清除旧的监听,避免重复绑定
|
|
||||||
btnUpgradeNode?.off(Button.EventType.CLICK);
|
|
||||||
btnUpgradeNode?.on(Button.EventType.CLICK, () => {
|
|
||||||
this.onUpgradeClicked(talentInfo.id, currentLevel);
|
|
||||||
}, this);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/** 点击升级按钮 */
|
/** 点击升级按钮 */
|
||||||
private onUpgradeClicked(talentId: TalentType, currentLevel: number) {
|
private onUpgradeClicked(talentId: TalentType, currentLevel: number) {
|
||||||
const collection = smc.collection;
|
const collection = smc.collection;
|
||||||
|
|||||||
Reference in New Issue
Block a user