diff --git a/assets/resources/gui/element/SInfoBox.prefab b/assets/resources/gui/element/SInfoBox.prefab index 99f0a105..30a3b6fb 100644 --- a/assets/resources/gui/element/SInfoBox.prefab +++ b/assets/resources/gui/element/SInfoBox.prefab @@ -1691,6 +1691,9 @@ "lv3_desc": { "__id__": 185 }, + "close_btn": { + "__id__": 95 + }, "_id": "" }, { diff --git a/assets/script/game/map/SinfoComp.ts b/assets/script/game/map/SinfoComp.ts index 8cbd2742..5510428f 100644 --- a/assets/script/game/map/SinfoComp.ts +++ b/assets/script/game/map/SinfoComp.ts @@ -25,7 +25,7 @@ * - SkillCardList / EquipPoolList(卡牌静态配置) * - HeroSkillDesc(buildCardDescRich 富文本描述生成) */ -import { _decorator, Node, Label, RichText, NodeEventType, Sprite, Color, input, Input, EventTouch } from "cc"; +import { _decorator, Node, Label, RichText, NodeEventType, Sprite, Color, input, Input, EventTouch, UITransform, Vec3 } 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"; @@ -104,6 +104,10 @@ export class SinfoComp extends CCComp { @property({ type: RichText, displayName: "3级提升说明" }) private lv3_desc: RichText = null; + /** 关闭按钮节点 */ + @property({ type: Node, displayName: "关闭按钮" }) + private close_btn: Node = null; + // ======================== 运行时状态 ======================== /** 弹窗参数 */ @@ -112,8 +116,13 @@ export class SinfoComp extends CCComp { // ======================== 生命周期 ======================== onLoad() { - // 点击弹窗自身(BlockInputEvents 拦截)不关闭,仅点击外部遮罩关闭 + // 点击弹窗自身:阻止冒泡,由全局触摸判定触点位置决定是否关闭 this.node.on(NodeEventType.TOUCH_END, this.onSelfTouch, this); + // 关闭按钮:编辑器未绑定时按节点名 "close" 兜底查找 + if (!this.close_btn) { + this.close_btn = this.node.getChildByName("close"); + } + this.close_btn?.on(NodeEventType.TOUCH_END, this.onCloseClick, this); } onDestroy() { @@ -121,6 +130,9 @@ export class SinfoComp extends CCComp { if (this.node && this.node.isValid) { this.node.off(NodeEventType.TOUCH_END, this.onSelfTouch, this); } + if (this.close_btn && this.close_btn.isValid) { + this.close_btn.off(NodeEventType.TOUCH_END, this.onCloseClick, this); + } // 注销全局触摸监听 input.off(Input.EventType.TOUCH_END, this.onGlobalTouch, this); } @@ -143,12 +155,32 @@ export class SinfoComp extends CCComp { event.propagationStopped = true; } - /** 全局触摸结束:点击弹窗外部关闭 */ - private onGlobalTouch() { - // 若点击落在弹窗内部(被 BlockInputEvents 拦截)则不会走到这里 + /** 关闭按钮点击 */ + private onCloseClick(event: EventTouch) { + // 阻止冒泡,避免同时触发 onSelfTouch / onGlobalTouch 双重关闭 + event.propagationStopped = true; + oops.audio.playEffect("music/button"); this.close(); } + /** 全局触摸结束:触点落在弹窗包围盒外才关闭 */ + private onGlobalTouch(event: EventTouch) { + if (!this.node || !this.node.isValid) return; + // 触点 UI 坐标 → 弹窗局部坐标,判定是否在弹窗内(convertToNodeSpaceAR 需要 Vec3) + const uit = this.node.getComponent(UITransform); + if (!uit) return; + const uiPos = event.getUILocation(); + const localPos = uit.convertToNodeSpaceAR(new Vec3(uiPos.x, uiPos.y, 0)); + const halfW = uit.contentSize.width * uit.anchorX; + const halfH = uit.contentSize.height * uit.anchorY; + const inBox = + localPos.x >= -halfW && localPos.x <= uit.contentSize.width - halfW && + localPos.y >= -halfH && localPos.y <= uit.contentSize.height - halfH; + if (!inBox) { + this.close(); + } + } + /** 关闭弹窗 */ private close() { oops.gui.removeByNode(this.node);