refactor: 统一将 pool_lv 重命名为 card_lv 并清理废弃代码
本次提交完成了全项目范围内的术语统一重构: 1. 将所有`pool_lv`相关变量、字段、注释替换为`card_lv`,对齐卡牌等级的业务含义 2. 移除了配置中冗余的默认`pool_lv`赋值,简化数据结构 3. 删除了废弃的`HlistComp.ts`组件及其元文件 4. 修正了多处逻辑错误,确保卡牌等级正确驱动背景框切换 5. 更新了相关注释和文档,保持代码一致性
This commit is contained in:
@@ -579,7 +579,7 @@ export class CHeroComp extends CCComp {
|
||||
? (this.queryHeroUuidByEid(this.cardData.target_hero_eid as number) ?? this.cardData.uuid)
|
||||
: this.cardData.uuid;
|
||||
const heroLv = Math.max(1, this.cardData.hero_lv ?? 1);
|
||||
const poolLv = Math.max(1, this.cardData.base_pool_lv ?? this.cardData.pool_lv ?? 1);
|
||||
const poolLv = Math.max(1, this.cardData.base_card_lv ?? this.cardData.card_lv ?? 1);
|
||||
|
||||
// oops.gui 打开 HInfo 英雄卡预览
|
||||
oops.gui.remove(UIID.HInfo);
|
||||
@@ -612,7 +612,7 @@ export class CHeroComp extends CCComp {
|
||||
reason: "",
|
||||
uuid: this.cardData.uuid,
|
||||
hero_lv: this.cardData.hero_lv ?? 1,
|
||||
card_lv: this.cardData.base_pool_lv ?? this.cardData.pool_lv ?? 1
|
||||
card_lv: this.cardData.base_card_lv ?? this.cardData.card_lv ?? 1
|
||||
};
|
||||
oops.message.dispatchEvent(GameEvent.UseHeroCard, guard);
|
||||
if (guard.cancel) return;
|
||||
|
||||
@@ -298,7 +298,7 @@ export class CardComp extends CCComp {
|
||||
reason: "",
|
||||
uuid: this.cardData.uuid,
|
||||
hero_lv: this.cardData.hero_lv ?? 1,
|
||||
card_lv: this.cardData.base_pool_lv ?? this.cardData.pool_lv ?? 1
|
||||
card_lv: this.cardData.base_card_lv ?? this.cardData.card_lv ?? 1
|
||||
};
|
||||
oops.message.dispatchEvent(GameEvent.UseHeroCard, guard);
|
||||
if (guard.cancel) {
|
||||
@@ -549,7 +549,7 @@ export class CardComp extends CCComp {
|
||||
? (this.queryHeroUuidByEid(this.cardData!.target_hero_eid as number) ?? this.card_uuid)
|
||||
: this.card_uuid;
|
||||
const heroLv = Math.max(1, this.cardData?.hero_lv ?? 1);
|
||||
const poolLv = Math.max(1, this.cardData?.base_pool_lv ?? this.cardData?.pool_lv ?? 1);
|
||||
const poolLv = Math.max(1, this.cardData?.base_card_lv ?? this.cardData?.card_lv ?? 1);
|
||||
oops.gui.remove(UIID.HInfo);
|
||||
oops.gui.open(UIID.HInfo, { heroUuid, heroLv, poolLv });
|
||||
}
|
||||
@@ -659,7 +659,7 @@ export class CardComp extends CCComp {
|
||||
* 2. 技能卡:显示技能名(带品质后缀)、描述文本、静态图标。
|
||||
* 3. 特殊卡:显示卡名(带品质后缀)、描述文本、静态图标。
|
||||
*
|
||||
* 同时根据 pool_lv 切换背景底框,根据 hero_lv / card_lv 切换普通/高级边框。
|
||||
* 同时根据 card_lv 切换背景底框,根据 hero_lv / card_lv 切换普通/高级边框。
|
||||
*/
|
||||
private applyCardUI() {
|
||||
if (!this.cardData) {
|
||||
@@ -686,7 +686,7 @@ export class CardComp extends CCComp {
|
||||
const kindName = CKind[renderKind];
|
||||
|
||||
if (this.BG_node) {
|
||||
const bgLv = this.cardData.base_pool_lv ?? this.cardData.pool_lv;
|
||||
const bgLv = this.cardData.base_card_lv ?? this.cardData.card_lv;
|
||||
this.BG_node.children.forEach(child => {
|
||||
child.active = (child.name === kindName);
|
||||
const bg = child.getComponent(CardBgComp);
|
||||
|
||||
@@ -115,10 +115,10 @@ export class CardLiteComp extends CCComp {
|
||||
* 便捷方法:通过英雄 UUID 和卡池等级直接设置英雄卡。
|
||||
* 自动从 CardPoolList 查找匹配的卡牌配置。
|
||||
* @param uuid 英雄 UUID
|
||||
* @param poolLv 卡池等级(默认 1)
|
||||
* @param cardLv 卡牌等级(默认 1)
|
||||
*/
|
||||
setHeroByUuid(uuid: number, poolLv: number = 1) {
|
||||
const card = CardPoolList.find(c => c.uuid === uuid && c.pool_lv === poolLv);
|
||||
setHeroByUuid(uuid: number, cardLv: number = 1) {
|
||||
const card = CardPoolList.find(c => c.uuid === uuid && c.card_lv === cardLv);
|
||||
if (card) {
|
||||
this.setData(card);
|
||||
return;
|
||||
@@ -130,7 +130,7 @@ export class CardLiteComp extends CCComp {
|
||||
type: CardType.Hero,
|
||||
cost: 5,
|
||||
weight: 25,
|
||||
pool_lv: poolLv as any,
|
||||
card_lv: cardLv,
|
||||
kind: CKind.Hero,
|
||||
hero_lv: hero.lv || 1
|
||||
});
|
||||
@@ -194,7 +194,7 @@ export class CardLiteComp extends CCComp {
|
||||
* 2. 技能卡:显示技能名、静态图标。
|
||||
* 3. 特殊卡:显示卡名、静态图标。
|
||||
*
|
||||
* 同时根据 pool_lv 切换背景底框,根据 kind 切换种类标识。
|
||||
* 同时根据 card_lv 切换背景底框,根据 kind 切换种类标识。
|
||||
*/
|
||||
private applyCardUI() {
|
||||
if (!this.cardData) {
|
||||
@@ -221,7 +221,7 @@ export class CardLiteComp extends CCComp {
|
||||
const kindName = CKind[this.cardData.kind];
|
||||
|
||||
if (this.BG_node) {
|
||||
const bgLv = this.cardData.base_pool_lv ?? this.cardData.pool_lv;
|
||||
const bgLv = this.cardData.base_card_lv ?? this.cardData.card_lv;
|
||||
this.BG_node.children.forEach(child => {
|
||||
child.active = (child.name === kindName);
|
||||
const bg = child.getComponent(CardBgComp);
|
||||
|
||||
@@ -333,7 +333,7 @@ export class HInfoComp extends CCComp {
|
||||
this.BG_node.children.forEach(child => {
|
||||
child.active = (child.name === kindName);
|
||||
const bg = child.getComponent(CardBgComp);
|
||||
if (bg) child.active ? bg.apply(this.model.base_pool_lv ?? this.model.pool_lv ?? 1) : bg.clear();
|
||||
if (bg) child.active ? bg.apply(this.model.base_card_lv ?? this.model.card_lv ?? 1) : bg.clear();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -116,7 +116,7 @@ export class HerosListComp extends CCComp {
|
||||
this.cards_node.removeAllChildren()
|
||||
|
||||
const sorted = [...HeroList].sort((a, b) => {
|
||||
return (HeroInfo[a]?.pool_lv ?? 1) - (HeroInfo[b]?.pool_lv ?? 1);
|
||||
return (HeroInfo[a]?.card_lv ?? 1) - (HeroInfo[b]?.card_lv ?? 1);
|
||||
});
|
||||
|
||||
for (const uuid of sorted) {
|
||||
@@ -136,7 +136,7 @@ export class HerosListComp extends CCComp {
|
||||
})
|
||||
|
||||
const comp = cardNode.getComponent(CardLiteComp) || cardNode.addComponent(CardLiteComp)
|
||||
comp.setHeroByUuid(uuid, hero.pool_lv ?? 1)
|
||||
comp.setHeroByUuid(uuid, hero.card_lv ?? 1)
|
||||
comp.onClickCallback = (cardComp: CardLiteComp) => {
|
||||
this.onCardSelect(uuid)
|
||||
this.highlightCard(cardNode)
|
||||
@@ -209,7 +209,7 @@ export class HerosListComp extends CCComp {
|
||||
if (infoLabel) infoLabel.string = desc || hero.info || ""
|
||||
}
|
||||
|
||||
this.updatePoolLvBg(hero.pool_lv ?? 1)
|
||||
this.updatePoolLvBg(hero.card_lv ?? 1)
|
||||
this.updateLvDisplay(hero)
|
||||
this.updateTypeDisplay(hero)
|
||||
this.updateHeroAnimation(uuid)
|
||||
@@ -237,7 +237,7 @@ export class HerosListComp extends CCComp {
|
||||
|
||||
private updateLvDisplay(hero: typeof HeroInfo[number]) {
|
||||
if (!this.lv_node) return
|
||||
const cardLvStr = `lv${hero.pool_lv ?? 1}`
|
||||
const cardLvStr = `lv${hero.card_lv ?? 1}`
|
||||
this.lv_node.active = true
|
||||
this.lv_node.children.forEach(child => {
|
||||
|
||||
|
||||
@@ -1,330 +0,0 @@
|
||||
/**
|
||||
* @file HlistComp.ts
|
||||
* @description 英雄列表轮播组件(UI 视图层)
|
||||
*
|
||||
* 职责:
|
||||
* 1. 在主页界面以 **5 格轮播** 形式展示英雄图鉴。
|
||||
* 2. 支持左右切换,用 tween 动画平滑过渡节点位置。
|
||||
* 3. 点击切换时自动更新当前选中英雄的名称、AP、HP 和技能信息。
|
||||
*
|
||||
* 关键设计:
|
||||
* - carouselNodes[0..4] 对应 5 个展示位(最左-2 到最右+2),
|
||||
* 中间位 [2] 为当前选中英雄。
|
||||
* - 切换时:将即将移出屏幕的节点瞬间跳转到另一端,再用 tween 滑入。
|
||||
* - 切换完成后重排 carouselNodes 数组保持逻辑顺序。
|
||||
* - iconVisualTokens 按节点独立管理竞态令牌,防止异步动画回调错乱。
|
||||
*
|
||||
* 依赖:
|
||||
* - HeroInfo / HeroList(heroSet)—— 英雄静态配置与全量英雄 UUID 列表
|
||||
* - SkillSet / IType(SkillSet)—— 技能配置与类型枚举
|
||||
*/
|
||||
import { _decorator, Animation, AnimationClip, Button, Event, Label, Node, NodeEventType, Sprite, resources, tween, Vec3, Widget } 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 { HeroInfo, HeroList } from "../common/config/heroSet";
|
||||
import { IType, SkillSet } from "../common/config/SkillSet";
|
||||
import { oops } from "db://oops-framework/core/Oops";
|
||||
import { mLogger } from "../common/Logger";
|
||||
import { UIID } from "../common/config/GameUIConfig";
|
||||
|
||||
const {property, ccclass } = _decorator;
|
||||
|
||||
/**
|
||||
* HListComp —— 英雄图鉴轮播视图组件
|
||||
*
|
||||
* 在任务主页展示所有可用英雄,玩家可左右滑动查看:
|
||||
* - 中间位显示完整信息(名称 / AP / HP / 技能列表)
|
||||
* - 两侧位显示缩略 idle 动画
|
||||
*/
|
||||
@ccclass('HListComp')
|
||||
@ecs.register('HListComp', false)
|
||||
export class HListComp extends CCComp {
|
||||
// ======================== 编辑器绑定节点 ========================
|
||||
|
||||
/** 中间位英雄 idle 图标节点 */
|
||||
@property(Node)
|
||||
hero_icon=null!
|
||||
|
||||
/** 攻击力标签节点 */
|
||||
@property(Node)
|
||||
ap_node=null!
|
||||
/** 生命值标签节点 */
|
||||
@property(Node)
|
||||
hp_node=null!
|
||||
/** 技能信息容器节点(包含 Line1~Line5 子节点) */
|
||||
@property(Node)
|
||||
info_node=null!
|
||||
/** 英雄名称标签节点 */
|
||||
@property(Node)
|
||||
name_node=null!
|
||||
/** 向左切换按钮 */
|
||||
|
||||
@property(Node)
|
||||
lv_node=null!
|
||||
|
||||
// ======================== 运行时状态 ========================
|
||||
|
||||
/** 当前选中英雄在 HeroList 中的索引 */
|
||||
huuid:number=null!
|
||||
/** 当前选中英雄在 HeroList 数组中的下标 */
|
||||
private currentIndex: number = 0;
|
||||
/** 各图标节点的视觉令牌映射(防止异步动画竞态) */
|
||||
private iconVisualTokens: Map<Node, number> = new Map();
|
||||
/** 是否正在播放切换动画(防止快速连点) */
|
||||
private isAnimating: boolean = false;
|
||||
/** 轮播节点数组,顺序为 [左2, 左1, 中, 右1, 右2] */
|
||||
private carouselNodes: Node[] = [];
|
||||
/** 5 个固定位置坐标(从场景中读取初始值) */
|
||||
private fixedPositions: Vec3[] = [];
|
||||
/** 调试日志开关 */
|
||||
debugMode: boolean = false;
|
||||
|
||||
onLoad() {
|
||||
|
||||
}
|
||||
/** 预留:弹窗打开时接收参数 */
|
||||
onAdded(args: any) {
|
||||
|
||||
}
|
||||
/** 关闭排行榜弹窗 */
|
||||
closeHeros(){
|
||||
oops.gui.remove(UIID.Heros)
|
||||
}
|
||||
start() {
|
||||
|
||||
|
||||
// 设置初始选中并加载所有位置的英雄动画
|
||||
if (HeroList && HeroList.length > 0) {
|
||||
this.currentIndex = 0;
|
||||
this.initAllNodes();
|
||||
this.updateHeroInfo();
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 切换逻辑 ========================
|
||||
|
||||
/**
|
||||
* 向左切换(查看上一个英雄):
|
||||
* 1. currentIndex 左移。
|
||||
* 2. 最右节点 n4 瞬间跳到最左位置,加载新英雄动画。
|
||||
* 3. 所有节点 tween 向右滑动一格。
|
||||
* 4. 动画完成后重排 carouselNodes 数组。
|
||||
*/
|
||||
private onPreClick() {
|
||||
if (!HeroList || HeroList.length === 0 || this.isAnimating || this.carouselNodes.length < 5) return;
|
||||
this.isAnimating = true;
|
||||
|
||||
this.currentIndex = (this.currentIndex - 1 + HeroList.length) % HeroList.length;
|
||||
|
||||
const [n0, n1, n2, n3, n4] = this.carouselNodes;
|
||||
|
||||
// n4 瞬间跳至最左位置,准备滑入
|
||||
n4.setPosition(new Vec3(this.fixedPositions[0].x, n4.position.y, n4.position.z));
|
||||
this.updateNodeAnimationByOffset(n4, -2);
|
||||
this.updateHeroInfo();
|
||||
|
||||
// 所有节点向右滑动一格
|
||||
tween(n0).to(0.2, { position: new Vec3(this.fixedPositions[1].x, n0.position.y, n0.position.z) }).start();
|
||||
tween(n1).to(0.2, { position: new Vec3(this.fixedPositions[2].x, n1.position.y, n1.position.z) }).start();
|
||||
tween(n2).to(0.2, { position: new Vec3(this.fixedPositions[3].x, n2.position.y, n2.position.z) }).start();
|
||||
tween(n3).to(0.2, { position: new Vec3(this.fixedPositions[4].x, n3.position.y, n3.position.z) })
|
||||
.call(() => {
|
||||
// 重排数组:n4 成为新的最左节点
|
||||
this.carouselNodes = [n4, n0, n1, n2, n3];
|
||||
this.isAnimating = false;
|
||||
})
|
||||
.start();
|
||||
}
|
||||
|
||||
/**
|
||||
* 向右切换(查看下一个英雄):
|
||||
* 1. currentIndex 右移。
|
||||
* 2. 最左节点 n0 瞬间跳到最右位置,加载新英雄动画。
|
||||
* 3. 所有节点 tween 向左滑动一格。
|
||||
* 4. 动画完成后重排 carouselNodes 数组。
|
||||
*/
|
||||
private onNextClick() {
|
||||
if (!HeroList || HeroList.length === 0 || this.isAnimating || this.carouselNodes.length < 5) return;
|
||||
this.isAnimating = true;
|
||||
|
||||
this.currentIndex = (this.currentIndex + 1) % HeroList.length;
|
||||
|
||||
const [n0, n1, n2, n3, n4] = this.carouselNodes;
|
||||
|
||||
// n0 瞬间跳至最右位置,准备滑入
|
||||
n0.setPosition(new Vec3(this.fixedPositions[4].x, n0.position.y, n0.position.z));
|
||||
this.updateNodeAnimationByOffset(n0, 2);
|
||||
this.updateHeroInfo();
|
||||
|
||||
// 所有节点向左滑动一格
|
||||
tween(n1).to(0.2, { position: new Vec3(this.fixedPositions[0].x, n1.position.y, n1.position.z) }).start();
|
||||
tween(n2).to(0.2, { position: new Vec3(this.fixedPositions[1].x, n2.position.y, n2.position.z) }).start();
|
||||
tween(n3).to(0.2, { position: new Vec3(this.fixedPositions[2].x, n3.position.y, n3.position.z) }).start();
|
||||
tween(n4).to(0.2, { position: new Vec3(this.fixedPositions[3].x, n4.position.y, n4.position.z) })
|
||||
.call(() => {
|
||||
// 重排数组:n0 成为新的最右节点
|
||||
this.carouselNodes = [n1, n2, n3, n4, n0];
|
||||
this.isAnimating = false;
|
||||
})
|
||||
.start();
|
||||
}
|
||||
|
||||
// ======================== 数据查询 ========================
|
||||
|
||||
/**
|
||||
* 根据偏移量获取英雄 UUID。
|
||||
* @param offset 相对于当前选中英雄的偏移(-2, -1, 0, 1, 2)
|
||||
* @returns HeroList 中对应位置的英雄 UUID
|
||||
*/
|
||||
private getHeroUuid(offset: number): number {
|
||||
const len = HeroList.length;
|
||||
return HeroList[(this.currentIndex + offset + len * 5) % len];
|
||||
}
|
||||
|
||||
/**
|
||||
* 按偏移量更新指定节点的英雄动画。
|
||||
* @param node 目标图标节点
|
||||
* @param offset 偏移量
|
||||
*/
|
||||
private updateNodeAnimationByOffset(node: Node, offset: number) {
|
||||
const uuid = this.getHeroUuid(offset);
|
||||
this.updateHeroAnimation(node, uuid);
|
||||
}
|
||||
|
||||
/** 更新当前选中英雄的详细信息(名称、AP、HP、技能列表) */
|
||||
private updateHeroInfo() {
|
||||
this.huuid = this.getHeroUuid(0);
|
||||
const hero = HeroInfo[this.huuid];
|
||||
if (!hero) return;
|
||||
|
||||
const heroLv = Math.max(1, Math.floor(hero.lv ?? 1));
|
||||
const suffix = heroLv >= 2 ? "★".repeat(heroLv - 1) : "";
|
||||
this.setLabelText(this.name_node, `${suffix}${hero.name || ""}${suffix}`);
|
||||
|
||||
this.setLabelText(this.ap_node, `${(hero.ap ?? 0) * heroLv}`);
|
||||
this.setLabelText(this.hp_node, `${(hero.hp ?? 0) * heroLv}`);
|
||||
|
||||
if (this.info_node) {
|
||||
const infoLabel = this.info_node.getChildByName("info")?.getComponent(Label);
|
||||
if (infoLabel) infoLabel.string = `${hero.info || ""}`;
|
||||
}
|
||||
|
||||
const cardLvStr = `lv${hero.pool_lv ?? 1}`;
|
||||
if (this.lv_node) {
|
||||
this.lv_node.active = true;
|
||||
this.lv_node.children.forEach(child => {
|
||||
if (child.name === "light") {
|
||||
child.active = false;
|
||||
} else if (child.name === "bg") {
|
||||
child.active = true;
|
||||
} else {
|
||||
child.active = (child.name === cardLvStr);
|
||||
}
|
||||
});
|
||||
const widget = this.lv_node.getComponent(Widget);
|
||||
if (widget) widget.updateAlignment();
|
||||
this.lv_node.children.forEach(child => {
|
||||
const childWidget = child.getComponent(Widget);
|
||||
if (childWidget) childWidget.updateAlignment();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/** 初始化 5 个轮播位的英雄动画 */
|
||||
private initAllNodes() {
|
||||
if (this.carouselNodes.length < 5) return;
|
||||
this.updateNodeAnimationByOffset(this.carouselNodes[0], -2);
|
||||
this.updateNodeAnimationByOffset(this.carouselNodes[1], -1);
|
||||
this.updateNodeAnimationByOffset(this.carouselNodes[2], 0);
|
||||
this.updateNodeAnimationByOffset(this.carouselNodes[3], 1);
|
||||
this.updateNodeAnimationByOffset(this.carouselNodes[4], 2);
|
||||
}
|
||||
|
||||
// ======================== UI 工具 ========================
|
||||
|
||||
/**
|
||||
* 安全设置 Label 文本
|
||||
* @param node 标签所在节点
|
||||
* @param text 文本内容
|
||||
*/
|
||||
private setLabelText(node: Node, text: string) {
|
||||
if (!node) return;
|
||||
const label = node.getComponent(Label) || node.getComponentInChildren(Label);
|
||||
if (label) {
|
||||
label.string = text;
|
||||
}
|
||||
}
|
||||
|
||||
// ======================== 英雄动画 ========================
|
||||
|
||||
/**
|
||||
* 为指定节点加载并播放英雄 idle 动画。
|
||||
* 使用 iconVisualTokens 做节点级竞态保护。
|
||||
*
|
||||
* @param node 图标节点
|
||||
* @param uuid 英雄 UUID
|
||||
*/
|
||||
private updateHeroAnimation(node: Node, uuid: number) {
|
||||
if (!node) return;
|
||||
const sprite = node.getComponent(Sprite) || node.getComponentInChildren(Sprite);
|
||||
if (sprite) sprite.spriteFrame = null;
|
||||
|
||||
const hero = HeroInfo[uuid];
|
||||
if (!hero) return;
|
||||
|
||||
const anim = node.getComponent(Animation) || node.addComponent(Animation);
|
||||
this.clearAnimationClips(anim);
|
||||
|
||||
// 递增该节点的视觉令牌
|
||||
let token = (this.iconVisualTokens.get(node) || 0) + 1;
|
||||
this.iconVisualTokens.set(node, token);
|
||||
const path = `game/heros/hero/${hero.path}/idle`;
|
||||
|
||||
resources.load(path, AnimationClip, (err, clip) => {
|
||||
if (err || !clip) {
|
||||
mLogger.log(this.debugMode, "HListComp", `load hero animation failed ${uuid}`, err);
|
||||
return;
|
||||
}
|
||||
// 竞态保护:令牌不匹配则丢弃
|
||||
if (token !== this.iconVisualTokens.get(node)) {
|
||||
return;
|
||||
}
|
||||
this.clearAnimationClips(anim);
|
||||
anim.addClip(clip);
|
||||
anim.play("idle");
|
||||
});
|
||||
}
|
||||
|
||||
/** 移除 Animation 上的全部 clip(倒序遍历避免索引偏移) */
|
||||
private clearAnimationClips(anim: Animation) {
|
||||
const clips = anim.clips;
|
||||
if (clips && clips.length > 0) {
|
||||
for (let i = clips.length - 1; i >= 0; i--) {
|
||||
const clip = clips[i];
|
||||
if (clip) anim.removeClip(clip, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 递归查找子节点(按名称)
|
||||
* @param root 起始节点
|
||||
* @param name 目标节点名
|
||||
*/
|
||||
private findNodeByName(root: Node, name: string): Node | null {
|
||||
if (!root) return null;
|
||||
if (root.name === name) return root;
|
||||
for (let i = 0; i < root.children.length; i++) {
|
||||
const res = this.findNodeByName(root.children[i], name);
|
||||
if (res) return res;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/** ECS 组件移除时销毁节点 */
|
||||
reset() {
|
||||
this.node.destroy();
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
{"ver":"4.0.24","importer":"typescript","imported":true,"uuid":"89bf6d65-5432-4946-9b14-3e5150dddedd","files":[],"subMetas":{},"userData":{}}
|
||||
@@ -419,7 +419,7 @@ export class ItemListComp extends CCComp {
|
||||
oops.gui.open(UIID.HInfo, {
|
||||
heroUuid: cardUuid,
|
||||
heroLv: this.cardData.card_lv ?? 1,
|
||||
poolLv: config?.pool_lv ?? 1,
|
||||
poolLv: config?.card_lv ?? 1,
|
||||
isSkillCard: true
|
||||
});
|
||||
}
|
||||
|
||||
@@ -73,7 +73,7 @@ export class MissionHeroComp extends CCComp {
|
||||
/** 是否正在消费召唤队列(防止并发) */
|
||||
is_processing_queue: boolean = false
|
||||
/** 召唤请求队列:保证召唤按顺序串行执行 */
|
||||
summon_queue: { uuid: number; hero_lv: number; pool_lv: number }[] = []
|
||||
summon_queue: { uuid: number; hero_lv: number; card_lv: number }[] = []
|
||||
/** 预留英雄列表 */
|
||||
heros: any = []
|
||||
|
||||
@@ -141,17 +141,17 @@ export class MissionHeroComp extends CCComp {
|
||||
|
||||
/**
|
||||
* 召唤请求入口:
|
||||
* 从事件参数中提取 uuid / hero_lv / pool_lv,放入串行队列。
|
||||
* 从事件参数中提取 uuid / hero_lv / card_lv,放入串行队列。
|
||||
* 防御:已召唤的英雄 uuid 拒绝重复召唤(只能通过升级卡升级)。
|
||||
*
|
||||
* @param event 事件名
|
||||
* @param args { uuid, hero_lv, pool_lv }
|
||||
* @param args { uuid, hero_lv, card_lv }
|
||||
*/
|
||||
private async call_hero(event: string, args: any) {
|
||||
const payload = args ?? event;
|
||||
const uuid = Number(payload?.uuid ?? 1001);
|
||||
const hero_lv = Math.max(1, Number(payload?.hero_lv ?? 1));
|
||||
const pool_lv = Math.max(1, Number(payload?.pool_lv ?? 1));
|
||||
const card_lv = Math.max(1, Number(payload?.card_lv ?? 1));
|
||||
|
||||
// 防御:场上已有同 uuid 的存活英雄时,拒绝重复召唤
|
||||
if (this.isHeroAlreadySummoned(uuid)) {
|
||||
@@ -159,7 +159,7 @@ export class MissionHeroComp extends CCComp {
|
||||
return;
|
||||
}
|
||||
|
||||
this.summon_queue.push({ uuid, hero_lv, pool_lv });
|
||||
this.summon_queue.push({ uuid, hero_lv, card_lv });
|
||||
this.processSummonQueue();
|
||||
}
|
||||
|
||||
@@ -216,16 +216,16 @@ export class MissionHeroComp extends CCComp {
|
||||
*
|
||||
* @param uuid 英雄 UUID
|
||||
* @param hero_lv 英雄等级
|
||||
* @param pool_lv 卡池等级(历史遗留,新机制下不再使用)
|
||||
* @param card_lv 卡牌等级(驱动 bg_node 颜色)
|
||||
* @returns 创建的 Hero 实体
|
||||
*/
|
||||
private addHero(uuid: number = 1001, hero_lv: number = 1, pool_lv: number = 1) {
|
||||
private addHero(uuid: number = 1001, hero_lv: number = 1, card_lv: number = 1) {
|
||||
let hero = ecs.getEntity<Hero>(Hero);
|
||||
let scale = 1
|
||||
const posIndex = this.pickPositionIndexForHero();
|
||||
const landingPos = MissionHeroComp.HERO_POSITIONS[posIndex];
|
||||
let spawnPos: Vec3 = v3(landingPos.x, landingPos.y + MissionHeroComp.HERO_DROP_HEIGHT, 0);
|
||||
hero.load(spawnPos, scale, uuid, landingPos.y, hero_lv, pool_lv, posIndex);
|
||||
hero.load(spawnPos, scale, uuid, landingPos.y, hero_lv, card_lv, posIndex);
|
||||
|
||||
// 召唤完成后,派发事件以更新英雄面板
|
||||
const model = hero.get(HeroAttrsComp);
|
||||
@@ -267,7 +267,7 @@ export class MissionHeroComp extends CCComp {
|
||||
while (this.summon_queue.length > 0) {
|
||||
const payload = this.summon_queue.shift();
|
||||
if (!payload) continue;
|
||||
await this.handleSingleSummon(payload.uuid, payload.hero_lv, payload.pool_lv);
|
||||
await this.handleSingleSummon(payload.uuid, payload.hero_lv, payload.card_lv);
|
||||
}
|
||||
} finally {
|
||||
this.is_processing_queue = false;
|
||||
@@ -279,10 +279,10 @@ export class MissionHeroComp extends CCComp {
|
||||
*
|
||||
* @param uuid 英雄 UUID
|
||||
* @param hero_lv 英雄等级
|
||||
* @param pool_lv 卡池等级(历史遗留)
|
||||
* @param card_lv 卡牌等级
|
||||
*/
|
||||
private async handleSingleSummon(uuid: number, hero_lv: number, pool_lv: number = 1) {
|
||||
this.addHero(uuid, hero_lv, pool_lv);
|
||||
private async handleSingleSummon(uuid: number, hero_lv: number, card_lv: number = 1) {
|
||||
this.addHero(uuid, hero_lv, card_lv);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -409,7 +409,7 @@ export class SCardComp extends CCComp {
|
||||
oops.gui.open(UIID.HInfo, {
|
||||
heroUuid: cardUuid,
|
||||
heroLv: this.cardData.card_lv ?? 1,
|
||||
poolLv: config?.pool_lv ?? 1,
|
||||
poolLv: config?.card_lv ?? 1,
|
||||
isSkillCard: true
|
||||
});
|
||||
}
|
||||
|
||||
@@ -186,7 +186,7 @@ export class SkillBoxComp extends CCComp {
|
||||
const cardUuid = config ? config.uuid : this.s_uuid;
|
||||
|
||||
oops.gui.remove(UIID.HInfo);
|
||||
oops.gui.open(UIID.HInfo, { heroUuid: cardUuid, heroLv: this.card_lv, poolLv: config?.pool_lv ?? 1, isSkillCard: true });
|
||||
oops.gui.open(UIID.HInfo, { heroUuid: cardUuid, heroLv: this.card_lv, poolLv: config?.card_lv ?? 1, isSkillCard: true });
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -49,10 +49,10 @@ export class TalentItemComp extends CCComp {
|
||||
if (this.lbl_name) this.lbl_name.string = config.name ?? "";
|
||||
if (this.lbl_info) this.lbl_info.string = config.info ?? "";
|
||||
|
||||
// 直接复用 CardSet 中已映射好的 pool_lv,保证与技能卡牌背景一致
|
||||
// CardSet 通过 waveToPoolLv[wave] 由 SKILL_CARD_WAVES 索引推导(wave 1→1, 5→2, 8→3)
|
||||
// 直接复用 CardSet 中已映射好的 card_lv,保证与技能卡牌背景一致
|
||||
// CardSet 通过 waveToCardLv[wave] 由 SKILL_CARD_WAVES 索引推导(wave 1→1, 5→2, 8→3)
|
||||
if (this.bg) {
|
||||
this.bg.apply(config.pool_lv || 1);
|
||||
this.bg.apply(config.card_lv || 1);
|
||||
}
|
||||
|
||||
// 设置图标:驻场卡(skill=undefined 但有 field)走 FieldSkillSet,否则走 SkillSet
|
||||
|
||||
@@ -172,9 +172,9 @@ export class VictoryComp extends CCComp {
|
||||
cost: 0,
|
||||
weight: 0,
|
||||
kind: CKind.Hero,
|
||||
pool_lv: mvp.pool_lv || CardLV.LV1,
|
||||
card_lv: mvp.card_lv || 1,
|
||||
hero_lv: mvp.lv || 1,
|
||||
base_pool_lv: mvp.base_pool_lv || mvp.pool_lv || 1,
|
||||
base_card_lv: mvp.base_card_lv || mvp.card_lv || 1,
|
||||
};
|
||||
|
||||
const originalPos = this.mvp_node.position.clone();
|
||||
|
||||
Reference in New Issue
Block a user