原文地址 http://cn.cocos2d-x.org/article/index?type=quick_doc&url=/doc/cocos-docs-master/manual/framework/quick/V3/touch-events/zh.md

Quick 中的触摸事件

Cocos2d-x 原本的触摸机制存在一些限制,在使用中需要开发者做不少额外的处理。所以 Quick-Cocos2d-x 提出了自己的一套触摸机制。本文详细介绍了这套新机制的用法。

显示层级

在 Cocos2d-x 里,整个游戏的画面是由一系列的 Scene, Node, Sprite, Layer 等对象构成的。而所有这些对象都是从 Node 这个类继承而来。我们可以将 Node 称为显示节点

一个游戏画面就是许多显示节点构成的一棵树:

1
2
3
4
5
6
7
8
9
10
11
12
/|\
 | 显示层级
 |
 |         [Node]  [Node]  [Node]
 |           |       |       |
 |           +---+---+       |
 |               |           |
 |             [Node]      [Node]
 |               |           |
 |               +-----+-----+
 |                     |
 |                   [Node]

在这棵树里,Node 所处的垂直位置就是它们的显示层级。越往上的 Node,其显示层级就越高。从画面表现上来说,下面的 Node 是背景,上面的 Node 是建筑,那么建筑就会挡住一部分背景。

触摸区域

在 Cocos2d-x 里,只有 Layer 对象才能接受触摸事件。而 Layer 总是响应整个屏幕范围内的触摸,这就要求开发者在拿到触摸事件后,再做进一步的处理。

例如有一个需求是在玩家触摸屏幕上的方块时,人物角色做一个动作。那么使用 Layer 接受到触摸事件后,开发者需要自行判断触摸位置是否在方块之内。当屏幕上有很多东西需要响应玩家交互时,程序结构就开始变得复杂了。

所以 Quick-Cocos2d-x 允许开发者将任何一个 Node 设置为接受触摸事件。并且触摸事件一开始只会出现在这个 Node 的触摸区域内。

所谓触摸区域,就是一个 Node 及其所有子 Node 显示内容占据的屏幕空间。要注意的是这个屏幕空间包含了图片的透明部分。下图中,节点 A 是一个 Sprite 对象,它的触摸区域就是图片大小;而节点 B 是一个 Node 对象,其中包含了三个 Sprite 对象,那么节点 B 的触摸区域就是三个 Sprite 对象触摸区域的合集。

为了简化实现,触摸区域都是一个矩形,所以节点 B 的触摸区域实际上是一个“包含三个 Sprite 对象触摸区域合集的矩形”,可以参考上图中的红色边框线。

用法示例

下面列出触摸事件的用法示例,更详细的示例请参考 samples/touch 示例。

单点触摸事件

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
-- 允许 node 接受触摸事件
node:setTouchEnabled(true)
 
-- 注册触摸事件
node:addNodeEventListener(cc.NODE_TOUCH_EVENT, function(event)
    -- event.name 是触摸事件的状态:began, moved, ended, cancelled
    -- event.x, event.y 是触摸点当前位置
    -- event.prevX, event.prevY 是触摸点之前的位置
    printf("sprite: %s x,y: %0.2f, %0.2f",
           event.name, event.x, event.y)
 
    -- 在 began 状态时,如果要让 Node 继续接收该触摸事件的状态变化
    -- 则必须返回 true
    if event.name == "began" then
        return true
    end
end)

触摸事件的 event.name 指示了事件的状态:

  • began: 手指开始触摸屏幕。在 began 状态时,如果要继续接收该触摸事件的状态变化,事件处理函数必须返回 true
  • moved: 手指在屏幕上移动。
  • ended: 手指离开屏幕。
  • cancelled: 因为其他原因取消触摸操作。

多点触摸

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
-- 允许 node 接受触摸事件
node:setTouchEnabled(true)
 
-- 设置触摸模式
node:setTouchMode(cc.TOUCH_MODE_ALL_AT_ONCE) -- 多点
-- node:setTouchMode(cc.TOUCH_MODE_ONE_BY_ONE) -- 单点(默认模式)
 
-- 注册触摸事件
node:addNodeEventListener(cc.NODE_TOUCH_EVENT, function(event)
    -- event.name 是触摸事件的状态:began, moved, ended, cancelled
    -- 多点触摸增加了 added 和 removed 状态
    -- event.points 包含所有触摸点
    -- 按照 events.point[id] = {x = ?, y = ?} 的结构组织
    for id, point in pairs(event.points) do
        printf("event [%s] %s = %0.2f, %0.2f",
               event.name, id, point.x, point.y)
    end
 
    if event.name == "began" then
        return true
    end
end)

在多点触摸时,事件状态的含义有所区别:

  • began: 手指开始触摸屏幕。用户可能同时用多个手指接触屏幕,但因为硬件响应速度极快的原因,began状态时,event.points 中可能仍然只有一个触摸点的数据,其他触摸点数据会通过 added 状态提供。
  • added: 开始触摸后,如果有更多触摸点出现,则出现 added 状态。此时 event.points 中包含新加入的触摸点数据。
  • removed: 如果触摸结束前有触摸点消失(接触屏幕的部分手指离开了屏幕),则出现 removed 状态。此时event.points 中包含删除的触摸点数据。
  • ended: 如果所有触摸点都消失(所有手指都离开了屏幕),则出现 ended 状态。此时 event.points 中包含删除的触摸点数据。
  • moved: 由于多点触摸时,可能只有部分触摸点移动。所以此时 event.points 中只包含有变化的触摸点数据。

触摸事件吞噬

默认情况下,Node 在响应触摸后(在 began 状态返回 true 表示要响应触摸),就会阻止事件继续传递给 Node 的父对象(更下层的 Node),这称为触摸事件吞噬

如果要改变这个行为,可以用:

  • setTouchSwallowEnabled() 是否允许 Node 吞噬触摸,默认为 true。如果设置为 false,则 Node 响应触摸事件后,仍然会将事件继续传递给父对象。
  • isTouchSwallowEnabled() 检查 Node 是否允许吞噬触摸。

禁用触摸

对于一个 Node,随时可以启用或禁用其触摸事件:

  • setTouchEnabled() 是否允许 Node 响应触摸,默认为 false
  • isTouchEnabled() 检查 Node 是否允许触摸。

但即便禁用了 Node 的触摸事件,也只能阻止这个 Node 响应触摸,而不能阻止这个 Node 的子 Node 响应触摸。

假设有一个对话框(Node),我们需要禁止对话框中的所有 Node 响应触摸。那么需要禁止对话框 Node 捕获事件:

1
dialog:setTouchCaptureEnabled(false)
  • setTouchCaptureEnabled() 是否允许 Node 捕获触摸,默认为 true。当设置为 false 时,该 Node 及其所有子 Node 都无法得到触摸事件。
  • isTouchCaptureEnabled() 检查 Node 是否允许捕获触摸。

总结而言,setTouchEnabled() 只针对当前 Node,而 setTouchCaptureEnabled() 同时影响当前 Node 及其所有子 Node。

触摸事件的三个阶段

quick 中触摸事件分为三个阶段:capturing(捕获)、targeting(触发)、bubbling(冒泡)。

当用户的一根手指触摸到屏幕时,将产生一个触摸事件:

  1. 遍历所有响应触摸的 Node,找出显示层级最高,并且其触摸区域包含触摸位置的那个 Node。这个 Node 被称为 TargetNode(目标 Node)。
  2. 检查 TargetNode 的 isTouchCaptureEnabled() 结果,如果返回 false,则重复 1
    1. 从 TargetNode 的根 Node(通常是 Scene)开始,检查 cc.NODE_TOUCH_CAPTURE_EVENT 事件的返回结果。任何一个 Node 返回 false 都会阻止事件在 TargetNode 上触发。并从步骤 1 开始查找其他符合条件的 Node。
    2. 这个阶段被称为 capturing
  3. 在 TargetNode 上触发事件。这个阶段被称为 targeting
  4. 如果事件返回结果为 false,表示 TargetNode 不响应该事件,并从步骤 1 开始查找其他符合条件的 Node。
  5. 在 TargetNode 完成事件的响应后,检查 TargetNode:isTouchSwallowEnabled() 的返回值。如果是true,则取消 bubbling 阶段。
  6. 从 TargetNode 开始往其所有父 Node 触发事件,直到某个 Node 返回 false 或者事件被吞噬。这个阶段称为 bubbling

利用事件的三个阶段,我们可以注册 capturing 阶段的触摸事件处理函数:

1
2
3
4
5
6
7
-- 在 capturing 阶段就捕获事件
node:addNodeEventListener(cc.NODE_TOUCH_CAPTURE_EVENT, function(event)
    if event.name == "began" then
        -- 在 began 状态返回 false,将阻止事件
        return false
    end
end)

关于触摸机制的灵活运用,可以参考 cc.ui 中的各个 UI 控件,以及 samples/touch 示例。

API 参考

  • addNodeEventListener() 为 Node 的特定事件设置处理函数,返回一个 id 表示注册成功。
  • removeNodeEventListener() 从 Node 上移除指定类型的事件处理函数,需要提供addNodeEventListener() 返回的注册 id。
  • setTouchEnabled() 是否允许 Node 响应触摸,默认为 false
  • isTouchEnabled() 检查 Node 是否允许触摸。
  • setTouchMode() 设置触摸模式,默认为 cc.TOUCH_MODE_ONE_BY_ONE
  • getTouchMode() 返回 Node 当前的触摸模式。
  • setTouchCaptureEnabled() 是否允许 Node 捕获触摸,默认为 true
  • isTouchCaptureEnabled() 检查 Node 是否允许捕获触摸。
  • setTouchSwallowEnabled() 是否允许 Node 吞噬触摸,默认为 true
  • isTouchSwallowEnabled() 检查 Node 是否允许吞噬触摸。

【转载】Quick 中的触摸事件的更多相关文章

  1. 关于js-binding中Layer触摸事件的优化

    关于js-binding中Layer触摸事件的优化 cocos2d-x 3.7 1. 目前js中监听触摸事件带来的不便(特别是cocosbuilder) 在目前的js-binding中,如果要监听la ...

  2. iOS中的触摸事件和手势处理

    iOS中的事件可以分为三大类: 1> 触摸事件 2> 加速计事件 3> 远程控制事件 响应者对象 在iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并 ...

  3. cocos2dx中的触摸事件及触摸优先级

    1.只有CCLayer及其派生类才有触摸功能. 2.开启触摸 setTouchEnable(true); 3.设置触摸模式,单点,多点(仅IOS支持) setTouchMode(kCCTouchesO ...

  4. iOS中的触摸事件,手势识别,摇晃事件等

    在iOS中,事件可以划分为以下几类: 1.触摸事件:通过触摸,手势进行触发(手指点击.缩放等) 2.运动事件:通过加速器触发(例如手机晃动) 3.远程控制事件:通过其他远程设备触发(例如耳机控制按钮) ...

  5. 浅析iOS中的触摸事件

    一.什么是响应者对象? 在 iOS中不是任何对象都能处理事件,只有继承了UIResponder的对象才能接收并处理事件.我们称之为“响应者对象”.UIApplication.UIViewControl ...

  6. VIew中的触摸事件 touchBegin 等一系列方法

    5.触摸事件  touchBegin 等一系列方法 1)手指按下 - (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event; 2 ...

  7. 转载 -- C# 中的委托和事件

    原文地址:http://www.tracefact.net/CSharp-Programming/Delegates-and-Events-in-CSharp.aspx C# 中的委托和事件 引言 委 ...

  8. react-native中的触摸事件

    移动应用上的用户交互基本靠"摸".当然,"摸"也是有各种姿势的:在一个按钮上点击,在一个列表上滑动, 或是在一个地图上缩放.React Native 提供了可以 ...

  9. vue中使用触摸事件,上滑,下滑,等

    第一步,下载一个包 npm install kim-vue-touch -s 在当前项目中下载包 第二部 import vueTouch from 'kim-vue-touch' Vue.use(vu ...

随机推荐

  1. Java中I/O流之缓冲流

    Java 中的缓冲流: 1. 缓冲流要“套接”在相应的节点流之上,对读写的数据提供了缓冲的功能,提高了读写的效率,同时增加了一些新的方法(带缓冲区的,显著减少对 IO 的读写次数,保护硬盘). 2. ...

  2. 【linux】- nohup 和 &

    &的意思是在后台运行, 什么意思呢? 意思是说,当你在执行 ./a.out & 的时候,即使你用ctrl C,那么a.out照样运行(因为对SIGINT信号免疫).但是要注意,如果你直 ...

  3. git工具SourceTree工作流

    分支模型 master 用来最终上线的分支,最终发布版本,整个项目中有且只有一个 develop 项目中用来开发的分支,原则上项目中有且只有一个,develop 分支下面的分支是经常变化的,会创建新的 ...

  4. JXM 监控tomcat 7(含代码

    1.在tomcat的server.xml中加入: <Listener className="org.apache.catalina.mbeans.JmxRemoteLifecycleL ...

  5. CheckStateChanged(复选框选中状态更改事件)和 CheckedChanged(单选按钮选中状态更改事件)二者区别?

    CheckStateChanged(复选框选中状态更改事件)和 CheckedChanged(单选按钮选中状态更改事件)二者区别: 复选框控件(CheckBox)提供了CheckedChanged控件 ...

  6. 含html转义字符编码(&#22235;)转换--python

    在抓取下来的网页源码显示的是如下的内容,而不是可读性的汉字 (当然,如果是在Web页面上展示,则实体会自动被浏览器转为原字符,正常显示) 经查资料后得知, 在网页中以四开头的是HTML实体,具体什么是 ...

  7. 求助 delphi ADO组件的 CursorLocation属性设置为 clUseServer 用法 [问题点数:20分]

    我有个管理系统,所有ADOQUERY组件的 CursorLocation属性设置为 clUseClient,一直运行正常,我尝试全部设置为clUseServer, 系统不运行了,请大家帮忙. 我的做法 ...

  8. 【数据库】各种主流 SQLServer 迁移到 MySQL 工具对比

    在部署前期,首要任务就是考虑如何快速把基于 SQL Server 数据库的应用程序移植到阿里云的 MySQL 数据库.由于程序是基于 O/R mapping 编写,并且数据库中没有使用存储过程.用户函 ...

  9. 【bzoj3437】小P的牧场 斜率优化dp

    题目描述 背景 小P是个特么喜欢玩MC的孩纸... 描述 小P在MC里有n个牧场,自西向东呈一字形排列(自西向东用1…n编号),于是他就烦恼了:为了控制这n个牧场,他需要在某些牧场上面建立控制站,每个 ...

  10. asp.net AES加密跟PHP的一致,将加密的2进制byte[]转换为16进制byte[] 的字符串获得

    <?php class AESUtil { public static function encrypt($input, $key) { $size = mcrypt_get_block_siz ...