Unity XR实现交互(抓取,移动旋转,传送,射击)
文章目录
前言
Unity XR提供了XR Interaction Toolkit交互工具包直接在Package Manager中安装/更新即可,对于简单的交互需求可以实现0代码,只需要将相应的脚本挂载到手柄和物体身上即可。本次演示使用当前最新的2.1.0 preview版本,如果版本较低可能会有部分脚本不可用,请尽可能更新到最新的版本。
本次演示使用Pico XR SDK,在导入SDK后其会自行携带一个XR Interaction Toolkit的0.9版本,请一定从Package Manager中进行更新,否则后续的选项会有较大的区别。
PS: 更新到新版后,很多脚本都提供了新版Action-based方式,和老版Device-based,本篇博客会以Device-based进行讲解,关于Unity新版输入系统的使用,笔者会在下一篇文章着重去讲。
一、手柄的创建
- Ray Interactor:会创建一个带有射线的手柄模板对象
- Direct Interactor:会创建一个不具有射线的手柄模板对象
- XR Origin(VR): 建议,会直接创建出VR摄像机+两个射线手柄对象,更为方便后续可直接在此基础上做更改。
二、手柄的抓取
1. XR DirectController 手柄直接抓取
- Interaction Manager: 交互管理类 — 关键,一般会随着XR Origin一起创建出来,一般创建手柄会直接挂载上去,如果没有挂载需要去Hireachy面板手动挂载一下。
- Interaction Layer Mask : 在可抓取物体身上的XR Grab Interactable脚本上也有同名属性,只有物体的Layer Mask和手柄的匹配才可被抓取。
- Attack Transform : 手柄的抓取位置,同时物体也可以设置抓取位置,当抓取时手柄的抓取位置会和物体的抓取位置相同,根据具体需求加以配置合适的位置即可。
- 碰撞体:如果不是使用模板配置,而是自行挂载脚本很容易忘记此组件,直接抓取必须具有碰撞体才可以检测到可抓取物体并进行抓取操作,而射线则无需碰撞体,只需射线检测。
2. XR Ray Interactor 手柄射线抓取
手柄射线抓取一般使用默认设置即可实现将击中的物体吸到手柄上,无需添加碰撞体,诸如Layer Mask等属性与上述一致,不再赘述。
3. XR Grab Interactable 可抓取物体
- Interaction Manager/LayerMask/Attack Transform,几个常用属性在XR DirectController中描述过,不再赘述
- Collider:必须拥有,抓取是通过碰撞器检测所实现的
- Rigibody:建议拥有,VR场景下的可抓取物体的抓取投掷等效果均基于自带的刚体。
- Interactable Events:里面提供了抓取物体一系列事件的回调,如抓取物体的回调,释放物体的回调,抓取物体后按下Trigger键的回调等等,后续的射击功能正是基于此实现的。
三、手柄摇杆控制移动和旋转
以左手摇杆控制持续旋转,右手摇杆控制持续移动为例
根据上图,在XR Origin上添加Locomotion System,Continous Turn Provider等组件,再按照上图箭头进行配置即可。
- 注意这些脚本不是必须放在XR Origin身上,任意地方均可但属性必须进行配置,放在XR Origin上方便管理。
- Continous 是持续进行移动和旋转的脚本,由手柄的摇杆控制,如果想一次旋转或移动一段距离/角度,可以用Snap Turn/Move,在低版本的XR互动包中可能会不支持某些脚本。
四、手柄射线传送
1. 基本功能版
- 基本的传送管理类Teleportion Provider必须要添加,推荐一起添加在XR Origin中
- 负责传送的手柄,首先必须是XR Ray Interactor射线控制,一般来讲会使用抛物线,或者贝塞尔曲线,关于其相关参数可以搜索贝塞尔曲线的知识,Sample Frequency取样点会直接影响曲线的平滑程度。
- Reticle为射线击中目标后的指示器,很适合作为传送目标点的指示器,如果没有合适的指示器可以用球体简单演示。
除了射线手柄的设置,在需要传送的地面上还需要添加Teleportation Area脚本(如果想只能传送到固定的点可以用Anchor,用法一致),然后射线检测到可以传送的地面后射线会变为绿色,默认按下Trigger键即可实现传送。
2. 进阶版
待改进的问题
- 只挂载默认的脚本,有时很大程度上没法满足需求,例如一般手柄的传送功能不会一直存在曲线去选择位置,我们会希望其在按下某个按键或者推动摇杆时出现曲线旋转位置,在松开按键或摇杆时进行传送等。
- 负责传送的手柄无法同时挂载Ray Interactor和Direct Interactor也就是说,我们无法通过仅仅挂载脚本去实现手柄平常负责直接抓取,而想传送时得到射线选取位置传送。
针对问题1,2的场景,笔者以左手柄平常负责直接抓取,按下A键出现射线选择位置传送为例,给出一种解决方案。
基本思路
- 创建两个左手柄对象,一个挂载Direct Interactor负责日常抓取,一个挂载Ray Interactor负责传送。
- 平常Ray Interactor脚本会被禁用掉,只有当按下A键后启用可以选择位置,当松开A键后代码控制发送传送请求,再禁用掉脚本指示器等等。
关于手柄按键的按下和抬起 Down和Up事件,如果使用老的输入系统可以参考这篇文章https://blog.csdn.net/Q540670228/article/details/123139150,关于脚本的启动禁用过程较为简单,下面只给出抬起按键时发起传送请求的代码。
//传送管理器脚本的获取省略publicTeleportationProvider provider;//负责传送的手柄XRRayInteractor脚本,获取过程省略publicXRRayInteractor teleportRayInteractor;privatevoidLeftAXButtonUpHandler(){//射线信息RaycastHit rayInfo;//判断目标点是否有效 1.是否击中目标 2.是否具有Teleportation组件bool isValid = teleportRayInteractor.TryGetCurrent3DRaycastHit(out rayInfo);
isValid = isValid && rayInfo.collider !=null&&(rayInfo.collider.GetComponent<TeleportationArea>()!=null||
rayInfo.collider.GetComponent<TeleportationAnchor>()!=null);if(isValid){//创建传送需求将射线击中的位置作为目的地,提交到provider中的传送队列。TeleportRequest request =newTeleportRequest();
request.destinationPosition = rayInfo.point;
provider.QueueTeleportRequest(request);}//禁用相关脚本和指示器
teleportRayInteractor.enabled =false;
teleportRayInteractor.GetComponent<XRInteractorLineVisual>().reticle?.SetActive(false);}
五、手柄控制射击
在VR游戏中经常会有捡起枪进行射击的功能,其一般设计难点在
- 判断物体是否被抓取,被哪个手柄抓取
- 抓取了此物体的手柄是否按下了Trigger键
在XR Grab Interactable脚本中已经很贴心的提供了一个事件,触发条件正是上述这两个。使用方式如下
private XRGrabInteractable grab;
private void Awake()
{
grab = GetComponent<XRGrabInteractable>();
//为activated事件添加监听函数即可
grab.activated.AddListener(GrabHandler);
}
private void GrabHandler(ActivateEventArgs a)
{
//当枪械被抓取和按下Trigger后回调此方法,触发射击方法。
Shoot();
}
版权归原作者 窗外听轩雨 所有, 如有侵权,请联系我们删除。