Created
March 8, 2020 08:00
-
-
Save shiena/4b4f4e874287a37e4bc14974b76294ec to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| using System; | |
| using System.Collections; | |
| using UnityEngine; | |
| using UnityEngine.XR; | |
| using UnityEngine.UI; | |
| using UnityEngine.XR.Interaction.Toolkit; | |
| [RequireComponent(typeof(CharacterController))] | |
| public class VRRigidbodyFirstPersonController : LocomotionProvider | |
| { | |
| [Serializable] | |
| public class MovementSettings | |
| { | |
| public bool turnModeDisable = false; | |
| [SerializeField] | |
| public bool smoothTurnMode = true; | |
| public bool freeWalkMode = true; | |
| public float ForwardSpeed = 8.0f; // Speed when walking forward | |
| public float BackwardSpeed = 4.0f; // Speed when walking backwards | |
| public float StrafeSpeed = 4.0f; // Speed when walking sideways | |
| public float RunMultiplier = 2.0f; // Speed when sprinting | |
| public KeyCode RunKey = KeyCode.LeftShift; | |
| public float JumpForce = 30f; | |
| public AnimationCurve SlopeCurveModifier = new AnimationCurve(new Keyframe(-90.0f, 1.0f), new Keyframe(0.0f, 1.0f), new Keyframe(90.0f, 0.0f)); | |
| [HideInInspector] public float CurrentTargetSpeed = 8f; | |
| public void UpdateDesiredTargetSpeed(Vector2 input) | |
| { | |
| if (input == Vector2.zero) return; | |
| if (input.x > 0 || input.x < 0) | |
| { | |
| //strafe | |
| CurrentTargetSpeed = StrafeSpeed; | |
| } | |
| if (input.y < 0) | |
| { | |
| //backwards | |
| CurrentTargetSpeed = BackwardSpeed; | |
| } | |
| if (input.y > 0) | |
| { | |
| //forwards | |
| //handled last as if strafing and moving forward at the same time forwards speed should take precedence | |
| CurrentTargetSpeed = ForwardSpeed; | |
| } | |
| } | |
| } | |
| [Serializable] | |
| public class AdvancedSettings | |
| { | |
| public float groundCheckDistance = 0.01f; // distance for checking if the controller is grounded ( 0.01f seems to work best for this ) | |
| public float stickToGroundHelperDistance = 0.5f; // stops the character | |
| public float slowDownRate = 20f; // rate at which the controller comes to a stop when there is no input | |
| public bool airControl; // can the user control the direction that is being moved in the air | |
| [Tooltip("set it to 0.1 or more if you get stuck in wall")] | |
| public float shellOffset; //reduce the radius by that ratio to avoid getting stuck in wall (a value of 0.1f is nice) | |
| } | |
| public PlayerInput InputSource; | |
| private bool startingStill = true; | |
| private Vector3 velocity = Vector3.zero; | |
| public HMDVarietyHandler hmdVarietyScript; | |
| public Transform headsetOffset; | |
| public Transform worldRef; | |
| public float RotationRatchet = 45.0f; | |
| public float smoothTime = 0.15f; | |
| private Vector3 currentRotation = Vector3.zero; | |
| private Vector3 refVelocity = Vector3.zero; | |
| public Camera cam; | |
| public PauseMenuController pauseMenuScript; | |
| public IntroFader fadeScript; | |
| public GameObject fadeBox; | |
| public float CurrentDistance; | |
| public MovementSettings movementSettings = new MovementSettings(); | |
| public AdvancedSettings advancedSettings = new AdvancedSettings(); | |
| private CharacterController m_CharControl; | |
| private Vector3 m_GroundContactNormal; | |
| public bool ReadyToSnapTurn; // Set to true when a snap turn has occurred, code requires one frame of centered thumbstick to enable another snap turn. | |
| private Vector3 desiredMove = Vector3.zero; | |
| public bool loading = false; | |
| public bool colliding = false; | |
| private void OnEnable() | |
| { | |
| InputSource.MenuInputEvent_Left += openPauseMenu; | |
| InputSource.MenuInputEvent_Right += openPauseMenu; | |
| } | |
| private void OnDisable() | |
| { | |
| InputSource.MenuInputEvent_Left -= openPauseMenu; | |
| InputSource.MenuInputEvent_Right -= openPauseMenu; | |
| } | |
| public void openPauseMenu(bool value) | |
| { | |
| pauseMenuScript.pauseButtonPressed(value); | |
| } | |
| private void Start() | |
| { | |
| m_CharControl = GetComponent<CharacterController>(); | |
| StartCoroutine(waitThenStart()); | |
| } | |
| IEnumerator waitThenStart() | |
| { | |
| yield return new WaitForSeconds(0.5f); | |
| startingStill = false; | |
| yield return null; | |
| } | |
| private void Update() | |
| { | |
| PreCharacterMovement(); | |
| } | |
| public void changeTurnMode(bool value) | |
| { | |
| //only do this on button press | |
| value = !movementSettings.smoothTurnMode; | |
| movementSettings.smoothTurnMode = value; | |
| } | |
| public void changeMovementMode(bool value) | |
| { | |
| movementSettings.freeWalkMode = value; | |
| } | |
| void PreCharacterMovement() | |
| { | |
| // First, determine if the lateral movement will collide with the scene geometry. | |
| var oldCameraPos = headsetOffset.position; | |
| var wpos = cam.transform.position; | |
| var delta = wpos - transform.position; | |
| delta.y = 0; | |
| var len = delta.magnitude; | |
| if (len > 0.02f) | |
| { | |
| //Recenter the char controller times 100 for an instant move | |
| //commented out for now due to unwanted fast movement glitches! To rewrite with an alternative | |
| //if (!startingStill) | |
| // { | |
| m_CharControl.Move(delta); | |
| // } | |
| //m_CharControl.Move(delta; | |
| var currentDelta = transform.position - wpos; | |
| currentDelta.y = 0; | |
| CurrentDistance = currentDelta.magnitude; | |
| //Only set the x and z values here so we don't suddenly move the headset down! | |
| headsetOffset.position = new Vector3(oldCameraPos.x, headsetOffset.position.y, oldCameraPos.z); | |
| if (CurrentDistance > 0) | |
| { | |
| headsetOffset.position = oldCameraPos - delta; | |
| } | |
| } | |
| else if (loading == false) | |
| { | |
| CurrentDistance = 0; | |
| } | |
| } | |
| private void FixedUpdate() | |
| { | |
| Vector2 input = GetInput(); | |
| if ((Mathf.Abs(input.x) > float.Epsilon || Mathf.Abs(input.y) > float.Epsilon)) | |
| { | |
| // always move along the camera forward as it is the direction that it being aimed at | |
| desiredMove = cam.transform.forward * input.y + cam.transform.right * input.x; | |
| desiredMove = Vector3.ProjectOnPlane(desiredMove, m_GroundContactNormal).normalized; | |
| desiredMove.x = desiredMove.x * movementSettings.CurrentTargetSpeed; | |
| desiredMove.z = desiredMove.z * movementSettings.CurrentTargetSpeed; | |
| desiredMove.y = 0; | |
| //desiredMove.y = desiredMove.y * movementSettings.CurrentTargetSpeed; | |
| } | |
| else | |
| { | |
| //In here, pass the values of the headset moving past bounds to move the character! To write later... | |
| desiredMove = Vector3.zero; | |
| } | |
| //Rotation here | |
| if (movementSettings.turnModeDisable == false) | |
| { | |
| if (movementSettings.smoothTurnMode == true) | |
| { | |
| //avoids the rotating if the game is effectively paused | |
| if (Mathf.Abs(Time.timeScale) < float.Epsilon) return; | |
| // get the rotation before it's changed | |
| float oldYRotation = transform.eulerAngles.y; | |
| float rightx = Input.GetAxis("RightHorizontal") * smoothTime; | |
| if (rightx == 0) | |
| { | |
| EndLocomotion(); | |
| } | |
| else | |
| { | |
| BeginLocomotion(); | |
| //To smooth this out, smoothTime value must be 0 for instant turning, nearer 0.15 is smooth/slower | |
| Vector3 targetRotation = new Vector3(0, rightx, 0); | |
| currentRotation = Vector3.SmoothDamp(currentRotation, targetRotation, ref refVelocity, 0.01f); | |
| transform.RotateAround(new Vector3(cam.transform.position.x, 0, cam.transform.position.z), Vector3.up, rightx); | |
| //EndLocomotion(); | |
| } | |
| } | |
| //Test this out with the Vive and Oculus Go | |
| else if (movementSettings.smoothTurnMode == false && BeginLocomotion()) | |
| { | |
| //snap turning code here! | |
| // Vector3 euler = transform.rotation.eulerAngles; | |
| float targetAngle = 0; | |
| if (Input.GetAxis("RightHorizontal") < 0) | |
| { | |
| if (ReadyToSnapTurn) | |
| { | |
| // euler.y -= RotationRatchet; | |
| targetAngle -= RotationRatchet; | |
| ReadyToSnapTurn = false; | |
| } | |
| } | |
| else if (Input.GetAxis("RightHorizontal") > 0) | |
| { | |
| if (ReadyToSnapTurn) | |
| { | |
| // euler.y += RotationRatchet; | |
| targetAngle += RotationRatchet; | |
| ReadyToSnapTurn = false; | |
| } | |
| } | |
| else | |
| { | |
| ReadyToSnapTurn = true; | |
| } | |
| //transform.rotation = Quaternion.Euler(euler); | |
| transform.RotateAround(new Vector3(cam.transform.position.x, 0, cam.transform.position.z), Vector3.up, targetAngle); | |
| targetAngle = 0; | |
| EndLocomotion(); | |
| } | |
| } | |
| if (movementSettings.freeWalkMode) | |
| { | |
| m_CharControl.SimpleMove(desiredMove * movementSettings.CurrentTargetSpeed); | |
| } | |
| } | |
| private Vector2 GetInput() | |
| { | |
| Vector2 input = new Vector2 | |
| { | |
| x = Input.GetAxis("Horizontal"), | |
| y = Input.GetAxis("Vertical") | |
| }; | |
| movementSettings.UpdateDesiredTargetSpeed(input); | |
| return input; | |
| } | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment