rabidus-test/Assets/BNG Framework/Scripts/Extras/VREmulator.cs

460 lines
18 KiB
C#

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
namespace BNG {
public class VREmulator : MonoBehaviour {
[Header("Enable / Disable : ")]
[Tooltip("Use Emulator if true and HMDIsActive is false")]
public bool EmulatorEnabled = true;
[Tooltip("Set to false if you want to use in standalone builds as well as the editor")]
public bool EditorOnly = true;
[Tooltip("If true the game window must have focus for the emulator to be active")]
public bool RequireGameFocus = true;
[Header("Input : ")]
[SerializeField]
[Tooltip("Action set used specifically to mimic or supplement a vr setup")]
public InputActionAsset EmulatorActionSet;
[Header("Player Teleportation")]
[Tooltip("Will set the PlayerTeleport component's ForceStraightArrow = true while the emulator is active.")]
public bool ForceStraightTeleportRotation = true;
[Header("Move Player Up / Down")]
[Tooltip("If true, move the player eye offset up / down whenever PlayerUpAction / PlayerDownAction is called.")]
public bool AllowUpDownControls = true;
[Tooltip("Unity Input Action used to move the player up")]
public InputActionReference PlayerUpAction;
[Tooltip("Unity Input Action used to move the player down")]
public InputActionReference PlayerDownAction;
[Tooltip("Minimum height in meters the player can shrink to when using the PlayerDownAction")]
public float MinPlayerHeight = 0.2f;
[Tooltip("Maximum height in meters the player can grow to when using the PlayerUpAction")]
public float MaxPlayerHeight = 5f;
[Header("Head Look")]
[Tooltip("Unity Input Action used to lock the camera in game mode to look around")]
public InputActionReference LockCameraAction;
[Tooltip("Unity Input Action used to lock the camera in game mode to look around")]
public InputActionReference CameraLookAction;
[Tooltip("Multiply the CameraLookAction by this amount")]
public float CameraLookSensitivityX = 0.1f;
[Tooltip("Multiply the CameraLookAction by this amount")]
public float CameraLookSensitivityY = 0.1f;
[Tooltip("Minimum local Eulers degrees the camera can rotate")]
public float MinimumCameraY = -90f;
[Tooltip("Minimum local Eulers degrees the camera can rotate")]
public float MaximumCameraY = 90f;
[Header("Controller Emulation")]
[Tooltip("Unity Input Action used to mimic holding the Left Grip")]
public InputActionReference LeftGripAction;
[Tooltip("Unity Input Action used to mimic holding the Left Trigger")]
public InputActionReference LeftTriggerAction;
[Tooltip("Unity Input Action used to mimic having your thumb near a button")]
public InputActionReference LeftThumbNearAction;
[Tooltip("Unity Input Action used to move mimic holding the Right Grip")]
public InputActionReference RightGripAction;
[Tooltip("Unity Input Action used to move mimic holding the Right Grip")]
public InputActionReference RightTriggerAction;
[Tooltip("Unity Input Action used to mimic having your thumb near a button")]
public InputActionReference RightThumbNearAction;
float mouseRotationX;
float mouseRotationY;
Transform mainCameraTransform;
Transform leftControllerTranform;
Transform rightControllerTranform;
Transform leftHandAnchor;
Transform rightHandAnchor;
BNGPlayerController player;
SmoothLocomotion smoothLocomotion;
PlayerTeleport playerTeleport;
bool didFirstActivate = false;
Grabber grabberLeft;
Grabber grabberRight;
private float _originalPlayerYOffset = 1.65f;
[Header("Shown for Debug : ")]
public bool HMDIsActive;
public Vector3 LeftControllerPosition = new Vector3(-0.2f, -0.2f, 0.5f);
public Vector3 RightControllerPosition = new Vector3(0.2f, -0.2f, 0.5f);
bool priorStraightSetting;
void Start() {
if(GameObject.Find("CameraRig")) {
mainCameraTransform = GameObject.Find("CameraRig").transform;
}
// Oculus Rig Setup
else if(GameObject.Find("OVRCameraRig")) {
mainCameraTransform = GameObject.Find("OVRCameraRig").transform;
}
leftHandAnchor = GameObject.Find("LeftHandAnchor").transform;
rightHandAnchor = GameObject.Find("RightHandAnchor").transform;
leftControllerTranform = GameObject.Find("LeftControllerAnchor").transform;
rightControllerTranform = GameObject.Find("RightControllerAnchor").transform;
player = FindObjectOfType<BNGPlayerController>();
if(player) {
// Use this to keep our head up high
player.ElevateCameraIfNoHMDPresent = true;
_originalPlayerYOffset = player.ElevateCameraHeight;
smoothLocomotion = player.GetComponentInChildren<SmoothLocomotion>(true);
// initialize component if it's currently disabled
if(smoothLocomotion != null && !smoothLocomotion.isActiveAndEnabled) {
smoothLocomotion.CheckControllerReferences();
}
playerTeleport = player.GetComponentInChildren<PlayerTeleport>(true);
if(playerTeleport) {
priorStraightSetting = playerTeleport.ForceStraightArrow;
}
if (smoothLocomotion == null) {
Debug.Log("No Smooth Locomotion component found. Will not be able to use SmoothLocomotion without calling it manually.");
}
else if (smoothLocomotion.MoveAction == null) {
Debug.Log("Smooth Locomotion Move Action has not been assigned. Make sure to assign this in the inspector if you want to be able to move around using the VR Emulator.");
}
}
}
public void OnBeforeRender() {
HMDIsActive = InputBridge.Instance.HMDActive;
// Ready to go
if (EmulatorEnabled && !HMDIsActive) {
UpdateControllerPositions();
}
}
void onFirstActivate() {
UpdateControllerPositions();
didFirstActivate = true;
}
void Update() {
//// Considerd absent if specified or unknown status
// bool userAbsent = XRDevice.userPresence == UserPresenceState.NotPresent || XRDevice.userPresence == UserPresenceState.Unknown;
// Updated to show in Debug Settings
HMDIsActive = InputBridge.Instance.HMDActive;
// Ready to go
if (EmulatorEnabled && !HMDIsActive) {
if(!didFirstActivate) {
onFirstActivate();
}
// Require focus
if (HasRequiredFocus()) {
CheckHeadControls();
UpdateControllerPositions();
CheckPlayerControls();
}
}
// Device came online after emulator had started
if(EmulatorEnabled && didFirstActivate && HMDIsActive) {
ResetAll();
}
}
public virtual bool HasRequiredFocus() {
// No Focus Required
if(EditorOnly == false || RequireGameFocus == false) {
return true;
}
return Application.isFocused;
}
public void CheckHeadControls() {
// Hold LockCameraAction (example : right mouse button down ) to move camera around
if (LockCameraAction != null) {
// Lock
if (LockCameraAction.action.ReadValue<float>() == 1) {
// Lock Camera and cursor
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
Vector3 mouseLook = Vector2.zero;
if(CameraLookAction != null) {
mouseLook = CameraLookAction.action.ReadValue<Vector2>();
}
// Fall back to mouse
else {
mouseLook = Mouse.current.delta.ReadValue();
}
// Rotation Y
mouseRotationY += mouseLook.y * CameraLookSensitivityY;
mouseRotationY = Mathf.Clamp(mouseRotationY, MinimumCameraY, MaximumCameraY);
mainCameraTransform.localEulerAngles = new Vector3(-mouseRotationY, mainCameraTransform.localEulerAngles.y, 0);
// Move PLayer on X Axis
player.transform.Rotate(0, mouseLook.x * CameraLookSensitivityX, 0);
}
// Unlock Camera
else {
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
}
}
float prevVal;
/// <summary>
/// Overwrite InputBridge inputs with our own bindings
/// </summary>
public void UpdateInputs() {
// Only override controls if no hmd is active and this script is enabled
if (EmulatorEnabled == false || HMDIsActive) {
return;
}
// Window doesn't have focus
if(!HasRequiredFocus()) {
return;
}
// Make sure grabbers are assigned
checkGrabbers();
// Simulate Left Controller states
if (LeftTriggerAction != null) {
prevVal = InputBridge.Instance.LeftTrigger;
InputBridge.Instance.LeftTrigger = LeftTriggerAction.action.ReadValue<float>();
InputBridge.Instance.LeftTriggerDown = prevVal < InputBridge.Instance.DownThreshold && InputBridge.Instance.LeftTrigger >= InputBridge.Instance.DownThreshold;
InputBridge.Instance.LeftTriggerUp = prevVal > InputBridge.Instance.DownThreshold && InputBridge.Instance.LeftTrigger < InputBridge.Instance.DownThreshold;
}
if (LeftGripAction != null) {
prevVal = InputBridge.Instance.LeftGrip;
InputBridge.Instance.LeftGrip = LeftGripAction.action.ReadValue<float>();
InputBridge.Instance.LeftGripDown = prevVal < InputBridge.Instance.DownThreshold && InputBridge.Instance.LeftGrip >= InputBridge.Instance.DownThreshold;
}
if(LeftThumbNearAction != null) {
InputBridge.Instance.LeftThumbNear = LeftThumbNearAction.action.ReadValue<float>() == 1;
}
// Simulate Right Controller states
if (RightTriggerAction!= null) {
float rightTriggerVal = RightTriggerAction.action.ReadValue<float>();
prevVal = InputBridge.Instance.RightTrigger;
InputBridge.Instance.RightTrigger = RightTriggerAction.action.ReadValue<float>();
InputBridge.Instance.RightTriggerDown = prevVal < InputBridge.Instance.DownThreshold && InputBridge.Instance.RightTrigger >= InputBridge.Instance.DownThreshold;
InputBridge.Instance.RightTriggerUp = prevVal > InputBridge.Instance.DownThreshold && InputBridge.Instance.RightTrigger < InputBridge.Instance.DownThreshold;
}
if (RightGripAction != null) {
prevVal = InputBridge.Instance.RightGrip;
InputBridge.Instance.RightGrip = RightGripAction.action.ReadValue<float>();
InputBridge.Instance.RightGripDown = prevVal < InputBridge.Instance.DownThreshold && InputBridge.Instance.RightGrip >= InputBridge.Instance.DownThreshold;
}
if(RightThumbNearAction) {
InputBridge.Instance.RightThumbNear = RightThumbNearAction.action.ReadValue<float>() == 1;
}
}
public void CheckPlayerControls() {
// Require focus
if(EditorOnly && !Application.isEditor) {
return;
}
// Player Up / Down
if(AllowUpDownControls) {
if (PlayerUpAction != null && PlayerUpAction.action.ReadValue<float>() == 1) {
player.ElevateCameraHeight = Mathf.Clamp(player.ElevateCameraHeight + Time.deltaTime, MinPlayerHeight, MaxPlayerHeight);
}
else if (PlayerDownAction != null && PlayerDownAction.action.ReadValue<float>() == 1) {
player.ElevateCameraHeight = Mathf.Clamp(player.ElevateCameraHeight - Time.deltaTime, MinPlayerHeight, MaxPlayerHeight);
}
}
// Force Forward Arrow
if(ForceStraightTeleportRotation && playerTeleport != null && playerTeleport.ForceStraightArrow == false) {
playerTeleport.ForceStraightArrow = true;
}
// Player Move Forward / Back, Snap Turn
if (smoothLocomotion != null && smoothLocomotion.enabled == false) {
// Manually allow player movement if the smooth locomotion component is disabled
smoothLocomotion.CheckControllerReferences();
smoothLocomotion.UpdateInputs();
if(smoothLocomotion.ControllerType == PlayerControllerType.CharacterController) {
smoothLocomotion.MoveCharacter();
}
else if (smoothLocomotion.ControllerType == PlayerControllerType.Rigidbody) {
smoothLocomotion.MoveRigidCharacter();
}
}
}
void FixedUpdate() {
// Player Move Forward / Back, Snap Turn
//if (smoothLocomotion != null && smoothLocomotion.enabled == false && smoothLocomotion.ControllerType == PlayerControllerType.Rigidbody) {
// smoothLocomotion.MoveRigidCharacter();
//}
}
public virtual void UpdateControllerPositions() {
leftControllerTranform.transform.localPosition = LeftControllerPosition;
leftControllerTranform.transform.localEulerAngles = Vector3.zero;
rightControllerTranform.transform.localPosition = RightControllerPosition;
rightControllerTranform.transform.localEulerAngles = Vector3.zero;
}
void checkGrabbers() {
// Find Grabber Left
if (grabberLeft == null || !grabberLeft.isActiveAndEnabled) {
Grabber[] grabbers = FindObjectsOfType<Grabber>();
for (var x = 0; x < grabbers.Length; x++) {
if (grabbers[x] != null && grabbers[x].isActiveAndEnabled && grabbers[x].HandSide == ControllerHand.Left) {
grabberLeft = grabbers[x];
}
}
}
// Find Grabber Right
if (grabberRight == null || !grabberRight.isActiveAndEnabled) {
Grabber[] grabbers = FindObjectsOfType<Grabber>();
for (var x = 0; x < grabbers.Length; x++) {
if (grabbers[x] != null && grabbers[x].isActiveAndEnabled && grabbers[x].HandSide == ControllerHand.Right) {
grabberRight = grabbers[x];
}
}
}
}
public virtual void ResetHands() {
leftControllerTranform.transform.localPosition = Vector3.zero;
leftControllerTranform.transform.localEulerAngles = Vector3.zero;
rightControllerTranform.transform.localPosition = Vector3.zero;
rightControllerTranform.transform.localEulerAngles = Vector3.zero;
}
public virtual void ResetAll() {
ResetHands();
// Reset Camera
mainCameraTransform.localEulerAngles = Vector3.zero;
// Reset Player
if (player) {
player.ElevateCameraHeight = _originalPlayerYOffset;
}
// Reset Teleport Status
if(ForceStraightTeleportRotation && playerTeleport) {
playerTeleport.ForceStraightArrow = priorStraightSetting;
}
didFirstActivate = false;
}
void OnEnable() {
if (EmulatorActionSet != null) {
foreach (var map in EmulatorActionSet.actionMaps) {
foreach (var action in map) {
if(action != null) {
action.Enable();
}
}
}
}
// Subscribe to input events
InputBridge.OnInputsUpdated += UpdateInputs;
Application.onBeforeRender += OnBeforeRender;
}
void OnDisable() {
// Disable Input Actions
if (EmulatorActionSet != null) {
foreach (var map in EmulatorActionSet.actionMaps) {
foreach (var action in map) {
if (action != null) {
action.Disable();
}
}
}
}
Application.onBeforeRender -= OnBeforeRender;
if (isQuitting) {
return;
}
// Reset Hand Positions
ResetAll();
// Unsubscribe from input events
InputBridge.OnInputsUpdated -= UpdateInputs;
}
bool isQuitting = false;
void OnApplicationQuit() {
isQuitting = true;
}
}
}