refactor(hero system): 重构英雄升级与卡片展示逻辑
1. 重构英雄升级方法,移除外部传入所需碎片参数,改为从配置表自动读取 2. 简化CardLiteComp.setHeroByUuid,移除卡池等级参数,直接读取英雄静态配置 3. 新增ChipComp.setHeroIconByUuid,重构英雄图标渲染逻辑 4. 新增英雄详情面板的升级功能与碎片展示 5. 新增英雄成长变化的事件监听与面板刷新逻辑
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@@ -8,7 +8,7 @@ import { GameEvent } from "./config/GameEvent";
|
|||||||
import { GameScoreStats } from "./config/HeroAttrs";
|
import { GameScoreStats } from "./config/HeroAttrs";
|
||||||
import { mLogger } from "./Logger";
|
import { mLogger } from "./Logger";
|
||||||
import { gameDataSync } from "./GameDataSync";
|
import { gameDataSync } from "./GameDataSync";
|
||||||
import { FightSet } from "./config/GameSet";
|
import { FightSet, HERO_UPGRADE_NEED_FRAGMENTS } from "./config/GameSet";
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 用远程数据覆盖本地数据(统一方法)
|
* 用远程数据覆盖本地数据(统一方法)
|
||||||
@@ -351,13 +351,15 @@ export class SingletonModuleComp extends ecs.Comp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 消耗碎片提升英雄局外等级
|
* 消耗碎片提升英雄局外等级(内部查表决定所需碎片数)
|
||||||
* @param uuid 英雄模板 uuid
|
* @param uuid 英雄模板 uuid
|
||||||
* @param needFragments 本次升级所需碎片数量(由外部配置表计算)
|
* @returns 是否升级成功(已到满级或碎片不足时返回 false)
|
||||||
* @returns 是否升级成功
|
|
||||||
*/
|
*/
|
||||||
upgradeHero(uuid: number, needFragments: number): boolean {
|
upgradeHero(uuid: number): boolean {
|
||||||
const growth = this.getHeroGrowth(uuid);
|
const growth = this.getHeroGrowth(uuid);
|
||||||
|
const needFragments = HERO_UPGRADE_NEED_FRAGMENTS[growth.lv + 1];
|
||||||
|
// 配置表中查不到下一级 = 已到满级
|
||||||
|
if (needFragments === undefined) return false;
|
||||||
if (growth.fragments < needFragments) return false;
|
if (growth.fragments < needFragments) return false;
|
||||||
growth.fragments -= needFragments;
|
growth.fragments -= needFragments;
|
||||||
growth.lv += 1;
|
growth.lv += 1;
|
||||||
|
|||||||
@@ -112,30 +112,23 @@ export class CardLiteComp extends CCComp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 便捷方法:通过英雄 UUID 和卡池等级直接设置英雄卡。
|
* 通过英雄 UUID 直接设置英雄卡(纯展示场景)。
|
||||||
* 自动从 CardPoolList 查找匹配的卡牌配置。
|
* 从 HeroInfo 读取静态配置,不再依赖 CardPoolList。
|
||||||
* @param uuid 英雄 UUID
|
* @param uuid 英雄 UUID
|
||||||
* @param cardLv 卡牌等级(默认 1)
|
|
||||||
*/
|
*/
|
||||||
setHeroByUuid(uuid: number, cardLv: number = 1) {
|
setHeroByUuid(uuid: number) {
|
||||||
const card = CardPoolList.find(c => c.uuid === uuid && c.card_lv === cardLv);
|
|
||||||
if (card) {
|
|
||||||
this.setData(card);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const hero = HeroInfo[uuid];
|
const hero = HeroInfo[uuid];
|
||||||
if (hero) {
|
if (!hero) return;
|
||||||
this.setData({
|
this.setData({
|
||||||
uuid: hero.uuid,
|
uuid: hero.uuid,
|
||||||
type: CardType.Hero,
|
type: CardType.Hero,
|
||||||
cost: 5,
|
cost: 0,
|
||||||
weight: 25,
|
weight: 0,
|
||||||
card_lv: cardLv,
|
card_lv: hero.card_lv ?? 1,
|
||||||
kind: CKind.Hero,
|
kind: CKind.Hero,
|
||||||
hero_lv: smc.getHeroOuterLv(hero.uuid)
|
hero_lv: smc.getHeroOuterLv(hero.uuid)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** 查询当前是否有卡牌数据 */
|
/** 查询当前是否有卡牌数据 */
|
||||||
hasCard(): boolean {
|
hasCard(): boolean {
|
||||||
|
|||||||
@@ -79,39 +79,35 @@ export class ChipComp extends CCComp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 便捷方法:通过英雄 UUID 和卡池等级直接设置英雄卡。
|
* 通过英雄 UUID 直接渲染英雄图标(自动播放 idle 动画并应用背景)。
|
||||||
* 自动从 CardPoolList 查找匹配的卡牌配置。
|
* 适用于碎片、头像、图鉴等纯展示场景。
|
||||||
* @param uuid 英雄 UUID
|
* @param uuid 英雄 UUID
|
||||||
* @param cardLv 卡牌等级(默认 1)
|
|
||||||
*/
|
*/
|
||||||
setHeroByUuid(uuid: number, cardLv: number = 1) {
|
setHeroIconByUuid(uuid: number) {
|
||||||
const card = CardPoolList.find(c => c.uuid === uuid && c.card_lv === cardLv);
|
|
||||||
if (card) {
|
|
||||||
this.setData(card);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const hero = HeroInfo[uuid];
|
const hero = HeroInfo[uuid];
|
||||||
if (hero) {
|
if (!hero) return;
|
||||||
this.setData({
|
this.cardData = null;
|
||||||
uuid: hero.uuid,
|
this.card_uuid = uuid;
|
||||||
type: CardType.Hero,
|
this.card_type = CardType.Hero;
|
||||||
cost: 0,
|
this.node.active = true;
|
||||||
weight: 0,
|
this.iconVisualToken += 1;
|
||||||
card_lv: cardLv,
|
|
||||||
kind: CKind.Hero,
|
// 背景:按 HeroInfo.card_lv 应用英雄底框样式
|
||||||
hero_lv: smc.getHeroOuterLv(hero.uuid)
|
if (this.BG_node) {
|
||||||
|
const cardLv = hero.card_lv ?? 1;
|
||||||
|
const kindName = CKind[CKind.Hero];
|
||||||
|
this.BG_node.children.forEach(child => {
|
||||||
|
child.active = (child.name === kindName);
|
||||||
|
const bg = child.getComponent(CardBgComp);
|
||||||
|
if (bg) child.active ? bg.apply(cardLv) : bg.clear();
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/** 查询当前是否有卡牌数据 */
|
// 图标:英雄 idle 动画(带镜像翻转)
|
||||||
hasCard(): boolean {
|
if (this.icon_node) {
|
||||||
return !!this.cardData;
|
this.icon_node.setScale(new Vec3(-1.5, 1.5, 1));
|
||||||
|
this.updateHeroAnimation(this.icon_node, uuid, this.iconVisualToken);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 获取当前卡牌数据 */
|
|
||||||
getCardData(): CardConfig | null {
|
|
||||||
return this.cardData;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** 清空卡牌数据并重置 UI */
|
/** 清空卡牌数据并重置 UI */
|
||||||
|
|||||||
9
assets/script/game/map/ChipComp.ts.meta
Normal file
9
assets/script/game/map/ChipComp.ts.meta
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
{
|
||||||
|
"ver": "4.0.24",
|
||||||
|
"importer": "typescript",
|
||||||
|
"imported": true,
|
||||||
|
"uuid": "dc823f36-51eb-405f-8361-7027eb49c8a6",
|
||||||
|
"files": [],
|
||||||
|
"subMetas": {},
|
||||||
|
"userData": {}
|
||||||
|
}
|
||||||
@@ -25,8 +25,12 @@ import { mLogger } from "../common/Logger";
|
|||||||
import { HeroInfo, HeroList } from "../common/config/heroSet";
|
import { HeroInfo, HeroList } from "../common/config/heroSet";
|
||||||
import { buildSkillDesc } from "../common/config/HeroSkillDesc";
|
import { buildSkillDesc } from "../common/config/HeroSkillDesc";
|
||||||
import { CKind } from "../common/config/CardSet";
|
import { CKind } from "../common/config/CardSet";
|
||||||
|
import { GameEvent } from "../common/config/GameEvent";
|
||||||
|
import { HERO_UPGRADE_NEED_FRAGMENTS } from "../common/config/GameSet";
|
||||||
import { CardBgComp } from "./CardBgComp";
|
import { CardBgComp } from "./CardBgComp";
|
||||||
import { CardLiteComp } from "./CardLiteComp";
|
import { CardLiteComp } from "./CardLiteComp";
|
||||||
|
import { ChipComp } from "./ChipComp";
|
||||||
|
import { smc } from "../common/SingletonModuleComp";
|
||||||
|
|
||||||
const { property, ccclass } = _decorator;
|
const { property, ccclass } = _decorator;
|
||||||
|
|
||||||
@@ -41,6 +45,9 @@ export class HerosListComp extends CCComp {
|
|||||||
@property(Node)
|
@property(Node)
|
||||||
ap_node = null!
|
ap_node = null!
|
||||||
|
|
||||||
|
@property(Node)
|
||||||
|
def_node = null!
|
||||||
|
|
||||||
@property(Node)
|
@property(Node)
|
||||||
hp_node = null!
|
hp_node = null!
|
||||||
|
|
||||||
@@ -69,6 +76,18 @@ export class HerosListComp extends CCComp {
|
|||||||
@property(Node)
|
@property(Node)
|
||||||
type_node = null!
|
type_node = null!
|
||||||
|
|
||||||
|
/** 升级按钮节点 */
|
||||||
|
@property(Node)
|
||||||
|
upgrade_btn = null!
|
||||||
|
|
||||||
|
/** 碎片数量显示节点(Label) */
|
||||||
|
@property(Node)
|
||||||
|
fragment_node = null!
|
||||||
|
|
||||||
|
/** 碎片图标节点(挂载 ChipComp 用于渲染碎片图标) */
|
||||||
|
@property(Node)
|
||||||
|
chip_node = null!
|
||||||
|
|
||||||
// ======================== 运行时状态 ========================
|
// ======================== 运行时状态 ========================
|
||||||
|
|
||||||
huuid: number = 0
|
huuid: number = 0
|
||||||
@@ -84,15 +103,49 @@ export class HerosListComp extends CCComp {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected onEnable(): void {
|
protected onEnable(): void {
|
||||||
|
oops.message.on(GameEvent.HERO_GROWTH_UPDATE, this.onGrowthUpdate, this)
|
||||||
if (this.cards_node && this.cards_node.children.length > 0) {
|
if (this.cards_node && this.cards_node.children.length > 0) {
|
||||||
this.onCardSelect(this.huuid || HeroList[0])
|
this.onCardSelect(this.huuid || HeroList[0])
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected onDisable(): void {
|
||||||
|
oops.message.off(GameEvent.HERO_GROWTH_UPDATE, this.onGrowthUpdate, this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private onGrowthUpdate() {
|
||||||
|
if (this.huuid) {
|
||||||
|
this.updateHeroDetail(this.huuid)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
closeHeros() {
|
closeHeros() {
|
||||||
this.node.active = false
|
this.node.active = false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 升级按钮点击回调
|
||||||
|
* 消耗碎片提升英雄局外等级,成功后刷新详情面板
|
||||||
|
*/
|
||||||
|
onUpgradeClick() {
|
||||||
|
const uuid = this.huuid
|
||||||
|
if (!uuid) return
|
||||||
|
|
||||||
|
const success = smc.upgradeHero(uuid)
|
||||||
|
if (success) {
|
||||||
|
mLogger.log(this.debugMode, "HerosListComp", `英雄 ${uuid} 升级成功`)
|
||||||
|
this.updateHeroDetail(uuid)
|
||||||
|
} else {
|
||||||
|
const growth = smc.getHeroGrowth(uuid)
|
||||||
|
const need = HERO_UPGRADE_NEED_FRAGMENTS[growth.lv + 1]
|
||||||
|
mLogger.log(this.debugMode, "HerosListComp", `英雄 ${uuid} 升级失败`, {
|
||||||
|
currentLv: growth.lv,
|
||||||
|
fragments: growth.fragments,
|
||||||
|
needFragments: need ?? "MAX",
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ======================== 卡片列表 ========================
|
// ======================== 卡片列表 ========================
|
||||||
|
|
||||||
private initCardList() {
|
private initCardList() {
|
||||||
@@ -136,7 +189,7 @@ export class HerosListComp extends CCComp {
|
|||||||
})
|
})
|
||||||
|
|
||||||
const comp = cardNode.getComponent(CardLiteComp) || cardNode.addComponent(CardLiteComp)
|
const comp = cardNode.getComponent(CardLiteComp) || cardNode.addComponent(CardLiteComp)
|
||||||
comp.setHeroByUuid(uuid, hero.card_lv ?? 1)
|
comp.setHeroByUuid(uuid)
|
||||||
comp.onClickCallback = (cardComp: CardLiteComp) => {
|
comp.onClickCallback = (cardComp: CardLiteComp) => {
|
||||||
this.onCardSelect(uuid)
|
this.onCardSelect(uuid)
|
||||||
this.highlightCard(cardNode)
|
this.highlightCard(cardNode)
|
||||||
@@ -197,6 +250,7 @@ export class HerosListComp extends CCComp {
|
|||||||
const suffix = heroLv >= 2 ? "★".repeat(heroLv - 1) : ""
|
const suffix = heroLv >= 2 ? "★".repeat(heroLv - 1) : ""
|
||||||
this.setLabelText(this.name_node, `${suffix}${hero.name || ""}${suffix}`)
|
this.setLabelText(this.name_node, `${suffix}${hero.name || ""}${suffix}`)
|
||||||
this.setLabelText(this.ap_node, `${(hero.ap ?? 0) * heroLv}`)
|
this.setLabelText(this.ap_node, `${(hero.ap ?? 0) * heroLv}`)
|
||||||
|
this.setLabelText(this.def_node, `${(hero.def ?? 0) * heroLv}`)
|
||||||
this.setLabelText(this.hp_node, `${(hero.hp ?? 0) * heroLv}`)
|
this.setLabelText(this.hp_node, `${(hero.hp ?? 0) * heroLv}`)
|
||||||
|
|
||||||
this.updateCdDisplay(hero)
|
this.updateCdDisplay(hero)
|
||||||
@@ -213,6 +267,7 @@ export class HerosListComp extends CCComp {
|
|||||||
this.updateLvDisplay(hero)
|
this.updateLvDisplay(hero)
|
||||||
this.updateTypeDisplay(hero)
|
this.updateTypeDisplay(hero)
|
||||||
this.updateHeroAnimation(uuid)
|
this.updateHeroAnimation(uuid)
|
||||||
|
this.updateGrowthPanel(uuid)
|
||||||
}
|
}
|
||||||
|
|
||||||
private updatePoolLvBg(poolLv: number) {
|
private updatePoolLvBg(poolLv: number) {
|
||||||
@@ -261,6 +316,38 @@ export class HerosListComp extends CCComp {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 更新局外成长面板:碎片数量与升级按钮状态
|
||||||
|
* @param uuid 英雄模板 uuid
|
||||||
|
*/
|
||||||
|
private updateGrowthPanel(uuid: number) {
|
||||||
|
const growth = smc.getHeroGrowth(uuid)
|
||||||
|
const needFragments = HERO_UPGRADE_NEED_FRAGMENTS[growth.lv + 1]
|
||||||
|
const isMaxLv = needFragments === undefined
|
||||||
|
|
||||||
|
// 碎片数量显示:当前拥有 / 下一级所需(满级时显示 MAX)
|
||||||
|
if (this.fragment_node) {
|
||||||
|
const fragmentText = isMaxLv
|
||||||
|
? `${growth.fragments} / MAX`
|
||||||
|
: `${growth.fragments} / ${needFragments}`
|
||||||
|
this.setLabelText(this.fragment_node, fragmentText)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 碎片图标:使用 ChipComp 渲染英雄图标(自动读取 HeroInfo 配置)
|
||||||
|
if (this.chip_node) {
|
||||||
|
const chipComp = this.chip_node.getComponent(ChipComp) || this.chip_node.addComponent(ChipComp)
|
||||||
|
chipComp.setHeroIconByUuid(uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
// 升级按钮状态:未满级且碎片足够时可用
|
||||||
|
if (this.upgrade_btn) {
|
||||||
|
const canUpgrade = !isMaxLv && growth.fragments >= needFragments
|
||||||
|
this.upgrade_btn.active = true
|
||||||
|
const btnComp = this.upgrade_btn.getComponent("cc.Button") as import("cc").Button | null
|
||||||
|
if (btnComp) btnComp.interactable = canUpgrade
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// ======================== 英雄动画 ========================
|
// ======================== 英雄动画 ========================
|
||||||
|
|
||||||
private updateHeroAnimation(uuid: number) {
|
private updateHeroAnimation(uuid: number) {
|
||||||
|
|||||||
Reference in New Issue
Block a user