refactor(common prompt,hero box): 优化弹窗绑定逻辑与英雄出售限制
1. 重构CommonPrompt的编辑器属性绑定,添加按钮节点序列化引用并优化兜底查找逻辑 2. 为英雄出售操作添加存活数量校验,场上仅1个英雄时禁止出售 3. 新增统一的存活英雄统计工具方法 4. 补充Claude工具命令配置
This commit is contained in:
@@ -59,40 +59,47 @@ export interface WindowPromptParams {
|
||||
@ccclass("CommonPrompt")
|
||||
export class CommonPrompt extends Component {
|
||||
/** 窗口标题 */
|
||||
@property(Label)
|
||||
@property({ type: Label, displayName: "标题文本" })
|
||||
private lab_title: Label | null = null;
|
||||
|
||||
/** 窗口内容(富文本,需在 prefab 中将 Label 换为 RichText 后重新拖入) */
|
||||
@property(RichText)
|
||||
@property({ type: RichText, displayName: "内容富文本" })
|
||||
private lab_content: RichText | null = null;
|
||||
|
||||
/** 确定按钮文本 */
|
||||
@property(Label)
|
||||
@property({ type: Label, displayName: "确定按钮文本" })
|
||||
private lab_ok: Label | null = null;
|
||||
|
||||
/** 取消按钮文本 */
|
||||
@property(Label)
|
||||
@property({ type: Label, displayName: "取消按钮文本" })
|
||||
private lab_cancel: Label | null = null;
|
||||
|
||||
/** 确定按钮节点 */
|
||||
@property({ type: Node, displayName: "确定按钮" })
|
||||
private btn_ok: Node | null = null;
|
||||
|
||||
/** 取消按钮节点 */
|
||||
@property({ type: Node, displayName: "取消按钮" })
|
||||
private btn_cancel: Node | null = null;
|
||||
|
||||
/** 运行时参数 */
|
||||
private config: WindowPromptParams = {};
|
||||
|
||||
/** 弹窗打开动画已播放标记(防止 onAdded 重复触发) */
|
||||
private animPlayed: boolean = false;
|
||||
|
||||
/** 代码动态绑定的确定按钮(prefab clickEvents 失效时的兜底) */
|
||||
private btnOk: Node | null = null;
|
||||
/** 代码动态绑定的取消按钮 */
|
||||
private btnCancel: Node | null = null;
|
||||
|
||||
onLoad() {
|
||||
// 兜底:prefab 中 clickEvents 引用的旧插件脚本被移除后,代码动态绑定保证按钮可用
|
||||
this.btnOk = this.node.getChildByName("Node")?.getChildByName("btn_ok") ?? null;
|
||||
this.btnCancel = this.node.getChildByName("Node")?.getChildByName("btn_cancel") ?? null;
|
||||
this.btnOk?.on(Button.EventType.CLICK, this.onOk, this);
|
||||
this.btnCancel?.on(Button.EventType.CLICK, this.onCancel, this);
|
||||
// 优先使用编辑器绑定的按钮节点;未绑定时按节点名查找兜底
|
||||
if (!this.btn_ok) {
|
||||
this.btn_ok = this.node.getChildByName("Node")?.getChildByName("btn_ok") ?? null;
|
||||
}
|
||||
if (!this.btn_cancel) {
|
||||
this.btn_cancel = this.node.getChildByName("Node")?.getChildByName("btn_cancel") ?? null;
|
||||
}
|
||||
this.btn_ok?.on(Button.EventType.CLICK, this.onOk, this);
|
||||
this.btn_cancel?.on(Button.EventType.CLICK, this.onCancel, this);
|
||||
// 遮罩点击关闭(btn_sky 为 btn_ok 内嵌子节点,无 Button 组件,直接监听触摸事件)
|
||||
this.btnOk?.getChildByName("btn_sky")?.on(NodeEventType.TOUCH_END, this.onMaskClick, this);
|
||||
this.btn_ok?.getChildByName("btn_sky")?.on(NodeEventType.TOUCH_END, this.onMaskClick, this);
|
||||
|
||||
// 序列化属性槽引用的是旧插件 LanguageLabel 组件实例,脚本替换后已失效;
|
||||
// 这里按节点名查找 Label/RichText 作为兜底,保证文字一定写入
|
||||
@@ -100,10 +107,10 @@ export class CommonPrompt extends Component {
|
||||
this.lab_title = this.node.getChildByName("lab_title")?.getComponent(Label) ?? null;
|
||||
}
|
||||
if (!this.lab_ok) {
|
||||
this.lab_ok = this.btnOk?.getChildByName("lab_ok")?.getComponent(Label) ?? null;
|
||||
this.lab_ok = this.btn_ok?.getChildByName("lab_ok")?.getComponent(Label) ?? null;
|
||||
}
|
||||
if (!this.lab_cancel) {
|
||||
this.lab_cancel = this.btnCancel?.getChildByName("lab_cancel")?.getComponent(Label) ?? null;
|
||||
this.lab_cancel = this.btn_cancel?.getChildByName("lab_cancel")?.getComponent(Label) ?? null;
|
||||
}
|
||||
if (!this.lab_content) {
|
||||
this.lab_content = this.node.getChildByName("lab_content")?.getComponent(RichText) ?? null;
|
||||
@@ -127,8 +134,8 @@ export class CommonPrompt extends Component {
|
||||
}
|
||||
|
||||
onDestroy() {
|
||||
this.btnOk?.off(Button.EventType.CLICK, this.onOk, this);
|
||||
this.btnCancel?.off(Button.EventType.CLICK, this.onCancel, this);
|
||||
this.btn_ok?.off(Button.EventType.CLICK, this.onOk, this);
|
||||
this.btn_cancel?.off(Button.EventType.CLICK, this.onCancel, this);
|
||||
Tween.stopAllByTarget(this.node);
|
||||
this.config = {};
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@ import { GameEvent } from "../common/config/GameEvent";
|
||||
import { HeroInfo } from "../common/config/heroSet";
|
||||
import { HeroAttrsComp } from "../hero/HeroAttrsComp";
|
||||
import { Hero } from "../hero/Hero";
|
||||
import { getLvColor } from "../common/config/GameSet";
|
||||
import { FacSet, getLvColor } from "../common/config/GameSet";
|
||||
import { buildSkillDescRich } from "../common/config/HeroSkillDesc";
|
||||
import { MissionEconomy } from "./MissionEconomy";
|
||||
import { UIID } from "../common/config/GameUIConfig";
|
||||
@@ -189,6 +189,11 @@ export class HeroBoxComp extends CCComp {
|
||||
*/
|
||||
private onSellHeroClick() {
|
||||
if (!this.eid || !this.model) return;
|
||||
// 场上仅剩 1 个英雄时不允许出售(至少保留一个作战单位)
|
||||
if (HeroBoxComp.getAliveHeroCount() <= 1) {
|
||||
oops.gui.toast("至少保留 1 个英雄");
|
||||
return;
|
||||
}
|
||||
oops.audio.playEffect("music/button");
|
||||
|
||||
const heroName = this.model.hero_name ?? "";
|
||||
@@ -453,6 +458,20 @@ export class HeroBoxComp extends CCComp {
|
||||
|
||||
// ======================== 内部工具 ========================
|
||||
|
||||
/**
|
||||
* 统计场上存活英雄数量(与 MissionCardComp.getAliveHeroCount 口径一致)。
|
||||
*/
|
||||
private static getAliveHeroCount(): number {
|
||||
let count = 0;
|
||||
ecs.query(ecs.allOf(HeroAttrsComp)).forEach((entity: ecs.Entity) => {
|
||||
const model = entity.get(HeroAttrsComp);
|
||||
if (model && model.fac === FacSet.HERO) {
|
||||
count++;
|
||||
}
|
||||
});
|
||||
return count;
|
||||
}
|
||||
|
||||
/**
|
||||
* 写入一行战斗信息(总值 + 附加值)。
|
||||
* 总值始终显示(0 不隐藏);附加值为 0 时隐藏,正/负分别显示 (+x) / (x)。
|
||||
|
||||
Reference in New Issue
Block a user