revival/game/Assets/Scripts/Player/PlayerController.cs

405 lines
11 KiB
C#
Raw Permalink Normal View History

2021-02-15 19:09:32 +01:00
using Extensions;
using UnityEngine;
2021-02-15 19:09:32 +01:00
using NaughtyAttributes;
2021-03-08 15:16:20 +01:00
using Ktyl.Util;
2021-03-13 03:01:20 +01:00
using System.Collections;
2021-05-17 15:31:13 +02:00
using FMOD;
using FMOD.Studio;
2021-04-16 20:30:49 +02:00
using FMODUnity;
2021-03-13 03:01:20 +01:00
using UnityEngine.UI;
2021-05-17 15:31:13 +02:00
using STOP_MODE = FMOD.Studio.STOP_MODE;
public class PlayerController : MonoBehaviour
{
2021-02-15 19:09:32 +01:00
[Header("Config")]
[SerializeField]
2021-02-15 19:09:32 +01:00
[Expandable]
private PlayerMovementSettings _movementSettings;
2021-02-15 19:09:32 +01:00
[Header("References")]
[SerializeField]
private PlayerInputHandler _inputHandler;
[SerializeField]
2021-02-15 19:09:32 +01:00
private CharacterController _controller;
[SerializeField]
private PlayerAnimationController _animController;
2021-02-15 19:09:32 +01:00
[SerializeField]
private PlayerPowers _powers;
[SerializeField]
private Transform _graphics;
[SerializeField]
private Renderer[] _renderers;
[Header( "Debug" )]
[SerializeField]
private Color _groundedColor;
[SerializeField]
private Color _jumpColor;
[SerializeField]
private Color _boostColor;
[SerializeField]
private Color _exhaustedColor;
[ShowNonSerializedField]
private Vector2 _surfVelocity;
[ShowNonSerializedField]
private Vector2 _overrideDelta;
[ShowNonSerializedField]
private float _lookAngle;
[ShowNonSerializedField]
private float _yVelocity;
[ShowNonSerializedField]
private bool _grounded;
2021-02-18 18:24:15 +01:00
2021-02-15 19:09:32 +01:00
[ShowNativeProperty]
2021-02-18 18:24:15 +01:00
private bool Still => Mathf.Approximately(_inputHandler?.InputState?.Move.Value.sqrMagnitude ?? 0f, 0f);
2021-02-15 19:09:32 +01:00
[ShowNonSerializedField]
private float _boostTime;
[ShowNonSerializedField]
private float _fallTime;
public bool CanJump => _grounded || _fallTime < _movementSettings.CoyoteTime;
private const float PI = Mathf.PI;
private const float TAU = Mathf.PI * 2f;
private const float HALF_PI = Mathf.PI / 2f;
2021-03-13 03:01:20 +01:00
private float timeSinceStop;
2021-03-08 15:16:20 +01:00
2021-03-13 03:01:20 +01:00
[Header("Power Freeze")]
2021-03-08 15:16:20 +01:00
[SerializeField]
2021-03-13 03:01:20 +01:00
private SerialFloat objectTimeScale;
[SerializeField]
2021-03-16 16:49:54 +01:00
private SerialFloat frozenTime;
[SerializeField]
private DialogueSystem _dialogueSystem;
[SerializeField]
private string _freezeFirstUseDialogueKey;
2021-03-08 15:16:20 +01:00
2021-04-16 16:43:19 +02:00
[SerializeField]
private GameObject _freezeVfx;
2021-05-17 18:02:55 +02:00
[SerializeField]
[FMODUnity.EventRef]
private string _jumpSfx;
private EventInstance _jumpInstance;
2021-04-16 16:43:19 +02:00
[SerializeField]
[FMODUnity.EventRef]
private string _freezeSfx;
2021-05-17 15:31:13 +02:00
private EventInstance _freezeInstance;
2021-04-16 16:43:19 +02:00
2021-04-16 20:30:49 +02:00
[SerializeField]
[FMODUnity.EventRef]
private string _blinkSfx;
2021-05-17 15:31:13 +02:00
private EventInstance _blinkInstance;
2021-04-16 20:30:49 +02:00
[SerializeField]
[FMODUnity.EventRef]
private string _boostSfx;
2021-05-17 15:31:13 +02:00
private EventInstance _boostInstance;
2021-04-16 20:30:49 +02:00
2021-02-15 19:09:32 +01:00
private enum JumpState
{
None,
Jump,
Boost,
Exhausted,
COUNT,
}
[ShowNonSerializedField]
private JumpState _jumpState;
2021-05-17 15:31:13 +02:00
private void Start()
{
2021-04-16 16:43:19 +02:00
_freezeVfx.SetActive( false );
2021-05-17 15:31:13 +02:00
2021-05-17 18:02:55 +02:00
_jumpInstance = RuntimeManager.CreateInstance( _jumpSfx );
2021-05-17 15:31:13 +02:00
_freezeInstance = RuntimeManager.CreateInstance( _freezeSfx );
_blinkInstance = RuntimeManager.CreateInstance( _blinkSfx );
_boostInstance = RuntimeManager.CreateInstance( _boostSfx );
}
private void PlayPlayerSFX( EventInstance instance )
{
2021-05-17 18:02:55 +02:00
instance.stop(STOP_MODE.ALLOWFADEOUT);
2021-05-17 15:31:13 +02:00
instance.start();
RuntimeManager.AttachInstanceToGameObject( instance, transform, (Rigidbody)null );
}
2021-02-15 19:09:32 +01:00
private Color GetDebugColor()
{
switch ( _jumpState )
{
case JumpState.None:
return _groundedColor;
case JumpState.Jump:
return _jumpColor;
case JumpState.Boost:
return _boostColor;
case JumpState.Exhausted:
return _exhaustedColor;
}
return Color.red;
}
private float normaliseAngle( float angle )
{
while ( angle > PI )
{
angle -= TAU;
}
while ( angle < -PI )
{
angle += TAU;
}
return angle;
}
private void Land()
{
_powers.Blink.Reset();
_powers.Boost.Reset();
}
private void UpdateLook( float dt )
{
if ( _surfVelocity.sqrMagnitude > 0.01f )
{
float targetAngle = -Vector2.SignedAngle( Vector2.up, _surfVelocity.normalized ) * Mathf.Deg2Rad;
float delta = targetAngle - _lookAngle;
float ls = _movementSettings.LookSpeed * dt;
_lookAngle += Mathf.Clamp( normaliseAngle(delta), -ls, ls );
_lookAngle = normaliseAngle( _lookAngle );
}
}
private void UpdateBlink( float dt )
{
if ( _powers.Blink.CanConsume && _inputHandler.InputState.Blink.GetDown() )
{
_powers.Blink.Consume();
Vector2 blinkDirection = Vector2.up.Rotate( -_lookAngle );
_overrideDelta += blinkDirection * _movementSettings.BlinkDistance;
_surfVelocity += blinkDirection * _movementSettings.BlinkVelocity;
2021-05-17 15:31:13 +02:00
PlayPlayerSFX( _blinkInstance );
2021-02-15 19:09:32 +01:00
}
}
2021-03-08 15:16:20 +01:00
2021-03-13 03:01:20 +01:00
private void UpdateFreeze( float dt)
2021-03-08 15:16:20 +01:00
{
2021-03-13 03:01:20 +01:00
if ( _powers.Freeze.CanConsume && _inputHandler.InputState.Freeze.GetRawValue() )
2021-03-08 15:16:20 +01:00
{
_powers.Freeze.Consume();
2021-03-13 03:01:20 +01:00
objectTimeScale.Value = 0f;
2021-04-16 16:43:19 +02:00
_freezeVfx.SetActive( true );
2021-05-17 15:31:13 +02:00
PlayPlayerSFX( _freezeInstance );
2021-03-08 15:16:20 +01:00
}
2021-03-13 03:01:20 +01:00
2021-04-13 16:33:59 +02:00
if ( _powers.Freeze.timeSinceConsume > frozenTime && TimeIsFrozen )
2021-03-13 03:01:20 +01:00
{
UnfreezeTime();
2021-05-14 20:08:27 +02:00
_dialogueSystem.PlayLineRadio( _freezeFirstUseDialogueKey );
2021-04-16 16:43:19 +02:00
_freezeVfx.SetActive( false );
2021-04-16 20:30:49 +02:00
// TODO: unfreeze sfx?
2021-03-13 03:01:20 +01:00
}
2021-03-08 15:16:20 +01:00
}
2021-03-13 03:01:20 +01:00
2021-04-13 16:33:59 +02:00
public bool TimeIsFrozen
=> objectTimeScale.AsBool;
2021-03-13 03:01:20 +01:00
private void UnfreezeTime()
{
objectTimeScale.Value = 1f;
}
2021-03-16 16:49:54 +01:00
private void FreezeReset()
2021-03-13 03:01:20 +01:00
{
2021-03-16 16:49:54 +01:00
_powers.Freeze.Reset();
}
2021-03-13 03:01:20 +01:00
2021-03-08 15:16:20 +01:00
2021-02-15 19:09:32 +01:00
private void UpdateJump(float dt)
{
_fallTime = _grounded ? 0f : (_fallTime + dt);
switch ( _jumpState )
{
case JumpState.None:
if ( CanJump )
{
if ( _inputHandler.InputState.Jump.GetDown() )
{
_grounded = false;
_jumpState = JumpState.Jump;
_yVelocity = Mathf.Sqrt( 2f * _movementSettings.JumpHeight * _movementSettings.UpGravity );
2021-05-17 18:02:55 +02:00
PlayPlayerSFX( _jumpInstance );
2021-02-15 19:09:32 +01:00
// always make sure we can blink once per jump
_powers.Blink.Reset();
}
}
else
{
_jumpState = JumpState.Jump;
}
break;
case JumpState.Jump:
if ( _powers.Boost.CanConsume && _inputHandler.InputState.Jump.GetDown( consume: false ) )
{
_powers.Boost.Consume();
_boostTime = 0f;
_jumpState = JumpState.Boost;
if ( _yVelocity < _movementSettings.MinBoostVelocity )
{
_yVelocity = _movementSettings.MinBoostVelocity;
}
2021-04-16 20:30:49 +02:00
2021-05-17 15:31:13 +02:00
PlayPlayerSFX( _boostInstance );
2021-02-15 19:09:32 +01:00
}
break;
case JumpState.Boost:
if ( _inputHandler.InputState.Jump.GetRawValue() )
{
_yVelocity += _movementSettings.BoostForce * dt;
_boostTime += dt;
if ( _boostTime > _movementSettings.BoostTime )
{
_jumpState = JumpState.Exhausted;
}
}
break;
default:
break;
}
}
private void UpdateGravity( float dt )
{
if ( _grounded )
{
_yVelocity = _movementSettings.GroundedYVelocity;
_jumpState = JumpState.None;
}
else
{
if ( _yVelocity > 0f && _jumpState == JumpState.Jump )
{
_yVelocity -= ( _movementSettings.UpGravity * dt );
}
else
{
_yVelocity -= ( _movementSettings.DownGravity * dt );
}
}
}
private void UpdateDrag( float dt )
{
Vector2 drag = -_surfVelocity;
float coefficient
= _grounded
? ( Still
? _movementSettings.StillDragCoefficient
: _movementSettings.DragCoefficient )
: ( _jumpState == JumpState.Boost
? _movementSettings.BoostDragCoefficient
: _movementSettings.AirDragCoefficient );
_surfVelocity += drag * (dt * coefficient);
}
private void UpdateMovement( float dt )
{
Vector2 moveVector = _inputHandler.InputState.Move.Value;
_surfVelocity += moveVector * (_movementSettings.BaseMovementForce * dt);
}
private void UpdateDebug()
{
Color debugColor = GetDebugColor();
for ( int i = 0; i < _renderers.Length; ++i )
{
_renderers[ i ].material.color = debugColor;
}
}
private void UpdateAnims()
{
var animParams = new PlayerAnimationController.AnimationParams();
animParams.IsWalking = _controller.velocity.sqrMagnitude > 0.01f;
animParams.InJumpState = _jumpState != JumpState.None;
animParams.InBoostState = _jumpState == JumpState.Boost || _jumpState == JumpState.Exhausted;
_animController.ProcessAnimUpdate( animParams );
}
private void FixedUpdate()
{
2021-03-13 03:01:20 +01:00
float dt = Time.fixedDeltaTime;
2021-02-15 19:09:32 +01:00
_overrideDelta = Vector2.zero;
if ( !_grounded && _controller.isGrounded )
{
Land();
}
_grounded = _controller.isGrounded;
_powers.UpdatePowers( dt, _grounded );
UpdateJump( dt );
UpdateLook( dt );
UpdateBlink( dt );
2021-03-13 03:01:20 +01:00
UpdateFreeze( dt );
2021-02-15 19:09:32 +01:00
UpdateGravity( dt );
UpdateDrag( dt );
UpdateMovement( dt );
UpdateDebug();
UpdateAnims();
2021-02-15 19:09:32 +01:00
_controller.Move(
new Vector3(
_surfVelocity.x * dt + _overrideDelta.x,
_yVelocity * dt,
_surfVelocity.y * dt + _overrideDelta.y
)
);
2021-02-15 19:09:32 +01:00
_graphics.rotation = Quaternion.Euler( 0f, _lookAngle * Mathf.Rad2Deg, 0f );
}
}