Facebook
From James Hawkins, 2 Years ago, written in Plain Text.
Embed
Download Paste or View Raw
Hits: 46
  1. using _Game.Player.StateMachine.Necro;
  2. using DG.Tweening;
  3. using UnityEngine;
  4. using UnityEngine.Events;
  5.  
  6. [AddComponentMenu("Game/Player/Necromancer"), DisallowMultipleComponent()]
  7. public class PlayerNecromancerController : MonoBehaviour
  8. {
  9.     public const float StandardJumpForce = 6.5f;
  10.     public const float CoyoteTime = .285f;
  11.     public const float MaxJumpTime = .35f;
  12.     public const float JumpRememberTime = .195f;
  13.     public const float invincibleTime = 1f;
  14.  
  15.     //refs
  16.     [SerializeField] private InputReader _inputReader = default;
  17.     [SerializeField] private CollisionHelper _collisionHelper;
  18.     [SerializeField] private Rigidbody2D _rb;
  19.     [SerializeField] private Animator _animator;
  20.     [SerializeField] private SpriteRenderer _spriteRenderer;
  21.     [SerializeField] private CapsuleCollider2D _capsuleCollider;
  22.  
  23.     #region FSM
  24.     private NecroBaseState m_currentState = null;
  25.  
  26.     private readonly NecroGroundState m_groundedState = new NecroGroundState();
  27.     private readonly NecroJumpingState m_jumpingState = new NecroJumpingState();
  28.     private readonly NecroFallingState m_fallingState = new NecroFallingState();
  29.     private readonly NecroDeadState m_necroDeadState = new NecroDeadState();
  30.  
  31.     public NecroGroundState GroundedState => m_groundedState;
  32.     public NecroJumpingState JumpingState => m_jumpingState;
  33.     public NecroFallingState FallingState => m_fallingState;
  34.     public NecroDeadState DeadState => m_necroDeadState;
  35.     #endregion
  36.  
  37.     [Header("Customizables"), Space(5)]
  38.     public float moveSpeed;
  39.     public float jumpHeight;
  40.     public float fastFallMultiplier = 2f;
  41.     [SerializeField, Range(42, 120)] private float airRecoveryRate = 45f;
  42.     [Space(5)]
  43.     [Range(0, .3f), SerializeField] private float smoothingFactor = 0.1666f;
  44.     [Range(0, .56f), SerializeField] private float airSmoothingFactor = 0.1666f;
  45.  
  46.     [Space(5)]
  47.     private Vector2 _previousMovementInput;
  48.     public bool jumpInput;
  49.     private float startGravityScale;
  50.     private float m_jumpForce;
  51.  
  52.     private readonly Vector2 capsuleColliderDeadOffset = new Vector2(0, -0.62f);
  53.     private Vector2 initialVerticalCapsuleSize;
  54.     private IInteractable _interactable;
  55.  
  56.     #region Timers
  57.     private float coyoteTimer;
  58.     private float jumpLimitTimer;
  59.     private float rememberJumpTimer;
  60.     private float invincibleFrameTimer;
  61.     #endregion
  62.  
  63.     internal Vector2 m_velocityVar;
  64.     internal float currentXVelocity;
  65.  
  66.     [Space(5)] public UnityEvent onWizardDead;
  67.  
  68.     public bool alive = true;
  69.  
  70.     //Accesors
  71.     public Vector2 TargetMoveSpeed => (Vector2.right * moveSpeed * _previousMovementInput);
  72.     public Rigidbody2D Rigidbody => _rb;
  73.     public float SmoothingFactor => smoothingFactor;
  74.     public CollisionHelper CollsionsH => _collisionHelper;
  75.  
  76.     public float CoyoteTimer
  77.     {
  78.         get => coyoteTimer;
  79.         set => coyoteTimer = value;
  80.     }
  81.  
  82.     public float RememberJumpTimer
  83.     {
  84.         get => rememberJumpTimer;
  85.         set => rememberJumpTimer = value;
  86.     }
  87.  
  88.     public float JumpTimer => jumpLimitTimer;
  89.     public SpriteRenderer SpriteRenderer => _spriteRenderer;
  90.     public Animator Animator => _animator;
  91.  
  92.     private void OnEnable()
  93.     {
  94.         _inputReader.jumpEvent += OnJumpInitiated;
  95.         _inputReader.jumpCanceledEvent += OnJumpCanceled;
  96.         _inputReader.moveEvent += OnMove;
  97.         _inputReader.interactEvent += OnInteract;
  98.     }
  99.  
  100.     private void OnDisable()
  101.     {
  102.         _inputReader.jumpEvent -= OnJumpInitiated;
  103.         _inputReader.jumpCanceledEvent -= OnJumpCanceled;
  104.         _inputReader.moveEvent -= OnMove;
  105.         _inputReader.interactEvent -= OnInteract;
  106.     }
  107.  
  108.     private void Awake()
  109.     {
  110.         ChangeState(m_groundedState);
  111.         startGravityScale = _rb.gravityScale;
  112.         initialVerticalCapsuleSize = _capsuleCollider.size;
  113.     }
  114.  
  115.     private void Start()
  116.     {
  117.         GameManager.Instance.onGameOver.AddListener(() =>
  118.         { this.enabled = false; });
  119.     }
  120.  
  121.     private void OnInteract()
  122.     {
  123.         //ToDo: For Talking
  124.         //Should work on any state but Dead
  125.         if (ReferenceEquals(m_currentState, m_necroDeadState) || PauseManager.paused)
  126.         {
  127.             Debug.Log("Invalid State");
  128.             return;
  129.         }
  130.  
  131.         if (!ReferenceEquals(_interactable, null)) _interactable.Interact();
  132.  
  133.     }
  134.  
  135.     private void OnMove(Vector2 movement) { _previousMovementInput = movement; }
  136.  
  137.     private void OnJumpInitiated()
  138.     {
  139.         jumpInput = true;
  140.         rememberJumpTimer = JumpRememberTime;
  141.  
  142.         m_currentState.OnPlayerJump(this);
  143.     }
  144.  
  145.     private void OnJumpCanceled() { jumpInput = false; }
  146.  
  147.     void Update()
  148.     {
  149.         if (PauseManager.paused) return;
  150.  
  151.         //Limit Jumps
  152.         if (jumpLimitTimer > 0)
  153.             jumpLimitTimer -= Time.deltaTime;
  154.  
  155.         if (invincibleFrameTimer > 0)
  156.             invincibleFrameTimer -= Time.deltaTime;
  157.  
  158.         m_currentState.Update(this);
  159.  
  160.         _rb.velocity = new Vector2(_rb.velocity.x, Mathf.Clamp(_rb.velocity.y, -10, 20f));
  161.     }
  162.  
  163.     private void FixedUpdate()
  164.     {
  165.         if (PauseManager.paused) return;
  166.  
  167.         m_currentState.FixedUpdate(this);
  168.     }
  169.  
  170.     public void HandleSpriteFlip()
  171.     {
  172.         if (Mathf.Abs(_previousMovementInput.x) >= float.Epsilon)
  173.             _spriteRenderer.flipX = _previousMovementInput.x < 0 ? true : false;
  174.     }
  175.  
  176.     public void Walk()
  177.     {
  178.         var x = Mathf.SmoothDamp(_rb.velocity.x, TargetMoveSpeed.x, ref currentXVelocity, SmoothingFactor);
  179.         _rb.velocity = new Vector2(x, _rb.velocity.y);
  180.  
  181.     }
  182.  
  183.     public void HandleMovementAnimation()
  184.     {
  185.         if (Mathf.Abs(_previousMovementInput.x) >= float.Epsilon)
  186.         {
  187.             Animator.Play("Walk");
  188.             Animator.SetFloat("xSpeed", Mathf.Abs(_rb.velocity.x / moveSpeed));
  189.         }
  190.         else
  191.         {
  192.             if (Mathf.Approximately(Mathf.Floor(_rb.velocity.x), 0)) { Animator.Play("Idle"); }
  193.             else { Animator.SetFloat("xSpeed", Mathf.Clamp01(Mathf.Abs(_rb.velocity.x))); }
  194.         }
  195.     }
  196.  
  197.     //Walk While in the air
  198.     public void AirWalk()
  199.     {
  200.         var x = Mathf.SmoothDamp(_rb.velocity.x, TargetMoveSpeed.x, ref currentXVelocity, airSmoothingFactor);
  201.         _rb.velocity = new Vector2(x, _rb.velocity.y);
  202.     }
  203.  
  204.     public void AirResistMoveSimpler()
  205.     {
  206.         _rb.velocity = new Vector2(Approach(_rb.velocity.x, moveSpeed * _previousMovementInput.x, airRecoveryRate * .65f * Time.fixedDeltaTime), _rb.velocity.y);
  207.     }
  208.  
  209.     public void Hop()
  210.     {
  211.         _rb.velocity = new Vector2(_rb.velocity.x, 0);
  212.         _rb.gravityScale = startGravityScale;
  213.         SetJumpForceAtDesiredHeight();
  214.  
  215.         var jumpForce = m_jumpForce * 1.025f / 2;
  216.  
  217.         jumpLimitTimer = MaxJumpTime;
  218.  
  219.         float xforce = _rb.velocity.x + (Mathf.Abs(_rb.velocity.x) > 0 ? Mathf.Sign(_rb.velocity.x) * Mathf.Abs(_previousMovementInput.x) : 0) * 1.025f;
  220.  
  221.         _rb.velocity = new Vector2(xforce, jumpForce);
  222.  
  223.     }
  224.  
  225.     public void FrameIndependentHeldJump(float heldTime)
  226.     {
  227.         //ToDo: Remove Double Guard statement
  228.         if (heldTime <= MaxJumpTime && Vector2.Dot(_rb.velocity, Vector2.up) > 0)
  229.         {
  230.             float frameRatio = heldTime / MaxJumpTime;
  231.  
  232.             frameRatio = Mathf.Abs(frameRatio - 1);
  233.             //Debug.Log(frameRatio);
  234.             //float yForce = Mathf.Lerp(m_jumpForce + 2, 0, frameRatio);
  235.             _rb.AddForce(m_jumpForce * 1.025f * 2 * _rb.mass * Vector2.up * frameRatio);
  236.         }
  237.         else { jumpInput = false; }
  238.     }
  239.  
  240.     public void SetJumpForceAtDesiredHeight()
  241.     {
  242.         m_jumpForce = Mathf.Sqrt(_rb.gravityScale * Physics2D.gravity.magnitude * 2 * jumpHeight);
  243.     }
  244.  
  245.     public void ChangeState(NecroBaseState state)
  246.     {
  247.         //Guard Statement
  248.         if (state == m_currentState) { return; }
  249.  
  250.         m_currentState = state;
  251.         m_currentState.EnterState(this);
  252.     }
  253.  
  254.     public static float Approach(float val, float target, float maxMove)
  255.     {
  256.         return val > target ? Mathf.Max(val - maxMove, target) : Mathf.Min(val + maxMove, target);
  257.     }
  258.  
  259.     public void TryToDie() { if (invincibleFrameTimer <= 0) { Death(); } }
  260.  
  261.     public void Death()
  262.     {
  263.         ChangeState(m_necroDeadState);
  264.         SFXManager.instance.Play("Splat");
  265.     }
  266.  
  267.     //ToDo: Move CapsuleMorph to another script
  268.     public void MorphCapsuleColliderVertical()
  269.     {
  270.         if (_capsuleCollider.direction == CapsuleDirection2D.Vertical) { return; }
  271.         _capsuleCollider.direction = CapsuleDirection2D.Vertical;
  272.         _capsuleCollider.offset = Vector2.zero;
  273.  
  274.         DOTween.To(() => _capsuleCollider.size, x => _capsuleCollider.size = x, initialVerticalCapsuleSize, .45f).SetEase(Ease.InOutCubic);
  275.     }
  276.  
  277.     public void Revive()
  278.     {
  279.         invincibleFrameTimer = invincibleTime;//This can also be set when we enter the death state
  280.         ReturnToCorrectState();
  281.     }
  282.  
  283.     public void ReturnToCorrectState()
  284.     {
  285.         if (_collisionHelper.onGround) { ChangeState(GroundedState); }
  286.         else { ChangeState(FallingState); }
  287.     }
  288.  
  289.     public void MorphCapsuleColliderHorizontal()
  290.     {
  291.         if (_capsuleCollider.direction == CapsuleDirection2D.Horizontal) { return; }
  292.         _capsuleCollider.direction = CapsuleDirection2D.Horizontal;
  293.         _capsuleCollider.offset = capsuleColliderDeadOffset;
  294.  
  295.         DOTween.To(() => _capsuleCollider.size, x => _capsuleCollider.size = x, new Vector2(initialVerticalCapsuleSize.y, initialVerticalCapsuleSize.x), .45f).SetEase(Ease.InOutCubic)/*.OnComplete(Hop)*/;
  296.     }
  297.  
  298.     private void OnTriggerEnter2D(Collider2D collision)
  299.     {
  300.         TryPopulateInteractable(collision);
  301.     }
  302.     private void OnTriggerExit2D(Collider2D collision)
  303.     {
  304.         TryDisposeInteractable(collision);
  305.     }
  306.  
  307.     private void TryPopulateInteractable(Collider2D collision)
  308.     {
  309.         var other = collision.GetComponent<IInteractable>();
  310.         if (!ReferenceEquals(other, null) && ReferenceEquals(_interactable, null)) { _interactable = other; }
  311.     }
  312.  
  313.     private void TryDisposeInteractable(Collider2D collision)
  314.     {
  315.         var other = collision.GetComponent<IInteractable>();
  316.         if (!ReferenceEquals(other, _interactable)) { DisposeInteractable(); }
  317.     }
  318.  
  319.     public void DisposeInteractable()
  320.     {
  321.         _interactable = null;
  322.     }
  323.  
  324.     private void OnValidate()
  325.     {
  326.         if (Application.isPlaying) { return; }
  327.  
  328.         if (_collisionHelper == null) { _collisionHelper = GetComponent<CollisionHelper>(); }
  329.         if (_rb == null) { _rb = GetComponent<Rigidbody2D>(); }
  330.  
  331.     }
  332.  
  333. }
  334.  
captcha