7、键盘、鼠标和触摸输入

223 阅读6分钟

在 LibGDX 中,处理用户输入(如键盘、鼠标和触摸输入)是通过 Gdx.input 模块实现的。LibGDX 提供了多种方式来处理输入事件,包括轮询输入状态和注册事件监听器。以下是详细的说明和示例代码:


1. 轮询输入状态

轮询输入状态是指每一帧都检查输入设备的状态(如按键是否按下、鼠标位置等)。这种方式适合处理实时输入。

键盘输入

  • 使用 Gdx.input.isKeyPressed() 检查某个按键是否被按下。
  • 示例:
    if (Gdx.input.isKeyPressed(Input.Keys.LEFT)) {
        player.moveLeft(); // 按下左键时移动角色
    }
    if (Gdx.input.isKeyPressed(Input.Keys.RIGHT)) {
        player.moveRight(); // 按下右键时移动角色
    }
    

鼠标输入

  • 使用 Gdx.input.isButtonPressed() 检查鼠标按键是否被按下。
  • 使用 Gdx.input.getX()Gdx.input.getY() 获取鼠标位置。
  • 示例:
    if (Gdx.input.isButtonPressed(Input.Buttons.LEFT)) {
        // 按下鼠标左键时执行操作
        float mouseX = Gdx.input.getX();
        float mouseY = Gdx.input.getY();
        System.out.println("Mouse clicked at: " + mouseX + ", " + mouseY);
    }
    

触摸输入

  • 使用 Gdx.input.isTouched() 检查屏幕是否被触摸。
  • 使用 Gdx.input.getX()Gdx.input.getY() 获取触摸位置。
  • 示例:
    if (Gdx.input.isTouched()) {
        // 屏幕被触摸时执行操作
        float touchX = Gdx.input.getX();
        float touchY = Gdx.input.getY();
        System.out.println("Touched at: " + touchX + ", " + touchY);
    }
    

2. 注册事件监听器

事件监听器是一种更高级的输入处理方式,适合处理离散的输入事件(如按键按下、鼠标点击)。

实现 InputProcessor 接口

  • InputProcessor 是一个接口,定义了处理输入事件的方法。
  • 示例:
    public class MyInputProcessor implements InputProcessor {
        @Override
        public boolean keyDown(int keycode) {
            if (keycode == Input.Keys.SPACE) {
                System.out.println("Space key pressed");
            }
            return true; // 返回 true 表示事件已处理
        }
    
        @Override
        public boolean keyUp(int keycode) {
            if (keycode == Input.Keys.SPACE) {
                System.out.println("Space key released");
            }
            return true;
        }
    
        @Override
        public boolean keyTyped(char character) {
            System.out.println("Key typed: " + character);
            return true;
        }
    
        @Override
        public boolean touchDown(int screenX, int screenY, int pointer, int button) {
            System.out.println("Touch down at: " + screenX + ", " + screenY);
            return true;
        }
    
        @Override
        public boolean touchUp(int screenX, int screenY, int pointer, int button) {
            System.out.println("Touch up at: " + screenX + ", " + screenY);
            return true;
        }
    
        @Override
        public boolean touchDragged(int screenX, int screenY, int pointer) {
            System.out.println("Touch dragged to: " + screenX + ", " + screenY);
            return true;
        }
    
        @Override
        public boolean mouseMoved(int screenX, int screenY) {
            System.out.println("Mouse moved to: " + screenX + ", " + screenY);
            return true;
        }
    
        @Override
        public boolean scrolled(float amountX, float amountY) {
            System.out.println("Scrolled: " + amountX + ", " + amountY);
            return true;
        }
    }
    

注册监听器

  • 使用 Gdx.input.setInputProcessor() 注册输入处理器。
  • 示例:
    @Override
    public void create() {
        Gdx.input.setInputProcessor(new MyInputProcessor());
    }
    

好的,继续介绍如何使用 InputMultiplexer 处理多个输入源,以及结合 LibGDX 的输入处理机制。


3. 结合 InputMultiplexer 处理多个输入源

InputMultiplexer 是 LibGDX 提供的一个工具类,用于将多个 InputProcessor 组合在一起,按顺序处理输入事件。这在需要同时处理 UI 输入和游戏逻辑输入时非常有用。

使用步骤

  1. 创建 InputMultiplexer 对象
    • 在游戏初始化时创建 InputMultiplexer 对象。
  2. 添加多个 InputProcessor
    • 将多个 InputProcessor 添加到 InputMultiplexer 中。
  3. 注册 InputMultiplexer
    • 使用 Gdx.input.setInputProcessor() 注册 InputMultiplexer

示例代码

以下是一个完整的示例,展示如何使用 InputMultiplexer 处理多个输入源:

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputMultiplexer;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.GL20;

public class MyGame implements ApplicationListener {
    @Override
    public void create() {
        // 创建 InputMultiplexer
        InputMultiplexer multiplexer = new InputMultiplexer();

        // 添加多个 InputProcessor
        multiplexer.addProcessor(new GameInputProcessor()); // 游戏逻辑输入处理器
        multiplexer.addProcessor(new UIInputProcessor());   // UI 输入处理器

        // 注册 InputMultiplexer
        Gdx.input.setInputProcessor(multiplexer);
    }

    @Override
    public void render() {
        // 清空屏幕
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
    }

    @Override
    public void resize(int width, int height) {
        // 窗口大小改变时调用
    }

    @Override
    public void pause() {
        // 游戏进入后台时调用
    }

    @Override
    public void resume() {
        // 游戏从后台恢复时调用
    }

    @Override
    public void dispose() {
        // 释放资源
    }
}

// 游戏逻辑输入处理器
class GameInputProcessor implements InputProcessor {
    @Override
    public boolean keyDown(int keycode) {
        if (keycode == Input.Keys.SPACE) {
            System.out.println("Game: Space key pressed");
        }
        return true;
    }

    @Override
    public boolean keyUp(int keycode) {
        if (keycode == Input.Keys.SPACE) {
            System.out.println("Game: Space key released");
        }
        return true;
    }

    @Override
    public boolean keyTyped(char character) {
        return false;
    }

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        System.out.println("Game: Touch down at " + screenX + ", " + screenY);
        return true;
    }

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
        System.out.println("Game: Touch up at " + screenX + ", " + screenY);
        return true;
    }

    @Override
    public boolean touchDragged(int screenX, int screenY, int pointer) {
        System.out.println("Game: Touch dragged to " + screenX + ", " + screenY);
        return true;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        return false;
    }

    @Override
    public boolean scrolled(float amountX, float amountY) {
        return false;
    }
}

// UI 输入处理器
class UIInputProcessor implements InputProcessor {
    @Override
    public boolean keyDown(int keycode) {
        if (keycode == Input.Keys.ESCAPE) {
            System.out.println("UI: Escape key pressed");
        }
        return true;
    }

    @Override
    public boolean keyUp(int keycode) {
        if (keycode == Input.Keys.ESCAPE) {
            System.out.println("UI: Escape key released");
        }
        return true;
    }

    @Override
    public boolean keyTyped(char character) {
        return false;
    }

	@Override
	public boolean touchDown(int screenX, int screenY, int pointer, int button) {
	    System.out.println("UI: Touch down at " + screenX + ", " + screenY);
	    return true;
	}
	
	@Override
	public boolean touchUp(int screenX, int screenY, int pointer, int button) {
	    System.out.println("UI: Touch up at " + screenX + ", " + screenY);
	    return true;
	}
	
	@Override
	public boolean touchDragged(int screenX, int screenY, int pointer) {
	    System.out.println("UI: Touch dragged to " + screenX + ", " + screenY);
	    return true;
	}
	
	@Override
	public boolean mouseMoved(int screenX, int screenY) {
	    System.out.println("UI: Mouse moved to " + screenX + ", " + screenY);
	    return true;
	}
	
	@Override
	public boolean scrolled(float amountX, float amountY) {
	    System.out.println("UI: Scrolled by " + amountX + ", " + amountY);
	    return true;
	}
	

4. 输入处理的最佳实践

1. 分离游戏逻辑和 UI 输入

  • 使用 InputMultiplexer 将游戏逻辑输入和 UI 输入分开处理。
  • 游戏逻辑输入处理器负责处理角色移动、攻击等操作。
  • UI 输入处理器负责处理按钮点击、菜单操作等。

2. 使用轮询和事件监听结合

  • 轮询:适合处理实时输入(如角色移动)。
  • 事件监听:适合处理离散事件(如按键按下、鼠标点击)。

3. 处理多点触控

  • 使用 pointer 参数区分不同的触摸点。
  • 示例:
    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        System.out.println("Touch down by pointer " + pointer + " at " + screenX + ", " + screenY);
        return true;
    }
    

4. 处理鼠标滚轮

  • 使用 scrolled() 方法处理鼠标滚轮事件。
  • 示例:
    @Override
    public boolean scrolled(float amountX, float amountY) {
        System.out.println("Scrolled by " + amountX + ", " + amountY);
        return true;
    }
    

5. 处理键盘输入

  • 使用 keyDown()keyUp() 方法处理按键事件。
  • 示例:
    @Override
    public boolean keyDown(int keycode) {
        if (keycode == Input.Keys.SPACE) {
            System.out.println("Space key pressed");
        }
        return true;
    }
    

5. 完整示例代码

以下是一个完整的示例,展示如何结合轮询和事件监听处理输入:

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputMultiplexer;
import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.Input.Keys;

public class MyGame implements ApplicationListener {
    private float playerX = 100;
    private float playerY = 100;

    @Override
    public void create() {
        // 创建 InputMultiplexer
        InputMultiplexer multiplexer = new InputMultiplexer();

        // 添加游戏逻辑输入处理器
        multiplexer.addProcessor(new GameInputProcessor());

        // 注册 InputMultiplexer
        Gdx.input.setInputProcessor(multiplexer);
    }

    @Override
    public void render() {
        // 清空屏幕
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        // 轮询键盘输入
        if (Gdx.input.isKeyPressed(Keys.LEFT)) {
            playerX -= 5;
        }
        if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
            playerX += 5;
        }
    }

    @Override
    public void resize(int width, int height) {
        // 窗口大小改变时调用
    }

    @Override
    public void pause() {
        // 游戏进入后台时调用
    }

	@Override
	public void resume() {
	    // 游戏从后台恢复时调用
	}
	
	@Override
	public void dispose() {
	    // 释放资源
	}

	// 游戏逻辑输入处理器
	class GameInputProcessor implements InputProcessor {
    @Override
    public boolean keyDown(int keycode) {
        if (keycode == Keys.SPACE) {
            System.out.println("Game: Space key pressed");
        }
        return true;
    }

    @Override
    public boolean keyUp(int keycode) {
        if (keycode == Keys.SPACE) {
            System.out.println("Game: Space key released");
        }
        return true;
    }

    @Override
    public boolean keyTyped(char character) {
        return false;
    }

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        System.out.println("Game: Touch down at " + screenX + ", " + screenY);
        return true;
    }

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
        System.out.println("Game: Touch up at " + screenX + ", " + screenY);
        return true;
    }

    @Override
    public boolean touchDragged(int screenX, int screenY, int pointer) {
        System.out.println("Game: Touch dragged to " + screenX + ", " + screenY);
        return true;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        return false;
    }

    @Override
    public boolean scrolled(float amountX, float amountY) {
        return false;
    }
}

6. 输入处理的完整流程

1. 初始化输入处理器

  • create() 方法中初始化 InputMultiplexer 并注册输入处理器。
  • 示例:
    InputMultiplexer multiplexer = new InputMultiplexer();
    multiplexer.addProcessor(new GameInputProcessor());
    Gdx.input.setInputProcessor(multiplexer);
    

2. 处理实时输入(轮询)

  • render() 方法中使用 Gdx.input.isKeyPressed()Gdx.input.isButtonPressed() 检查输入状态。
  • 示例:
    if (Gdx.input.isKeyPressed(Keys.LEFT)) {
        playerX -= 5;
    }
    if (Gdx.input.isKeyPressed(Keys.RIGHT)) {
        playerX += 5;
    }
    

3. 处理离散事件(事件监听)

  • 实现 InputProcessor 接口,处理按键按下、鼠标点击等事件。
  • 示例:
    @Override
    public boolean keyDown(int keycode) {
        if (keycode == Keys.SPACE) {
            System.out.println("Space key pressed");
        }
        return true;
    }
    

4. 处理多点触控

  • 使用 pointer 参数区分不同的触摸点。
  • 示例:
    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        System.out.println("Touch down by pointer " + pointer + " at " + screenX + ", " + screenY);
        return true;
    }
    

5. 处理鼠标滚轮

  • 使用 scrolled() 方法处理鼠标滚轮事件。
  • 示例:
    @Override
    public boolean scrolled(float amountX, float amountY) {
        System.out.println("Scrolled by " + amountX + ", " + amountY);
        return true;
    }
    

7. 总结

  • 轮询输入:适合处理实时输入(如角色移动)。
  • 事件监听:适合处理离散事件(如按键按下、鼠标点击)。
  • InputMultiplexer:用于同时处理多个输入源(如游戏逻辑和 UI 输入)。
  • 多点触控:通过 pointer 参数区分不同的触摸点。
  • 鼠标滚轮:通过 scrolled() 方法处理滚轮事件。

通过结合轮询和事件监听,可以高效地处理键盘、鼠标和触摸输入,满足不同游戏场景的需求。如果你有更多问题,欢迎继续提问!