首页 / 技术文章地图 / 正文

【界面UI】Cocos2d-x 触摸事件优先级与吞噬:点击穿透排查指南

发布:2026-09-20 08:45 | 作者:996 技术组 | 3 阅读
完整课程入口:996 全套课程体系Lua 学习路径幂尔框架 mirs.cn

实战应用:用在哪里

两个经典 UI 事故:点按钮把按钮下面一层的"关闭区域"也触发了(点击穿透);全屏遮罩挡不住后面的界面(吞事件失败)。两者都源于对 Cocos 触摸事件分发顺序与吞噬机制的理解不足。本文给出一套排查顺序与标准写法。

分发顺序:谁先收到触摸

Cocos2d-x 3.x 的事件监听按注册时的优先级分发:addEventListenerWithSceneGraphPriority 按节点在场景树中的绘制顺序(越靠上层节点越先收到);固定优先级模式(数值越小越先)。996 客户端的 GUI 封装统一走场景树优先级,所以规律是:上层界面先拿到触摸,处理完可选择吞掉

吞噬:setSwallowTouches

lua
local listener = cc.EventListenerTouchOneByOne:create()
listener:setSwallowTouches(true)          -- 命中后吞掉,不再下传
listener:registerScriptHandler(function(touch, event)
    return true                            -- onTouchBegan 返回 true 才会吞
end, cc.Handler.EVENT_TOUCH_BEGAN)
cc.Director:getInstance():getEventDispatcher()
    :addEventListenerWithSceneGraphPriority(listener, maskNode)

两个条件缺一不可:setSwallowTouches(true) 加上 onTouchBegan 返回 true。半透明遮罩挡不住点击,九成是Began 返回了 false 或压根没注册监听。

排查口诀:从上往下找第一个返回 true 的监听

点击穿透排查按固定顺序:打印事件分发日志(重写 Dispatcher 或挂调试监听),确认触摸事件到达了哪些节点;从最上层节点往下检查每个 onTouchBegan 的返回值;检查按钮的 hitTest 区域是否与预期一致(子控件超出父节点边界时,命中区域计算会出现偏差)。反向问题——"整个界面点不动"——通常是某层透明节点开了 swallow 且 Began 恒返回 true,覆盖了全屏。

一个易被忽略的细节

节点 setVisible(false) 后监听仍在分发链上(部分版本行为),隐藏遮罩时同步 getEventDispatcher():removeEventListener(listener) 或复用控件时确保监听状态与可见性一致。规范做法:界面基类统一管理监听的注册与移除(onEnter 注册、onExit 移除),子界面只写回调——事件与节点生命周期绑定后,穿透与泄漏两类问题都会显著减少。

作者履历与出处
本文由 996 技术组基于 996 引擎官方知识库与浮生梦老师课程体系整理,讲解体系出自多年商业端开发生产一线。作者团队长期从事传奇类引擎 Lua 后端逻辑、客户端界面与版本交付,内容以官方知识库与真实项目为出处,按版本持续修订。
© 威海旷世互娱 · 返回文章地图 · 课程体系 · 幂尔框架