1. 新增HeroInfoComp英雄详情弹窗,支持英雄属性展示、升级操作、前后切换功能 2. 重构HerosListComp图鉴页面,将详情面板逻辑剥离至弹窗,点击卡片直接打开详情页 3. 新增英雄列表排序工具函数,统一图鉴与弹窗切换的排序逻辑 4. 优化战斗渲染排序逻辑,移除无关的Y轴渲染权重计算 5. 新增英雄详情弹窗UI配置与预制体资源
151 lines
4.9 KiB
TypeScript
151 lines
4.9 KiB
TypeScript
/**
|
||
* @file HerosListComp.ts
|
||
* @description 英雄图鉴页面(UI 视图层)
|
||
*
|
||
* 职责:
|
||
* 1. 以卡片列表形式展示所有可用英雄(使用 CardLiteComp 预制体)。
|
||
* 2. 点击卡片打开英雄详情弹窗(UIID.HeroInfo),详情/升级在 HeroInfoComp 中处理。
|
||
* 3. 卡片排序:可升级优先 → 现有等级降序 → 品质降序(getSortedHeroList)。
|
||
*
|
||
* 关键设计:
|
||
* - cards_node 为卡片容器,通过 instantiate(card_lite_prefab) 动态生成卡片。
|
||
* - 升级/碎片变动后通过 HERO_GROWTH_UPDATE 事件统一刷新所有卡片的可升级标识。
|
||
* - 详情面板已从本组件剥离,由 HeroInfoComp 承载。
|
||
*
|
||
* 依赖:
|
||
* - getSortedHeroList(heroUpSet)—— 图鉴排序
|
||
* - CardLiteComp —— 轻量卡片组件
|
||
* - UIID.HeroInfo(oops.gui)—— 英雄详情弹窗
|
||
*/
|
||
import { _decorator, Node, Prefab, UITransform, instantiate } 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 { oops } from "db://oops-framework/core/Oops";
|
||
import { mLogger } from "../common/Logger";
|
||
import { HeroInfo, HeroList } from "../common/config/heroSet";
|
||
import { GameEvent } from "../common/config/GameEvent";
|
||
import { getSortedHeroList } from "../common/config/heroUpSet";
|
||
import { UIID } from "../common/config/GameUIConfig";
|
||
import { CardLiteComp } from "./CardLiteComp";
|
||
import { smc } from "../common/SingletonModuleComp";
|
||
|
||
const { property, ccclass } = _decorator;
|
||
|
||
@ccclass('HerosListComp')
|
||
@ecs.register('HerosListComp', false)
|
||
export class HerosListComp extends CCComp {
|
||
// ======================== 编辑器绑定节点 ========================
|
||
|
||
@property(Node)
|
||
cards_node = null!
|
||
|
||
@property(Prefab)
|
||
card_lite_prefab = null!
|
||
|
||
/** 卡片宽度 */
|
||
@property
|
||
card_w = 120
|
||
|
||
/** 卡片横向间隔 */
|
||
@property
|
||
spacing_x = 10
|
||
|
||
/** 卡片左右边距 */
|
||
@property
|
||
margin_x = 15
|
||
|
||
// ======================== 运行时状态 ========================
|
||
|
||
debugMode: boolean = false
|
||
|
||
start() {
|
||
this.initCardList()
|
||
}
|
||
|
||
protected onEnable(): void {
|
||
oops.message.on(GameEvent.HERO_GROWTH_UPDATE, this.onGrowthUpdate, this)
|
||
}
|
||
|
||
protected onDisable(): void {
|
||
oops.message.off(GameEvent.HERO_GROWTH_UPDATE, this.onGrowthUpdate, this)
|
||
}
|
||
|
||
private onGrowthUpdate() {
|
||
this.refreshAllCardsCanUp()
|
||
}
|
||
|
||
/** 升级/碎片变动后统一刷新所有卡片的可升级标识与等级数字 */
|
||
private refreshAllCardsCanUp() {
|
||
if (!this.cards_node) return
|
||
this.cards_node.children.forEach(cardNode => {
|
||
const comp = cardNode.getComponent(CardLiteComp)
|
||
comp?.refreshCanUp()
|
||
comp?.refreshLv()
|
||
})
|
||
}
|
||
|
||
closeHeros() {
|
||
this.node.active = false
|
||
}
|
||
|
||
// ======================== 卡片列表 ========================
|
||
|
||
private initCardList() {
|
||
if (!this.cards_node || !this.card_lite_prefab) return
|
||
|
||
this.cards_node.removeAllChildren()
|
||
|
||
// 排序与详情面板"前后切换"同源(getSortedHeroList),保证两个入口顺序一致
|
||
const sorted = getSortedHeroList(uuid => smc.getHeroGrowth(uuid))
|
||
|
||
for (const uuid of sorted) {
|
||
const hero = HeroInfo[uuid]
|
||
if (!hero) continue
|
||
|
||
const cardNode = instantiate(this.card_lite_prefab)
|
||
cardNode.name = `card_${uuid}`
|
||
|
||
const comp = cardNode.getComponent(CardLiteComp) || cardNode.addComponent(CardLiteComp)
|
||
comp.setHeroByUuid(uuid)
|
||
comp.onClickCallback = () => {
|
||
// 点击卡片:打开英雄详情弹窗(详情/升级/前后切换由 HeroInfoComp 承载)
|
||
oops.audio.playEffect("music/button");
|
||
oops.gui.open(UIID.HeroInfo, { uuid })
|
||
}
|
||
|
||
this.cards_node.addChild(cardNode)
|
||
}
|
||
|
||
mLogger.log(this.debugMode, "HerosListComp", "initCardList done", {
|
||
totalChildren: this.cards_node.children.length,
|
||
})
|
||
|
||
this.updateContentSize()
|
||
}
|
||
|
||
private updateContentSize() {
|
||
const total = this.cards_node.children.length
|
||
if (total === 0) return
|
||
|
||
// 宽度 = 卡片总宽 + 卡片间隔 + 左右边距
|
||
const contentW = total * this.card_w
|
||
+ (total - 1) * this.spacing_x
|
||
+ this.margin_x * 2
|
||
|
||
const cols = 4
|
||
const rows = Math.ceil(total / cols)
|
||
const cardH = 200
|
||
const spacingY = 10
|
||
const contentH = Math.max(1000, rows * (cardH + spacingY) + 50)
|
||
|
||
const uiTrans = this.cards_node.getComponent(UITransform)
|
||
if (uiTrans) {
|
||
uiTrans.setContentSize(contentW, contentH)
|
||
}
|
||
}
|
||
|
||
reset() {
|
||
this.node.destroy()
|
||
}
|
||
}
|