refactor(VictoryComp): 重构MVP英雄渲染逻辑

使用CardComp统一渲染MVP英雄,移除冗余的手动UI设置代码,修复了UI被覆盖的问题,同时禁用卡牌交互防止误操作
This commit is contained in:
pan
2026-06-09 10:49:12 +08:00
parent 46cadb3bc2
commit 1766d74a27
2 changed files with 232 additions and 10724 deletions

File diff suppressed because it is too large Load Diff

View File

@@ -4,7 +4,7 @@
*
*/
import { _decorator, instantiate, Label ,Prefab,Node, Sprite, Animation, AnimationClip, resources, UITransform, Widget, ProgressBar } from "cc";
import { _decorator, instantiate, Label ,Prefab,Node, Sprite, Animation, AnimationClip, resources, UITransform, Widget, ProgressBar, Tween, NodeEventType } 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 "../../../../extensions/oops-plugin-framework/assets/core/Oops";
@@ -13,7 +13,8 @@ import { GameEvent } from "../common/config/GameEvent";
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
import { FacSet } from "../common/config/GameSet";
import { HeroInfo } from "../common/config/heroSet";
import { CKind } from "../common/config/CardSet";
import { CKind, CardType, CardLV, CardConfig } from "../common/config/CardSet";
import { CardComp } from "./CardComp";
import { HighlightSet, HighlightType, HighlightLevel } from "../common/config/HighlightSet";
import { LangPrefix, lang, langf } from "../common/LangUtil";
import { mLogger } from "../common/Logger";
@@ -137,7 +138,7 @@ export class VictoryComp extends CCComp {
}
/**
* 渲染 MVP 英雄,逻辑参考 CardComp 长按放大的 UI 显示
* 渲染 MVP 英雄,使用绑定的 CardComp
*/
private renderMVPHero(mvp: HeroAttrsComp | null) {
if (!this.mvp_node) return;
@@ -153,185 +154,53 @@ export class VictoryComp extends CCComp {
const hero = HeroInfo[uuid];
if (!hero) return;
const kindName = CKind[CKind.Hero];
// 节点查找
const BG_node = this.mvp_node.getChildByName("BG");
const HF_node = this.mvp_node.getChildByName("HF");
const NF_node = this.mvp_node.getChildByName("NF");
const lv_node = this.mvp_node.getChildByName("lv");
const name_node = this.mvp_node.getChildByName("name");
const ap_node = this.mvp_node.getChildByName("ap");
const hp_node = this.mvp_node.getChildByName("hp");
const oinfo_node = this.mvp_node.getChildByName("oinfo");
const icon_node = this.mvp_node.getChildByName("icon");
const hbNode = this.mvp_node.getChildByName("HB");
const cost_node = this.mvp_node.getChildByName("cost");
// 延迟到下一帧执行,因为如果 mvp_node 刚被激活Cocos 会在当前帧稍后/下一帧触发 CardComp 的 onLoad
// 而 CardComp 的 onLoad 中调用了 applyEmptyUI() 会把卡面清空,导致我们的设置被覆盖。
this.scheduleOnce(() => {
if (!this.isValid || !this.mvp_node) return;
// ---- 背景与边框 ----
if (BG_node) {
BG_node.children.forEach(child => {
child.active = (child.name === kindName);
});
}
if (HF_node) {
HF_node.active = true;
// HF_node.children.forEach(child => {
// child.active = (child.name === kindName);
// });
}
if (NF_node) {
NF_node.active = false;
}
if (hbNode) hbNode.active = false;
// ---- 卡牌等级标识 ----
const cardLvStr = `lv${mvp.base_pool_lv || mvp.pool_lv || 1}`;
if (lv_node) {
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 isEnlarged = true; // 结算界面的卡牌默认处于放大显示状态
const uiTrans = this.mvp_node.getComponent(UITransform);
if (uiTrans) {
uiTrans.setContentSize(isEnlarged ? 230 : 170, isEnlarged ? 340 : 230);
const widget = this.mvp_node.getComponent(Widget);
if (widget) widget.updateAlignment();
}
if (BG_node) {
const bgTrans = BG_node.getComponent(UITransform);
if (bgTrans) {
bgTrans.setContentSize(isEnlarged ? 230 : 170, isEnlarged ? 340 : 230);
const widget = BG_node.getComponent(Widget);
if (widget) widget.updateAlignment();
// 获取 CardComp 组件
let cardComp = this.mvp_node.getComponent(CardComp);
if (!cardComp) {
cardComp = this.mvp_node.addComponent(CardComp);
}
BG_node.children.forEach(child => {
const childTrans = child.getComponent(UITransform);
if (childTrans) {
childTrans.setContentSize(isEnlarged ? 230 : 170, isEnlarged ? 340 : 230);
const widget = child.getComponent(Widget);
if (widget) widget.updateAlignment();
}
});
}
if (HF_node) {
const hfTrans = HF_node.getComponent(UITransform);
if (hfTrans) {
hfTrans.setContentSize(isEnlarged ? 230 : 170, isEnlarged ? 340 : 230);
const widget = HF_node.getComponent(Widget);
if (widget) widget.updateAlignment();
// 构造虚拟的 CardConfig 数据供渲染
const cardConfig: CardConfig = {
uuid: uuid,
type: CardType.Hero,
cost: 0,
weight: 0,
kind: CKind.Hero,
pool_lv: mvp.pool_lv || CardLV.LV1,
hero_lv: mvp.lv || 1,
base_pool_lv: mvp.base_pool_lv || mvp.pool_lv || 1,
};
const originalPos = this.mvp_node.position.clone();
// 禁用交互事件,防止结算界面的卡牌被拖拽或点击
this.mvp_node.off(NodeEventType.TOUCH_START);
this.mvp_node.off(NodeEventType.TOUCH_MOVE);
this.mvp_node.off(NodeEventType.TOUCH_END);
this.mvp_node.off(NodeEventType.TOUCH_CANCEL);
if (cardComp.Lock) cardComp.Lock.off(NodeEventType.TOUCH_END);
if (cardComp.unLock) cardComp.unLock.off(NodeEventType.TOUCH_END);
// 应用数据并刷新UI
cardComp.applyDrawCard(cardConfig);
// 隐藏不必要的信息(比如费用)
if (cardComp.cost_node) {
cardComp.cost_node.active = false;
}
HF_node.children.forEach(child => {
const childTrans = child.getComponent(UITransform);
if (childTrans) {
childTrans.setContentSize(isEnlarged ? 230 : 170, isEnlarged ? 340 : 230);
const widget = child.getComponent(Widget);
if (widget) widget.updateAlignment();
}
});
}
this.mvp_node.children.forEach(child => {
const widget = child.getComponent(Widget);
if (widget) widget.updateAlignment();
child.children.forEach(subChild => {
const subWidget = subChild.getComponent(Widget);
if (subWidget) subWidget.updateAlignment();
});
});
// ---- 文本信息 ----
const heroLv = mvp.lv || 1;
const suffix = heroLv >= 2 ? "★".repeat(heroLv - 1) : "";
if (name_node) {
const label = name_node.getComponent(Label);
if (label) label.string = `${suffix}${hero.name || ""}${suffix}`;
const currentPos = name_node.position;
name_node.setPosition(currentPos.x, isEnlarged ? 8 : -70, currentPos.z);
}
if (ap_node) {
ap_node.active = true;
const valNode = ap_node.getChildByName("val");
if (valNode) {
const label = valNode.getComponent(Label);
if (label) label.string = `${Math.floor(mvp.ap)}`;
}
}
if (hp_node) {
hp_node.active = true;
const valNode = hp_node.getChildByName("val");
if (valNode) {
const label = valNode.getComponent(Label);
if (label) label.string = `${Math.floor(mvp.hp_max)}`;
}
}
if (oinfo_node) {
oinfo_node.active = isEnlarged;
const infoLabel = oinfo_node.getChildByName("info")?.getComponent(Label);
if (infoLabel) infoLabel.string = `${hero.info || ""}`;
}
if (cost_node) {
cost_node.active = false; // 结算时不显示金币费用
}
// ---- 图标动画 ----
if (icon_node) {
this.updateHeroAnimation(icon_node, uuid);
}
}
private updateHeroAnimation(node: Node, uuid: number) {
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);
// clear animation clips
const clips = anim.clips;
for (let i = clips.length - 1; i >= 0; i--) {
const clip = clips[i];
if (clip) anim.removeClip(clip);
}
const path = `game/heros/hero/${hero.path}/idle`;
resources.load(path, AnimationClip, (err, clip) => {
if (err || !clip) {
mLogger.log(this.debugMode, "VictoryComp", `load hero animation failed ${uuid}`, err);
return;
}
// avoid state conflict
if (!this.node.isValid || !this.mvp_node || !this.mvp_node.active) return;
const currentClips = anim.clips;
for (let i = currentClips.length - 1; i >= 0; i--) {
const c = currentClips[i];
if (c) anim.removeClip(c);
}
anim.addClip(clip);
anim.play("idle");
});
// 覆盖 CardComp 内部动画的 scale停止其上的 tween并直接放大
// 结算界面的卡牌需要放大显示170 * 1.35 ≈ 230
Tween.stopAllByTarget(this.mvp_node);
this.mvp_node.setPosition(originalPos);
this.mvp_node.setScale(1.35, 1.35, 1);
}, 0);
}
/**