输入事件系统

EventTarget 支持了一套完整的 事件监听和发射机制 。在 Cocos Creator 3.4.0 中,我们支持了 input 对象,该对象实现了 EventTarget 的事件监听接口,可以通过 input 对象监听全局的系统输入事件。而原先的 systemEvent 对象则从 v3.4.0 开始废弃了,未来将逐步移除,建议使用 input 对象作为替代。

systemEventinput 二者的差异包括:

  • 在类型定义上的差异

    • systemEvent 的触摸事件回调的类型定义是 (touch: Touch, event: EventTouch) => void

    • input 的触摸事件回调的类型定义是 (event: EventTouch) => void

  • 在优先级上的差异

    • systemEvent 的事件监听器会被节点的事件监听器拦截

    • input 对象优先级比节点高,不会被拦截

      注意:我们在 v3.4.1 中降低了 input 优先级,因此二者从 v3.4.1 开始在优先级上已经不存在差异了。


本篇文档我们将介绍在 Cocos Creator 中对全局输入事件的处理。

全局输入事件是指与节点树不相关的各种输入事件,由 input 来统一派发,目前支持了以下几种事件:

  • 鼠标事件
  • 触摸事件
  • 键盘事件
  • 设备重力传感事件

定义输入事件

上文提到的输入事件,都可以通过接口 input.on(type, callback, target) 注册。可选的 type 类型包括:

输入事件type 类型
鼠标事件Input.EventType.MOUSE_DOWN
Input.EventType.MOUSE_MOVE
Input.EventType.MOUSE_UP
Input.EventType.MOUSE_WHEEL
触摸事件Input.EventType.TOUCH_START
Input.EventType.TOUCH_MOVE
Input.EventType.TOUCH_END
Input.EventType.TOUCH_CANCEL
键盘事件Input.EventType.KEY_DOWN(键盘按下)
Input.EventType.KEY_PRESSING(键盘持续按下)
Input.EventType.KEY_UP(键盘释放)
设备重力传感事件Input.EventType.DEVICEMOTION

指针事件

指针事件包括 鼠标事件触摸事件

  • 事件监听器类型

    • 鼠标事件监听

      • Input.EventType.MOUSE_DOWN

      • Input.EventType.MOUSE_MOVE

      • Input.EventType.MOUSE_UP

      • Input.EventType.MOUSE_WHEEL

    • 触摸事件监听

      • Input.EventType.TOUCH_START

      • Input.EventType.TOUCH_MOVE

      • Input.EventType.TOUCH_CANCEL

      • Input.EventType.TOUCH_END

  • 事件触发后的回调函数

    • 自定义回调函数:callback(event);
  • 回调参数

指针事件的使用范例如下:

  1. import { _decorator, Component, input, Input, EventTouch } from 'cc';
  2. const { ccclass } = _decorator;
  3. @ccclass("Example")
  4. export class Example extends Component {
  5. onLoad () {
  6. input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
  7. }
  8. onDestroy () {
  9. input.off(Input.EventType.TOUCH_START, this.onTouchStart, this);
  10. }
  11. onTouchStart(event: EventTouch) {
  12. console.log(event.getLocation()); // Location on screen space
  13. console.log(event.getUILocation()); // Location on UI space
  14. }
  15. }

键盘事件

  • 事件监听器类型

    • Input.EventType.KEY_DOWN

    • Input.EventType.KEY_PRESSING

    • Input.EventType.KEY_UP

  • 事件触发后的回调函数

    • 自定义回调函数:callback(event);
  • 回调参数

使用键盘事件的代码示例如下:

  1. import { _decorator, Component, input, Input, EventKeyboard, KeyCode } from 'cc';
  2. const { ccclass } = _decorator;
  3. @ccclass("Example")
  4. export class Example extends Component {
  5. onLoad () {
  6. input.on(Input.EventType.KEY_DOWN, this.onKeyDown, this);
  7. input.on(Input.EventType.KEY_UP, this.onKeyUp, this);
  8. }
  9. onDestroy () {
  10. input.off(Input.EventType.KEY_DOWN, this.onKeyDown, this);
  11. input.off(Input.EventType.KEY_UP, this.onKeyUp, this);
  12. }
  13. onKeyDown (event: EventKeyboard) {
  14. switch(event.keyCode) {
  15. case KeyCode.KEY_A:
  16. console.log('Press a key');
  17. break;
  18. }
  19. }
  20. onKeyUp (event: EventKeyboard) {
  21. switch(event.keyCode) {
  22. case KeyCode.KEY_A:
  23. console.log('Release a key');
  24. break;
  25. }
  26. }
  27. }

设备重力传感事件

  • 事件监听器类型

    • Input.EventType.DEVICEMOTION
  • 事件触发后的回调函数

    • 自定义回调函数:callback(event);
  • 回调参数

使用设备重力传感事件的代码示例如下:

  1. import { _decorator, Component, input, Input, log } from 'cc';
  2. const { ccclass } = _decorator;
  3. @ccclass("Example")
  4. export class Example extends Component {
  5. onLoad () {
  6. input.setAccelerometerEnabled(true);
  7. input.on(Input.EventType.DEVICEMOTION, this.onDeviceMotionEvent, this);
  8. }
  9. onDestroy () {
  10. input.off(Input.EventType.DEVICEMOTION, this.onDeviceMotionEvent, this);
  11. }
  12. onDeviceMotionEvent (event: EventAcceleration) {
  13. log(event.acc.x + " " + event.acc.y);
  14. }
  15. }

具体使用方法可参考范例 eventGitHub | Gitee),其中包含了键盘、重力感应、单点触摸、多点触摸等功能的实现。

3D 物体的触摸检测

3D 物体与 2D UI 节点的触摸检测不同:

  • 2D UI 节点只需要通过 UITransform 组件提供的尺寸信息和节点的位置信息,就可以实现触摸检测,详情请参考 节点事件系统

  • 3D 物体的触摸检测需要通过射线检测来实现。具体做法是通过渲染 3D 物体的 Camera 到触点的屏幕坐标,生成一条射线,判断射线是否穿过想要检测的对象。具体代码实现如下:

    1. import { _decorator, Component, Node, Camera, geometry, input, Input, EventTouch, PhysicsSystem } from 'cc';
    2. const { ccclass, property } = _decorator;
    3. @ccclass("Example")
    4. export class Example extends Component {
    5. // Specify the camera rendering the target node.
    6. @property(Camera)
    7. readonly cameraCom!: Camera;
    8. @property(Node)
    9. public targetNode!: Node
    10. private _ray: geometry.Ray = new geometry.Ray();
    11. onEnable () {
    12. input.on(Input.EventType.TOUCH_START, this.onTouchStart, this);
    13. }
    14. onDisable () {
    15. input.off(Input.EventType.TOUCH_START, this.onTouchStart, this);
    16. }
    17. onTouchStart(event: EventTouch) {
    18. const touch = event.touch!;
    19. this.cameraCom.screenPointToRay(touch.getLocationX(), touch.getLocationY(), this._ray);
    20. if (PhysicsSystem.instance.raycast(this._ray)) {
    21. const raycastResults = PhysicsSystem.instance.raycastResults;
    22. for (let i = 0; i < raycastResults.length; i++) {
    23. const item = raycastResults[i];
    24. if (item.collider.node == this.targetNode) {
    25. console.log('raycast hit the target node !');
    26. break;
    27. }
    28. }
    29. } else {
    30. console.log('raycast does not hit the target node !');
    31. }
    32. }
    33. }