在Unity中获取DualShock4的动作数据(陀螺仪与加速计)

本文介绍如何在Unity中通过自定义InputSystem布局,获取并应用DualShock4手柄的陀螺仪和加速计数据。通过修改布局文件并编写C#脚本,实现手柄旋转数据的读取,用于控制游戏对象的旋转。
先上效果
一直以来,Unity官方并没有提供开箱即用的工具来方便地获取DualShock4中陀螺仪和加速计的数据(听说只有PS4的SDK有提供),要手动获取可能也避免不了和偏底层的代码打交道。直到Unity发布了新的输入工具, the new Input System(以下简称Input System, 没有了解过的朋友可以看 这里 )。 Input System中一个非常强大的功能就是支持自定义布局,这使得我们可以通过修改DualShock4的默认布局,使得原本不能直接访问的陀螺仪和加速计数据暴露出来。
首先新建一个项目,并且通过package manager安装input system。
通过Window -> Analysis -> Input Debugger 打开调试窗口,连上DualShock4,就可以看到当前识别到的输入设备了。(如果没有,重启Unity即可)
点开Input Debug -> Layouts -> Specific Devices -> Gamepads -> PS4 Controller -> Controls,可以看到默认的布局已经映射了所有所有的按钮和摇杆。我们只需要以这一份布局为基础,增加新的映射。映射可以通过结构体或者JSON开创建,为了方便起见这里选用JSON。
在Input Debug -> Layouts -> Specific Devices -> Gamepads -> PS4 Controller 上点击右键,选择Copy Layout as JSON, 在工程目录下新建一个JSON文件并粘贴。修改JSON的name和display name以便和默认的layout区分。
观察Controls下的每一项,对照 http://eleccelerator.com/wiki/index.php?title=DualShock_4#Report_Structure 提供的report structure,我们要映射的布局应该有如下结构。 两个传感器共计六个轴,参考上方提到的report structure,每一个轴都可能有两个byte来存放数据,为了方便debug,一次性将12项添加进JSON,offset从13到24,按照“传感器+轴+offset”的方式命名。
接下来编写一个C#脚本来在启动时覆盖默认的DualShock4布局。
    
//DS4.cs using System . IO ; using UnityEngine ; using UnityEngine . InputSystem ; using UnityEngine . InputSystem . Controls ; public class DS4 { public static Gamepad controller = null ; public static Gamepad getConroller ( string layoutFile = null ) { // Read layout from JSON file string layout = File . ReadAllText ( layoutFile == null ? "Assets/Script/customLayout.json" : layoutFile ) ; // Overwrite the default layout InputSystem . RegisterLayoutOverride ( layout , "DualShock4GamepadHID" ) ; var ds4 = Gamepad . current ; DS4 . controller = ds4 ; return ds4 ; } }
手动调用DS4.getController()会从customLayout.json读取布局并且配置到当前的手柄上。建立一个Cube并写一个monobehavior来测试一下。
    
//InputTest.cs using System . Collections ; using System . Collections . Generic ; using UnityEngine ; using UnityEngine . InputSystem ; public class InputTest : MonoBehaviour { Gamepad controller ; void Start ( ) { this . controller = DS4 . getConroller ( ) ; } }
运行程序,在Input Debug中双击DualShock4GamepadHID,在新的窗口中可以看到新的布局已成功映射并且正在接受数据输入。
到这一步为止,已经可以成功获取两个传感器的raw data了,接下来将展示一个简单的DEMO,以演示如何将数据应用在程序中,以陀螺仪数据(offset13至offset18)为例。
由于陀螺仪各个轴的数据都对应了两个offset,在DualShock4静止不动时,offset 14、16、18可以获得较为稳定的数据,其他三个offset则就有(原因不明?)的持续抖动,因此选择14、16、18作为最终的输入。通过对数据观察,总结出每个轴的数据具有以下特征:
  • 数值在0到1之间
  • 0或1表示静止,0~0.5是负方向,0.5~1是正方向
  • 0~0.5内,数值越大旋转速度越快。0.5~1内,数值越大旋转速度越慢。也就是越靠近0.5旋转速度越快
修改DS4.cs为以下代码。需要注意DS4的数据使用的是和Unity相反的坐标系,所以Z轴的数据需要乘-1。 调用getRotation(),即可获得当前DualShock4的旋转速度,以四元数的形式返回。
    
using System . IO ; using UnityEngine ; using UnityEngine . InputSystem ; using UnityEngine . InputSystem . Controls ; public class DS4 { // Gyroscope public static ButtonControl gyroX = null ; public static ButtonControl gyroY = null ; public static ButtonControl gyroZ = null ; public static Gamepad controller = null ; public static Gamepad getConroller ( string layoutFile = null ) { // Read layout from JSON file string layout = File . ReadAllText ( layoutFile == null ? "Assets/Script/customLayout.json" : layoutFile ) ; // Overwrite the default layout InputSystem . RegisterLayoutOverride ( layout , "DualShock4GamepadHID" ) ; var ds4 = Gamepad . current ; DS4 . controller = ds4 ; bindControls ( DS4 . controller ) ; return DS4 . controller ; } private static void bindControls ( Gamepad ds4 ) { gyroX = ds4 . GetChildControl < ButtonControl > ( "gyro X 14" ) ; gyroY = ds4 . GetChildControl < ButtonControl > ( "gyro Y 16" ) ; gyroZ = ds4 . GetChildControl < ButtonControl > ( "gyro Z 18" ) ; } public static Quaternion getRotation ( float scale = 1 ) { float x = processRawData ( gyroX . ReadValue ( ) ) * scale ; float y = processRawData ( gyroY . ReadValue ( ) ) * scale ; float z = - processRawData ( gyroZ . ReadValue ( ) ) * scale ; return Quaternion . Euler ( x , y , z ) ; } private static float processRawData ( float data ) { return data > 0.5 ? 1 - data : - data ; } }
改写InputTest.cs,以控制Cube跟随手柄转动。
    
using System ; using UnityEngine ; using UnityEngine . InputSystem ; public class InputTest : MonoBehaviour { private Gamepad controller = null ; private Transform m_transform ; void Start ( ) { this . controller = DS4 . getConroller ( ) ; m_transform = this . transform ; } void Update ( ) { if ( controller == null ) { try { controller = DS4 . getConroller ( ) ; } catch ( Exception e ) { Console . WriteLine ( e ) ; } } else { // Press circle button to reset rotation if ( controller . buttonEast . isPressed ) { m_transform . rotation = Quaternion . identity ; } m_transform . rotation *= DS4 . getRotation ( 4000 * Time . deltaTime ) ; } } }
运行程序,即可获得类似文章开头展示的效果。 工程文件的源代码已上传至GitHub,地址 https://github.com/SG4YK/DS4Motion_Unity
(第一次写Unity的文章,如有错漏,欢迎指正!) 封面图来自 Unsplash
参考链接
  • http://eleccelerator.com/wiki/index.php?title=DualShock_4#Report_Structure
  • https://docs.unity3d.com/Packages/com.unity.inputsystem@1.0/manual/
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值