如何区分方向键运动和操纵杆运动?

Posted

技术标签:

【中文标题】如何区分方向键运动和操纵杆运动?【英文标题】:How to differentiate a D-pad movement from a Joystick movement? 【发布时间】:2016-04-04 19:43:22 【问题描述】:

我需要有两种不同的行为,一种用于方向键,另一种用于模拟操纵杆(在同一个游戏手柄上)。

问题是在onGenericMotionEvent 回调中,两者在MotionEvent 上的信息相同,我无法区分它们。

// d-pad
MotionEvent  action=ACTION_MOVE, id[0]=0, x[0]=-1.5259255E-5, y[0]=-1.5259255E-5, toolType[0]=TOOL_TYPE_UNKNOWN, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=151637936, downTime=0, deviceId=5, source=0x1000010 

// analog joystick
MotionEvent  action=ACTION_MOVE, id[0]=0, x[0]=0.64507514, y[0]=0.710811, toolType[0]=TOOL_TYPE_UNKNOWN, buttonState=0, metaState=0, flags=0x0, edgeFlags=0x0, pointerCount=1, historySize=0, eventTime=151650802, downTime=0, deviceId=5, source=0x1000010 

是否可以识别正在使用的输入类型?怎么样?

【问题讨论】:

您找到解决方案了吗?我有同样的问题,但似乎没有办法区分这两种输入法。会很烦人... 似乎 DS4 控制器在您使用 DPAD 时不会声明 DPAD 源。您会得到一个操纵杆源事件,其帽子值设置为最小/最大值,具体取决于您按下的内容。无论如何,要支持 DS4,您似乎需要查询 X 和 XHat,看看哪个更大(abs)并使用它。 【参考方案1】:

我遇到了同样的问题,我不得不深入研究this helpful Git user's project 以弄清楚他是如何做到的。区分不同操纵杆(和方向键)的方法是使用每个方向的特定

如果您非常仔细地阅读android documentation's page(我没有注意到它),它确实显示了您如何区分各种操纵杆及其方向:

此图像显示左侧操纵杆使用轴 AXIS_XAXIS_Y,而右侧操纵杆使用 AXIS_ZAXIS_RZ。对于方向键,我使用了 AXIS_HAT_XAXIS_HAT_Y。以下来自我的代码(在 Kotlin 中)的 sn-p 显示了如何单独访问其中的每一个:

注意:我还将搜索栏设置为 0-100 的范围,这就是为什么我在 processJoystickInput() 的底部有转换数学。

private fun processJoystickInput(event: MotionEvent, historyPos: Int) 

    val inputDevice = event.device

    val newJoystickValues = floatArrayOf(
            getCenteredAxis(event, inputDevice, MotionEvent.AXIS_X, historyPos),
            getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Y, historyPos),
            getCenteredAxis(event, inputDevice, MotionEvent.AXIS_Z, historyPos),
            getCenteredAxis(event, inputDevice, MotionEvent.AXIS_RZ, historyPos),
            getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_X, historyPos),
            getCenteredAxis(event, inputDevice, MotionEvent.AXIS_HAT_Y, historyPos))

    // Update based on the new x and y values
    val throttleSeekBar = findViewById<SeekBar>(R.id.throttle_seekBar)
    val yawSeekBar = findViewById<SeekBar>(R.id.yaw_seekBar)
    val pitchSeekBar = findViewById<SeekBar>(R.id.pitch_seekBar)
    val rollSeekBar = findViewById<SeekBar>(R.id.roll_seekBar)
    val dpadXSeekBar = findViewById<SeekBar>(R.id.dpadX_seekBar)
    val dpadYSeekBar = findViewById<SeekBar>(R.id.dpadY_seekBar)

    // Convert the float range (-1.00 to 1.00) to Int (0 to 100)
    yawSeekBar.progress = ((newJoystickValues[0] + 1) * 50).toInt()
    throttleSeekBar.progress = ((newJoystickValues[1] + 1) * 50).toInt()
    rollSeekBar.progress = ((newJoystickValues[2] + 1) * 50).toInt()
    pitchSeekBar.progress = ((newJoystickValues[3] + 1) * 50).toInt()
    dpadXSeekBar.progress = ((newJoystickValues[4] + 1) * 50).toInt()
    dpadYSeekBar.progress = ((newJoystickValues[5] + 1) * 50).toInt()


override fun onGenericMotionEvent(event: MotionEvent): Boolean 
    // Check that the event came from a game controller

    return if (event.source and(InputDevice.SOURCE_JOYSTICK) == InputDevice.SOURCE_JOYSTICK
            && event.action == MotionEvent.ACTION_MOVE) 

        // Process the movements starting from the
        // earliest historical position in the batch
        (0 until event.historySize).forEach  i ->
            // Process the event at historical position i
            processJoystickInput(event, i)
        

        // Process the current movement sample in the batch (position -1)
        processJoystickInput(event, -1)
        true
     else 
        super.onGenericMotionEvent(event)
    

【讨论】:

【参考方案2】:

查看您提供的信息,它们看起来来自同一来源,即操纵杆 (0x1000010)。您可以在Input Device 对象上查看这些信息。

以下信息来自Handling Controller Actions:

要验证连接的输入设备是游戏控制器,请调用getSources() 以获取该设备支持的输入源类型的组合位字段。

SOURCE_GAMEPAD 的源类型表示输入设备具有游戏手柄按钮(例如,BUTTON_A)。请注意,尽管大多数游戏手柄通常具有方向控制,但此源类型并未严格指示游戏控制器是否具有方向键按钮。

SOURCE_DPAD 的源类型表示输入设备具有方向键按钮(例如,DPAD_UP)。

SOURCE_JOYSTICK 的源类型表示输入设备具有模拟控制杆(例如,记录沿 AXIS_XAXIS_Y 移动的操纵杆)。

您可能还想查看Supporting Multiple Controller Input。

【讨论】:

我需要区分两个不同的输入(dpad 和模拟)来自同一个操纵杆源,而不是两个不同的源【参考方案3】:

来自 Android 文档 (https://developer.android.com/training/game-controllers/controller-input):

Android 将 D-pad UP 和 DOWN 按下报告为 AXIS_HAT_Y 事件,并带有 范围从 -1.0(向上)到 1.0(向下),方向键向左或向右按​​下 AXIS_HAT_X 事件,范围从 -1.0(左)到 1.0(右)。

一些控制器会使用键代码报告方向键按下。如果你的游戏关心方向键,你应该处理帽子轴 事件和方向键键代码作为相同的输入事件,如 推荐在表 2 中。

我使用过的两个控制器(NVIDIA SHIELD 蓝牙和 Microsoft XBOX360 有线)都生成 AXIS_HAT_* 运动事件。

【讨论】:

DS4 也是如此。 DPad 始终是 MotionEvent,source=Joystick,必须从 XHat/YHat 值中读取 DPad。

以上是关于如何区分方向键运动和操纵杆运动?的主要内容,如果未能解决你的问题,请参考以下文章

方向键控制圆球运动(简易)(js)

处理中的平滑运动?

使用基于相机朝向的操纵杆的玩家运动

编写 OpenGL 基本摄像机运动

笔记-3.路径动画+小球闯关练习

DOM操作——操纵方向键