176 lines
5.7 KiB
TypeScript
176 lines
5.7 KiB
TypeScript
/**
|
||
* @file HerosListComp.ts
|
||
* @description 英雄图鉴页面(UI 视图层)
|
||
*
|
||
* 职责:
|
||
* 1. 以卡片列表形式展示所有可用英雄(使用 CardLiteComp 预制体)。
|
||
* 2. 点击卡片打开英雄详情弹窗(UIID.HeroInfo),详情/升级在 HeroInfoComp 中处理。
|
||
* 3. 卡片排序:仅按品质降序 → uuid 升序(与养成进度解耦,保持展示稳定)。
|
||
*
|
||
* 关键设计:
|
||
* - cards_node 为卡片容器,通过 instantiate(card_lite_prefab) 动态生成卡片。
|
||
* - 升级/碎片变动后通过 HERO_GROWTH_UPDATE 事件统一刷新所有卡片的可升级标识。
|
||
* - 详情面板已从本组件剥离,由 HeroInfoComp 承载。
|
||
* - 排序不依赖 smc,仅读取静态配置(HeroInfo.rarity)。
|
||
*
|
||
* 依赖:
|
||
* - HeroInfo / HeroList(heroSet)—— 英雄静态配置与全量 UUID 列表
|
||
* - 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 { UIID } from "../common/config/GameUIConfig";
|
||
import { CardLiteComp } from "./CardLiteComp";
|
||
|
||
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
|
||
card_h = 200
|
||
|
||
/** 卡片横向间隔 */
|
||
@property
|
||
spacing_x = 10
|
||
|
||
/** 卡片纵向间隔 */
|
||
@property
|
||
spacing_y = 10
|
||
|
||
/** 每行卡片数(竖向滚动时按列排列) */
|
||
@property
|
||
cols = 4
|
||
|
||
/** 卡片左右边距 */
|
||
@property
|
||
margin_x = 15
|
||
|
||
/** 卡片上下边距 */
|
||
@property
|
||
margin_y = 50
|
||
|
||
// ======================== 运行时状态 ========================
|
||
|
||
debugMode: boolean = false
|
||
|
||
start() {
|
||
this.initCardList()
|
||
}
|
||
|
||
protected onEnable(): void {
|
||
oops.message.on(GameEvent.HERO_GROWTH_UPDATE, this.onGrowthUpdate, this)
|
||
// 页面隐藏期间会错过事件(战斗结算发碎片时本节点 active=false 已注销监听),
|
||
// 重新显示时必须补刷;首次 onEnable 早于 start,卡片未创建时 forEach 空数组安全
|
||
this.refreshAllCardsCanUp()
|
||
}
|
||
|
||
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()
|
||
|
||
// 图鉴排序:仅按品质降序 → uuid 升序(与养成进度解耦,保持展示稳定)
|
||
const sorted = [...HeroList].sort((a, b) => {
|
||
const ra = HeroInfo[a]?.rarity ?? 1;
|
||
const rb = HeroInfo[b]?.rarity ?? 1;
|
||
if (ra !== rb) return rb - ra;
|
||
return a - b;
|
||
})
|
||
|
||
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
|
||
|
||
// 竖向滚动:宽度固定(每行 cols 列),高度按行数累计
|
||
const rows = Math.ceil(total / this.cols)
|
||
|
||
// 宽度 = 每行卡片总宽 + 横向间隔 + 左右边距
|
||
const contentW = this.cols * this.card_w
|
||
+ (this.cols - 1) * this.spacing_x
|
||
+ this.margin_x * 2
|
||
|
||
// 高度 = 行数 × 卡片高 + 纵向间隔 + 上下边距
|
||
const contentH = rows * this.card_h
|
||
+ (rows - 1) * this.spacing_y
|
||
+ this.margin_y * 2
|
||
|
||
const uiTrans = this.cards_node.getComponent(UITransform)
|
||
if (uiTrans) {
|
||
uiTrans.setContentSize(contentW, contentH)
|
||
}
|
||
}
|
||
|
||
reset() {
|
||
this.node.destroy()
|
||
}
|
||
}
|