【Laya】InputManager 输入管理器

Laya.InputManager 输入管理器

版本: v3.3.6 | 模块: laya/events/InputManager


概述

Laya.InputManager 是 LayaAir 引擎的输入事件管理类,负责处理鼠标、触摸和键盘等输入事件。


静态属性

开关控制

属性 类型 默认值 说明
multiTouchEnabled boolean true 是否开启多点触控支持
mouseEventsEnabled boolean true 是否开启鼠标/触摸事件
keyEventsEnabled boolean true 是否开启键盘事件
clickTestThreshold number 10 鼠标按下和弹起位置距离阈值,超过此值不视为点击

鼠标位置

属性 类型 说明
mouseX number canvas 上鼠标的 X 坐标
mouseY number canvas 上鼠标的 Y 坐标
lastMouseTime number 上一次鼠标事件的时间

触摸相关

属性 类型 说明
touchCount number (只读) 当前触摸数量
touches TouchInfo[] (只读) 当前触摸信息数组
touchTarget Node (只读) 当前触摸目标节点
lastTouchId number 上一次触摸事件的 ID

回调

属性 类型 说明
onMouseDownCapture Delegate (只读) 在处理 MOUSE_DOWN 事件之前调度,可用于预处理按下事件

静态方法

实例获取

typescript 复制代码
static get inst(): InputManager

获取 InputManager 单例实例。


触摸位置

typescript 复制代码
static getTouchPos(touchId?: number): Point

获取指定触摸点的位置。

参数:

  • touchId: 触摸点 ID,不提供则返回 lastTouchId 对应的触摸点位置

返回: Point - 触摸点的位置


键盘检测

typescript 复制代码
static hasKeyDown(key: string | number): boolean

返回指定键是否被按下。

参数:

  • key: 键值(支持 key 字符串或 keyCode 数字)

返回: boolean - 是否被按下

常用键值:

按键 key 值 keyCode 按键 key 值 keyCode
W "w" 87 A "a" 65
S "s" 83 D "d" 68
空格 " " 32 ESC "Escape" 27
Shift "Shift" 16 Enter "Enter" 13

取消点击

typescript 复制代码
static cancelClick(touchId?: number): void

取消指定触摸点的点击事件(将 clickCancelled 设为 true)。

参数:

  • touchId: 要取消的触摸事件 ID,不提供则使用 lastTouchId

实例方法

获取节点

typescript 复制代码
getNodeUnderPoint(x: number, y: number): Node

获取指定坐标下的节点。

参数:

  • x: X 坐标值(已除以 clientScaleX)
  • y: Y 坐标值(已除以 clientScaleY)

返回: Node - 该点下的节点,如果没有找到节点则返回舞台


typescript 复制代码
getSpriteUnderPoint(sp: Sprite, x: number, y: number): Sprite

获取在相对 Sprite 指定坐标下的 Sprite。


typescript 复制代码
getSprite3DUnderPoint(x: number, y: number): Node

获取 3D 场景中指定坐标下的 3D 节点(源码中返回 null,由子类实现)。


碰撞检测

typescript 复制代码
hitTest(sp: Sprite, x: number, y: number, editing?: boolean): boolean

检测指定坐标是否命中 Sprite。

命中规则(源码逻辑):

typescript 复制代码
if (sp.width > 0 && sp.height > 0 || mouseThrough || hitArea) {
    if (!mouseThrough)
        isHit = (0, 0, sp.width, sp.height).contains(x, y);
    else
        isHit = sp.getGraphicBounds(false).contains(x, y);
}

重要说明

graphics 绘图必须设置 size

使用 graphics.drawCircle、graphics.drawRect 等方法绘制的内容不会自动设置 Sprite 的宽高。

hitTest 方法检测条件 : sp.width > 0 && sp.height > 0

因此必须手动调用 size() 设置宽高,否则鼠标事件无法正确检测。

typescript 复制代码
// ❌ 错误:width=0, height=0,hitTest 返回 false
const sprite = new Laya.Sprite();
sprite.graphics.drawRect(0, 0, 100, 100, "#FF0000");
console.log(sprite.width, sprite.height); // 0, 0

// ✅ 正确:设置 size 后
sprite.size(100, 100);
console.log(sprite.width, sprite.height); // 100, 100

使用示例

示例 1: 鼠标位置追踪

typescript 复制代码
export class MouseTrackExample {
    private sprite: Laya.Sprite;

    constructor() {
        Laya.init(800, 600).then(() => {
            this.init();
        });
    }

    private init(): void {
        this.sprite = new Laya.Sprite();
        this.sprite.graphics.drawCircle(0, 0, 20, "#FF0000");
        this.sprite.size(40, 40);  // 必须设置 size
        Laya.stage.addChild(this.sprite);

        Laya.stage.on(Laya.Event.MOUSE_MOVE, this, this.onMouseMove);
    }

    private onMouseMove(): void {
        this.sprite.x = Laya.InputManager.mouseX;
        this.sprite.y = Laya.InputManager.mouseY;
    }
}

示例 2: 多点触控

typescript 复制代码
export class MultiTouchExample {
    private text: Laya.Text;
    private touches: Laya.Sprite[] = [];

    constructor() {
        Laya.init(0, 0).then(() => {
            this.init();
        });
    }

    private init(): void {
        this.text = new Laya.Text();
        this.text.fontSize = 30;
        this.text.color = "#FFFFFF";
        Laya.stage.addChild(this.text);

        Laya.timer.frameLoop(1, this, this.update);
    }

    private update(): void {
        this.text.text = `触控点数量: ${Laya.InputManager.touchCount}`;

        for (let i = 0; i < Laya.InputManager.touches.length; i++) {
            let touchSprite = this.touches[i];
            if (!touchSprite) {
                touchSprite = new Laya.Sprite();
                touchSprite.graphics.drawCircle(0, 0, 30, "#00FF00");
                touchSprite.size(60, 60);  // 必须设置 size
                Laya.stage.addChild(touchSprite);
                this.touches[i] = touchSprite;
            }

            const pos = Laya.InputManager.getTouchPos(i);
            touchSprite.pos(pos.x, pos.y);
        }
    }
}

示例 3: 键盘控制

typescript 复制代码
export class KeyboardControlExample {
    private player: Laya.Sprite3D;
    private speed: number = 0.1;

    constructor() {
        Laya.init(0, 0).then(() => {
            this.init();
        });
    }

    private init(): void {
        // 创建玩家对象...
        Laya.timer.frameLoop(1, this, this.onUpdate);
    }

    private onUpdate(): void {
        const movement = new Laya.Vector3();

        if (Laya.InputManager.hasKeyDown("w")) movement.z -= this.speed;
        if (Laya.InputManager.hasKeyDown("s")) movement.z += this.speed;
        if (Laya.InputManager.hasKeyDown("a")) movement.x -= this.speed;
        if (Laya.InputManager.hasKeyDown("d")) movement.x += this.speed;

        if (movement.length() > 0) {
            this.player.transform.translate(movement);
        }
    }
}

示例 4: 取消点击判定

typescript 复制代码
export class CancelClickExample {
    private sprite: Laya.Sprite;

    constructor() {
        Laya.init(800, 600).then(() => {
            this.init();
        });
    }

    private init(): void {
        this.sprite = new Laya.Sprite();
        this.sprite.graphics.drawRect(0, 0, 100, 100, "#FF0000");
        this.sprite.size(100, 100);
        Laya.stage.addChild(this.sprite);

        this.sprite.on(Laya.Event.MOUSE_MOVE, this, () => {
            // 鼠标移动时取消点击判定
            Laya.InputManager.cancelClick();
        });

        this.sprite.on(Laya.Event.CLICK, this, () => {
            console.log("只有不拖动才会触发");
        });
    }
}

常见问题

Q: 用 graphics 画图为什么不触发鼠标事件?

必须设置 size(),因为 hitTest 检测条件是 sp.width > 0 && sp.height > 0。

Q: 为什么 hasKeyDown 检测不到按键?

确保 Laya.InputManager.keyEventsEnabled = true。

Q: 如何禁用多点触控?

typescript 复制代码
Laya.InputManager.multiTouchEnabled = false;

Q: 如何判断是点击还是拖拽?

源码中 clickCancelled 在移动距离超过 clickTestThreshold 时设为 true,可通过 Laya.InputManager.cancelClick() 手动取消。


事件流程

源码中的事件处理流程:

  1. 鼠标事件 (handleMouse):

    • mousedown → handleMouse(ev, 0) → Event.MOUSE_DOWN
    • mouseup → handleMouse(ev, 1) → Event.MOUSE_UP → Event.CLICK
    • mousemove → handleMouse(ev, 2) → Event.MOUSE_MOVE
    • wheel → handleMouse(ev, 4) → Event.MOUSE_WHEEL
  2. 触摸事件 (handleTouch):

    • touchstart → handleTouch(ev, 0) → Event.MOUSE_DOWN
    • touchend → handleTouch(ev, 1) → Event.MOUSE_UP → Event.CLICK
    • touchmove → handleTouch(ev, 2) → Event.MOUSE_MOVE
  3. 键盘事件 (handleKeys):

    • keydown / keyup → Event.KEY_DOWN / Event.KEY_UP

相关类

类 说明
Laya.Event 事件类型常量定义
Laya.TouchInfo 触摸信息结构
Laya.Keyboard 键盘事件常量
相关推荐
警醒与鞭策5 小时前
【无标题】
android·unity·性能优化·游戏引擎·perforce
zhchyun20087 小时前
【Unity UI 进阶】仿 Element UI 打造企业级 Unity UI 组件库(10)
ui·unity·游戏引擎
地狱为王11 小时前
Unity使用NVIDIA的Audio2Face驱动口型
unity·游戏引擎
seowmt17 小时前
结构化数据和自然语言描述哪个更管用?答案分场景
人工智能·google·typescript·go语言·schema
一线灵19 小时前
跨平台游戏引擎 Axmol-2.11.5 发布
游戏引擎·lua
淡海水19 小时前
16-01-C#数据结构源码-附录A-术语表
unity·c#·游戏引擎·il2cpp
进击的明明19 小时前
TypeScript速通笔记(上)
前端·面试·typescript
淡海水20 小时前
16-03-C#数据结构源码-附录C-参考资源
unity·c#·游戏引擎·il2cpp
天神哥哥啊20 小时前
unity联调注意事项-安卓
android·unity·游戏引擎
天神哥哥啊20 小时前
unity联调注意事项-IOS
unity·ios·游戏引擎