8、使用InputProcessor和GestureDetector处理复杂输入

155 阅读10分钟

在 LibGDX 中,InputProcessorGestureDetector 是处理复杂输入的两个强大工具。InputProcessor 用于处理基本的输入事件(如按键、触摸、鼠标),而 GestureDetector 则用于处理更复杂的手势操作(如滑动、缩放、长按)。以下是它们的详细使用方法:


1. InputProcessor 的使用

InputProcessor 是一个接口,定义了处理输入事件的方法。通过实现这个接口,可以处理键盘、鼠标和触摸输入。

实现 InputProcessor

以下是一个简单的 InputProcessor 实现示例:

import com.badlogic.gdx.InputProcessor;

public class MyInputProcessor implements InputProcessor {
    @Override
    public boolean keyDown(int keycode) {
        System.out.println("Key down: " + keycode);
        return true;
    }

    @Override
    public boolean keyUp(int keycode) {
        System.out.println("Key up: " + keycode);
        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;
    }
}

注册 InputProcessor

在游戏初始化时注册 InputProcessor

@Override
public void create() {
    Gdx.input.setInputProcessor(new MyInputProcessor());
}

2. GestureDetector 的使用

GestureDetector 是一个工具类,用于检测复杂的手势操作(如滑动、缩放、长按)。它基于 InputProcessor,但提供了更高层次的抽象。

实现 GestureListener

GestureDetector 需要一个 GestureListener 实现类来处理手势事件。以下是一个简单的 GestureListener 实现示例:

import com.badlogic.gdx.input.GestureDetector;
import com.badlogic.gdx.math.Vector2;

public class MyGestureListener implements GestureDetector.GestureListener {
    @Override
    public boolean touchDown(float x, float y, int pointer, int button) {
        System.out.println("Touch down at: " + x + ", " + y);
        return true;
    }

    @Override
    public boolean tap(float x, float y, int count, int button) {
        System.out.println("Tap at: " + x + ", " + y + ", count: " + count);
        return true;
    }

    @Override
    public boolean longPress(float x, float y) {
        System.out.println("Long press at: " + x + ", " + y);
        return true;
    }

    @Override
    public boolean fling(float velocityX, float velocityY, int button) {
        System.out.println("Fling with velocity: " + velocityX + ", " + velocityY);
        return true;
    }

    @Override
    public boolean pan(float x, float y, float deltaX, float deltaY) {
        System.out.println("Pan at: " + x + ", " + y + ", delta: " + deltaX + ", " + deltaY);
        return true;
    }

    @Override
    public boolean panStop(float x, float y, int pointer, int button) {
        System.out.println("Pan stop at: " + x + ", " + y);
        return true;
    }

    @Override
    public boolean zoom(float initialDistance, float distance) {
        System.out.println("Zoom: initial distance = " + initialDistance + ", current distance = " + distance);
        return true
    }
	@Override
	public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
	    System.out.println("Pinch: initial pointers = " + initialPointer1 + ", " + initialPointer2 +
	                       ", current pointers = " + pointer1 + ", " + pointer2);
	    return true;
	}
	
	@Override
	public void pinchStop() {
	    System.out.println("Pinch stopped");
	}

3. 注册 GestureDetector

在游戏初始化时,创建 GestureDetector 并注册为输入处理器:

@Override
public void create() {
    // 创建 GestureDetector
    GestureDetector gestureDetector = new GestureDetector(new MyGestureListener());

    // 注册 GestureDetector
    Gdx.input.setInputProcessor(gestureDetector);
}

4. 结合 InputMultiplexer 同时处理 InputProcessorGestureDetector

如果需要同时处理基本输入事件和手势操作,可以使用 InputMultiplexerInputProcessorGestureDetector 组合在一起。

示例代码

以下是一个完整的示例,展示如何结合 InputProcessorGestureDetector

import com.badlogic.gdx.ApplicationListener;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.InputMultiplexer;
import com.badlogic.gdx.input.GestureDetector;
import com.badlogic.gdx.math.Vector2;

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

        // 添加 InputProcessor
        multiplexer.addProcessor(new MyInputProcessor());

        // 添加 GestureDetector
        multiplexer.addProcessor(new GestureDetector(new MyGestureListener()));

        // 注册 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() {
        // 释放资源
    }
}

// InputProcessor 实现
class MyInputProcessor implements InputProcessor {
    @Override
    public boolean keyDown(int keycode) {
        System.out.println("Key down: " + keycode);
        return true;
    }

    @Override
    public boolean keyUp(int keycode) {
        System.out.println("Key up: " + keycode);
        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;
    }
}


以下是 GestureListener 的完整实现:

import com.badlogic.gdx.input.GestureDetector;
import com.badlogic.gdx.math.Vector2;

public class MyGestureListener implements GestureDetector.GestureListener {
    @Override
    public boolean touchDown(float x, float y, int pointer, int button) {
        System.out.println("Touch down at: " + x + ", " + y);
        return true;
    }

    @Override
    public boolean tap(float x, float y, int count, int button) {
        System.out.println("Tap at: " + x + ", " + y + ", count: " + count);
        return true;
    }

    @Override
    public boolean longPress(float x, float y) {
        System.out.println("Long press at: " + x + ", " + y);
        return true;
    }

    @Override
    public boolean fling(float velocityX, float velocityY, int button) {
        System.out.println("Fling with velocity: " + velocityX + ", " + velocityY);
        return true;
    }

    @Override
    public boolean pan(float x, float y, float deltaX, float deltaY) {
        System.out.println("Pan at: " + x + ", " + y + ", delta: " + deltaX + ", " + deltaY);
        return true;
    }

    @Override
    public boolean panStop(float x, float y, int pointer, int button) {
        System.out.println("Pan stop at: " + x + ", " + y);
        return true;
    }

    @Override
    public boolean zoom(float initialDistance, float distance) {
        System.out.println("Zoom: initial distance = " + initialDistance + ", current distance = " + distance);
        return true;
    }

    @Override
    public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
        System.out.println("Pinch: initial pointers = " + initialPointer1 + ", " + initialPointer2 +
                          ", current pointers = " + pointer1 + ", " + pointer2);
        return true;
    }

    @Override
    public void pinchStop() {
        System.out.println("Pinch stopped");
    }
}

5. 结合 InputProcessorGestureDetector 的完整流程

1. 初始化输入处理器

  • create() 方法中创建 InputMultiplexer,并添加 InputProcessorGestureDetector
  • 示例:
    @Override
    public void create() {
        InputMultiplexer multiplexer = new InputMultiplexer();
        multiplexer.addProcessor(new MyInputProcessor()); // 添加 InputProcessor
        multiplexer.addProcessor(new GestureDetector(new MyGestureListener())); // 添加 GestureDetector
        Gdx.input.setInputProcessor(multiplexer); // 注册 InputMultiplexer
    }
    

2. 处理基本输入事件

  • 使用 InputProcessor 处理键盘、鼠标和触摸输入。
  • 示例:
    @Override
    public boolean keyDown(int keycode) {
        if (keycode == Input.Keys.SPACE) {
            System.out.println("Space key pressed");
        }
        return true;
    }
    

3. 处理手势操作

  • 使用 GestureDetector 处理复杂手势(如滑动、缩放、长按)。
  • 示例:
    @Override
    public boolean fling(float velocityX, float velocityY, int button) {
        System.out.println("Fling with velocity: " + velocityX + ", " + velocityY);
        return true;
    }
    

4. 处理多点触控

  • 使用 GestureDetectorpinch() 方法处理多点触控缩放。
  • 示例:
    @Override
    public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
        System.out.println("Pinch: initial pointers = " + initialPointer1 + ", " + initialPointer2 +
                          ", current pointers = " + pointer1 + ", " + pointer2);
        return true;
    }
    

好的,继续总结并结合实际应用场景,展示如何高效使用 InputProcessorGestureDetector 处理复杂输入。


6. 总结

  • InputProcessor:用于处理基本的输入事件(如按键、鼠标点击、触摸)。
  • GestureDetector:用于处理复杂的手势操作(如滑动、缩放、长按)。
  • InputMultiplexer:用于同时处理多个输入源(如 InputProcessorGestureDetector)。

通过结合 InputProcessorGestureDetector,可以高效地处理各种输入事件,满足复杂游戏或应用的需求。


7. 实际应用场景

以下是一些实际应用场景,展示如何结合 InputProcessorGestureDetector 处理复杂输入:

场景 1:角色移动和手势缩放

  • 角色移动:使用 InputProcessor 处理键盘或触摸输入,控制角色移动。
  • 手势缩放:使用 GestureDetector 处理双指缩放,调整游戏视角。
@Override
public boolean keyDown(int keycode) {
    if (keycode == Input.Keys.LEFT) {
        player.moveLeft(); // 角色向左移动
    }
    if (keycode == Input.Keys.RIGHT) {
        player.moveRight(); // 角色向右移动
    }
    return true;
}

@Override
public boolean zoom(float initialDistance, float distance) {
    float zoomFactor = distance / initialDistance;
    camera.zoom = zoomFactor; // 调整相机缩放
    return true;
}

场景 2:UI 按钮点击和手势滑动

  • UI 按钮点击:使用 InputProcessor 处理触摸事件,检测按钮点击。
  • 手势滑动:使用 GestureDetector 处理滑动事件,实现页面切换。
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
    if (playButton.contains(screenX, screenY)) {
        startGame(); // 点击播放按钮
    }
    return true;
}

@Override
public boolean fling(float velocityX, float velocityY, int button) {
    if (Math.abs(velocityX) > Math.abs(velocityY)) {
        if (velocityX > 0) {
            switchToNextPage(); // 向右滑动切换下一页
        } else {
            switchToPreviousPage(); // 向左滑动切换上一页
        }
    }
    return true;
}

场景 3:多点触控缩放和旋转

  • 多点触控缩放:使用 GestureDetectorpinch() 方法处理缩放。
  • 多点触控旋转:使用 GestureDetectorpinch() 方法计算旋转角度。
@Override
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
    // 计算缩放比例
    float initialDistance = initialPointer1.dst(initialPointer2);
    float currentDistance = pointer1.dst(pointer2);
    float zoomFactor = currentDistance / initialDistance;
    camera.zoom = zoomFactor; // 调整相机缩放

    // 计算旋转角度
    float initialAngle = initialPointer1.sub(initialPointer2).angle();
    float currentAngle = pointer1.sub(pointer2).angle();
    float rotationDelta = currentAngle - initialAngle;
    camera.rotate(rotationDelta); // 调整相机旋转
    return true;
}

8. 最佳实践

  1. 分离输入逻辑
    • 将游戏逻辑输入和 UI 输入分开处理,使用 InputMultiplexer 组合多个输入处理器。
  2. 优先使用 GestureDetector
    • 对于复杂手势操作(如滑动、缩放、长按),优先使用 GestureDetector,而不是手动实现。
  3. 优化性能
    • render() 方法中尽量减少输入处理的复杂度,避免影响游戏性能。
  4. 处理多点触控
    • 使用 pointer 参数区分不同的触摸点,支持多点触控操作。
  5. 释放资源
    • 在游戏结束时,释放输入处理器和手势检测器的资源。

好的,继续完成完整示例代码,并总结如何在实际项目中应用这些技术。


9. 完整示例代码(续)

以下是一个完整的示例,展示如何结合 InputProcessorGestureDetector 处理复杂输入:

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.GestureDetector;
import com.badlogic.gdx.math.Vector2;

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

        // 添加 InputProcessor
        multiplexer.addProcessor(new MyInputProcessor());

        // 添加 GestureDetector
        multiplexer.addProcessor(new GestureDetector(new MyGestureListener()));

        // 注册 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() {
        // 释放资源
    }
}

// InputProcessor 实现
class MyInputProcessor implements InputProcessor {
    @Override
    public boolean keyDown(int keycode) {
        System.out.println("Key down: " + keycode);
        return true;
    }

    @Override
    public boolean keyUp(int keycode) {
        System.out.println("Key up: " + keycode);
        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;
    }
}

// GestureListener 实现
class MyGestureListener implements GestureDetector.GestureListener {
    @Override
    public boolean touchDown(float x, float y, int pointer, int button) {
        System.out.println("Touch down at: " + x + ", " + y);
        return true;
    }

    @Override
    public boolean tap(float x, float y, int count, int button) {
        System.out.println("Tap at: " + x + ", " + y + ", count: " + count);
        return true;
    }

    @Override
    public boolean longPress(float x, float y) {
        System.out.println("Long press at: " + x + ", " + y);
        return true;
    }

    @Override
    public boolean fling(float velocityX, float velocityY, int button) {
        System.out.println("Fling with velocity: " + velocityX + ", " + velocityY);
        return true;
    }

    @Override
    public boolean pan(float x, float y, float deltaX, float deltaY) {
        System.out.println("Pan at: " + x + ", " + y + ", delta: " + deltaX + ", " + deltaY);
        return true;
    }

	@Override
	public boolean panStop(float x, float y, int pointer, int button) {
	    System.out.println("Pan stop at: " + x + ", " + y);
	    return true;
	}
	
	@Override
	public boolean zoom(float initialDistance, float distance) {
	    System.out.println("Zoom: initial distance = " + initialDistance + ", current distance = " + distance);
	    return true;
	}
	
	@Override
	public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
	    System.out.println("Pinch: initial pointers = " + initialPointer1 + ", " + initialPointer2 +
	                      ", current pointers = " + pointer1 + ", " + pointer2);
	    return true;
	}
	
	@Override
	public void pinchStop() {
	    System.out.println("Pinch stopped");
	}

10. 实际项目中的应用

在实际项目中,InputProcessorGestureDetector 可以结合使用,处理复杂的输入需求。以下是一些常见的应用场景:

场景 1:角色移动和手势缩放

  • 角色移动:使用 InputProcessor 处理键盘或触摸输入,控制角色移动。
  • 手势缩放:使用 GestureDetector 处理双指缩放,调整游戏视角。
@Override
public boolean keyDown(int keycode) {
    if (keycode == Input.Keys.LEFT) {
        player.moveLeft(); // 角色向左移动
    }
    if (keycode == Input.Keys.RIGHT) {
        player.moveRight(); // 角色向右移动
    }
    return true;
}

@Override
public boolean zoom(float initialDistance, float distance) {
    float zoomFactor = distance / initialDistance;
    camera.zoom = zoomFactor; // 调整相机缩放
    return true;
}

场景 2:UI 按钮点击和手势滑动

  • UI 按钮点击:使用 InputProcessor 处理触摸事件,检测按钮点击。
  • 手势滑动:使用 GestureDetector 处理滑动事件,实现页面切换。
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
    if (playButton.contains(screenX, screenY)) {
        startGame(); // 点击播放按钮
    }
    return true;
}

@Override
public boolean fling(float velocityX, float velocityY, int button) {
    if (Math.abs(velocityX) > Math.abs(velocityY)) {
        if (velocityX > 0) {
            switchToNextPage(); // 向右滑动切换下一页
        } else {
            switchToPreviousPage(); // 向左滑动切换上一页
        }
    }
    return true;
}

场景 3:多点触控缩放和旋转

  • 多点触控缩放:使用 GestureDetectorpinch() 方法处理缩放。
  • 多点触控旋转:使用 GestureDetectorpinch() 方法计算旋转角度。
@Override
public boolean pinch(Vector2 initialPointer1, Vector2 initialPointer2, Vector2 pointer1, Vector2 pointer2) {
    // 计算缩放比例
    float initialDistance = initialPointer1.dst(initialPointer2);
    float currentDistance = pointer1.dst(pointer2);
    float zoomFactor = currentDistance / initialDistance;
    camera.zoom = zoomFactor; // 调整相机缩放

    // 计算旋转角度
    float initialAngle = initialPointer1.sub(initialPointer2).angle();
    float currentAngle = pointer1.sub(pointer2).angle();
    float rotationDelta = currentAngle - initialAngle;
    camera.rotate(rotationDelta); // 调整相机旋转
    return true;
}

11. 总结

  • InputProcessor:用于处理基本的输入事件(如按键、鼠标点击、触摸)。
  • GestureDetector:用于处理复杂的手势操作(如滑动、缩放、长按)。
  • InputMultiplexer:用于同时处理多个输入源(如 InputProcessorGestureDetector)。

通过结合 InputProcessorGestureDetector,可以高效地处理各种输入事件,满足复杂游戏或应用的需求。如果你有更多问题,欢迎继续提问!