Files
pixelheros/assets/script/game/map/HerosListComp.ts
panFD 63a9f6cba5 feat(hero): 新增英雄详情弹窗与图鉴页面重构
1.  新增HeroInfoComp英雄详情弹窗,支持英雄属性展示、升级操作、前后切换功能
2.  重构HerosListComp图鉴页面,将详情面板逻辑剥离至弹窗,点击卡片直接打开详情页
3.  新增英雄列表排序工具函数,统一图鉴与弹窗切换的排序逻辑
4.  优化战斗渲染排序逻辑,移除无关的Y轴渲染权重计算
5.  新增英雄详情弹窗UI配置与预制体资源
2026-09-18 11:22:03 +08:00

151 lines
4.9 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/**
* @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()
}
}