/*
* Copyright (c) Meta Platforms, Inc. and affiliates.
* All rights reserved.
*
* Licensed under the Oculus SDK License Agreement (the "License");
* you may not use the Oculus SDK except in compliance with the License,
* which is provided at the time of installation or download, or which
* otherwise accompanies this software in either electronic or hard copy form.
*
* You may obtain a copy of the License at
*
* https://developer.oculus.com/licenses/oculussdk/
*
* Unless required by applicable law or agreed to in writing, the Oculus SDK
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
using System.Collections;
using UnityEngine;
///
/// Listens to the user's input, moves and animates Oppy accordingly.
///
[RequireComponent(typeof(CharacterController))]
[RequireComponent(typeof(Animator))]
public class OppyCharacterController : MonoBehaviour
{
///
/// The transform who's the forward vector for Oppy's motion
///
[SerializeField] private Transform movementFrameOfReference;
///
/// The vertical speed that Oppy will have if the jump button is pressed
///
[SerializeField] private float jumpSpeed = 4;
///
/// The vertical acceleration applied to Oppy if the jump button is kept pressed
///
[SerializeField] private float keepPressedJumpAcceleration = 1;
[SerializeField] private OVRInput.Button jumpButton;
///
/// The transform in front of which Oppy will be respawned
///
[SerializeField] private Transform respawnTransform;
[SerializeField] private float maximumLinearSpeed = 0.9f;
[SerializeField] private float gravity = -9.8f;
private Animator _animator;
private CharacterController _characterController;
private Vector3 _moveVelocity;
private Quaternion _rotation;
private Vector2 _motionInput;
private bool _jumpRequested;
private JumpingState _jumpingState = JumpingState.Grounded;
private const float JumpDelay = 0.16f;
private enum JumpingState
{
Grounded,
JumpStarted,
JumpedAndAirborne
}
void Awake()
{
_characterController = GetComponent();
_animator = GetComponent();
}
void Update()
{
GetLocomotionInput();
HandleLocomotion();
HandleJumping();
ApplyMotion();
}
public void Respawn()
{
if (_characterController == null)
{
_characterController = GetComponent();
}
_characterController.enabled = false;
transform.position = respawnTransform.position + respawnTransform.forward * 0.3f;
_characterController.enabled = true;
}
private void GetLocomotionInput()
{
var hInput =
OVRInput.Get(OVRInput.RawAxis2D.RThumbstick).x;
var vInput =
OVRInput.Get(OVRInput.RawAxis2D.RThumbstick).y;
_motionInput = new Vector2(hInput, vInput);
}
private void ApplyMotion()
{
_moveVelocity.y += gravity * Time.deltaTime;
_characterController.Move(_moveVelocity * Time.deltaTime);
if (Mathf.Abs(_motionInput.y) > 0 || Mathf.Abs(_motionInput.x) > 0)
{
transform.rotation = _rotation;
}
}
private void HandleLocomotion()
{
bool noMovementInput = Mathf.Abs(_motionInput.y) == 0 && Mathf.Abs(_motionInput.x) == 0;
_animator.SetBool("Running", !noMovementInput && _characterController.isGrounded);
Vector3 motionForwardDirection =
Vector3.ProjectOnPlane(movementFrameOfReference.forward, Vector3.up).normalized;
Vector3 motionRightDirection = Vector3.ProjectOnPlane(movementFrameOfReference.right, Vector3.up).normalized;
Vector3 motionDirection = (motionForwardDirection * _motionInput.y + motionRightDirection * _motionInput.x)
.normalized;
_rotation = transform.rotation;
if (_characterController.isGrounded)
{
_moveVelocity = motionDirection * maximumLinearSpeed;
Vector3 lerpedMoveDirection = Vector3.Lerp(transform.forward, motionDirection, 0.6f);
_rotation = Quaternion.LookRotation(lerpedMoveDirection);
}
}
private void HandleJumping()
{
bool jumpButtonDown = OVRInput.GetDown(jumpButton);
bool jumpButtonPressed = OVRInput.Get(jumpButton);
if (_jumpRequested)
{
_moveVelocity.y = jumpSpeed;
_jumpRequested = false;
}
if (_jumpingState == JumpingState.JumpStarted && !_characterController.isGrounded)
{
_jumpingState = JumpingState.JumpedAndAirborne;
}
if (_jumpingState != JumpingState.Grounded && jumpButtonPressed)
{
_moveVelocity.y += keepPressedJumpAcceleration * Time.deltaTime;
}
if (_jumpingState == JumpingState.Grounded && _characterController.isGrounded && jumpButtonDown)
{
_jumpingState = JumpingState.JumpStarted;
StartCoroutine(RequestJumpAfterSeconds(JumpDelay));
_animator.SetTrigger("Jumping");
}
else if (_characterController.isGrounded && _jumpingState == JumpingState.JumpedAndAirborne)
{
_animator.SetTrigger("Landed");
_jumpingState = JumpingState.Grounded;
}
}
private IEnumerator RequestJumpAfterSeconds(float delay)
{
yield return new WaitForSeconds(delay);
_jumpRequested = true;
}
}