Skip to content

Instantly share code, notes, and snippets.

@mrkybe
Created March 1, 2023 23:09
Show Gist options
  • Save mrkybe/b086af5e9e80603e8d4e111689baf344 to your computer and use it in GitHub Desktop.
Save mrkybe/b086af5e9e80603e8d4e111689baf344 to your computer and use it in GitHub Desktop.
using Assets;
using Assets.Scripts;
using System.Collections;
using UnityEngine;
using Random = UnityEngine.Random;
public class PlayerController : EntController
{
public static PlayerController Instance { get; private set; }
[SerializeField]
public GameObject ProjectilePrefab;
[SerializeField]
public AnimationClip _Idle;
[SerializeField]
public AnimationClip _Walk;
[SerializeField]
public AnimationClip _Run;
[SerializeField]
public AnimationClip _Jump;
[SerializeField]
public AnimationClip _JumpAttack;
[SerializeField]
public AnimationClip _Hurt;
[SerializeField]
public AnimationClip _Fall;
[SerializeField]
public AnimationClip _Basic_Attack_1;
[SerializeField]
public AnimationClip _Basic_Attack_2;
[SerializeField]
public AnimationClip _DashAttack;
[SerializeField]
public AnimationClip _Kick;
[SerializeField]
public AnimationClip _RoundHouseKick;
[SerializeField]
public AnimationClip _Smack;
[SerializeField]
public AnimationClip _Throw;
[SerializeField]
public AnimationClip _Thrust;
[SerializeField]
public AnimationClip _Dead;
[SerializeField]
public float MaxSprintEnergy = 1f;
[SerializeField]
public float SprintEnergy = 1f;
[SerializeField]
public float MovementSpeed = 1f;
[SerializeField]
public float SprintMultiplier = 2f;
public float RemainingSprintPercent { get => SprintEnergy / MaxSprintEnergy; }
public bool IsSprinting = false;
private Transform ReferenceTransform;
private Camera ReferenceCamera;
private DefaultControls controls;
private bool LockInDirection;
private Vector3 LockedDirection;
private bool CanCancelAttackIntoMovement = false;
private bool CanCancelAttackIntoNewAttack = false;
private bool WantToCancelAttack = false;
public CharHealth CharHealth;
[SerializeField]
private BoxCollider2D HitboxSword;
[SerializeField]
private LayerMask HitboxOnlyLayerMask;
protected new void Awake()
{
base.Awake();
CharHealth = GetComponent<CharHealth>();
CharHealth.TookDamageEvent += MyHealth_TookDamageEvent;
CharHealth.DiedEvent += MyHealth_DiedEvent;
ZDepthOffset = 5;
if (Instance == null)
{
Instance = this;
ReferenceTransform = Instance.transform;
}
else
{
Debug.LogError("too many players", this);
}
HitboxSword.enabled = false;
CantMoveCauses.Add(() => { return IsFalling; });
CantMoveCauses.Add(() => { return animController.IsPlaying(_Basic_Attack_1); });
CantMoveCauses.Add(() => { return animController.IsPlaying(_Basic_Attack_2); });
CantMoveCauses.Add(() => { return animController.IsPlaying(_Kick); });
CantMoveCauses.Add(() => { return animController.IsPlaying(_RoundHouseKick); });
CantMoveCauses.Add(() => { return animController.IsPlaying(_Smack); });
CantMoveCauses.Add(() => { return animController.IsPlaying(_Throw); });
CantMoveCauses.Add(() => { return animController.IsPlaying(_Thrust); });
CantMoveCauses.Add(() => { return animController.IsPlaying(_Hurt); });
CantMoveCauses.Add(() => { return animController.IsPlaying(_Fall); });
CantMoveCauses.Add(() => { return animController.IsPlaying(_Dead); });
IsAttackingCauses.Add(() => { return animController.IsPlaying(_Basic_Attack_1); });
IsAttackingCauses.Add(() => { return animController.IsPlaying(_Basic_Attack_2); });
IsAttackingCauses.Add(() => { return animController.IsPlaying(_Kick); });
IsAttackingCauses.Add(() => { return animController.IsPlaying(_RoundHouseKick); });
IsAttackingCauses.Add(() => { return animController.IsPlaying(_Smack); });
IsAttackingCauses.Add(() => { return animController.IsPlaying(_Throw); });
IsAttackingCauses.Add(() => { return animController.IsPlaying(_Thrust); });
IsAttackingCauses.Add(() => { return animController.IsPlaying(_DashAttack); });
IsMovingOrIdleCauses.Add(() => { return animController.IsPlaying(_Idle); });
IsMovingOrIdleCauses.Add(() => { return animController.IsPlaying(_Run); });
IsMovingOrIdleCauses.Add(() => { return animController.IsPlaying(_Walk); });
}
private void CharHealth_DiedEvent(object sender, CharHealth.DiedArgs e)
{
throw new System.NotImplementedException();
}
private void Start()
{
if (ReferenceCamera == null || ReferenceTransform == null)
{
ReferenceCamera = Camera.main;
ReferenceTransform = Instance.transform;
}
controls = ControlFreak.Controls;
controls.Player.Sprint.started += Sprint_started;
controls.Player.Sprint.canceled += Sprint_canceled;
controls.Player.Movement.started += Movement_started;
controls.Player.Movement.canceled += Movement_canceled;
controls.Player.BasicAttack.performed += BasicAttack_performed;
controls.Player.StrongAttack.performed += StrongAttack_performed;
controls.Player.KickAttack.performed += KickAttack_performed;
controls.Player.ThrowAttack.performed += ThrowAttack_performed;
}
protected new void Update()
{
base.Update();
UpdateAnimator();
}
private void CanOrCantCancelIntoMovement(AnimationEvent e)
{
if (e.stringParameter == "CanCancel")
{
CanCancelAttackIntoMovement = true;
}
if (e.stringParameter == "CantCancel")
{
CanCancelAttackIntoMovement = false;
}
}
protected override void ApplyMovementAndAttacks()
{
if (CanMove)
{
if (moveDirection != Vector2.zero || (LockInDirection && LockedDirection != Vector3.zero))
{
if (LockInDirection)
{
rb.velocity = LockedDirection * MovementSpeed * (IsSprinting ? SprintMultiplier : 1f);
SetFlipMode(FlipMode.Velocity);
}
else
{
rb.velocity = moveDirection * MovementSpeed * (IsSprinting ? SprintMultiplier : 1f);
SetFlipMode(FlipMode.MovementDirection);
}
}
else
{
rb.drag = 20f;
}
}
else
{
rb.drag = IsFalling ? 0f : 10f;
}
if (WantToCancelAttack && CanCancelAttackIntoMovement)
{
WantToCancelAttack = false;
MovementState(true);
}
if (InputState.BasicAttackPressed && !IsSprinting)
{
if (!animController.IsPlaying(_Basic_Attack_1) && !animController.IsPlaying(_Basic_Attack_2) && !IsAttacking)
{
PlayAnimation(Random.value > 0.5f ? _Basic_Attack_1 : _Basic_Attack_2);
InputState.MovementKeyWasCancelled = InputState.MovementKeyPressed || InputState.MovementKeyWasCancelled;
InputState.MovementKeyPressed = false;
LockFlipMode();
_EventReceiver.OnEvent.Set(animState, CanOrCantCancelIntoMovement);
CanCancelAttackIntoMovement = true;
animState.Events.OnEnd = ExitBasicAttack;
}
else if (animController.IsPlaying(_Basic_Attack_1))
{
InputState.MovementKeyWasCancelled = InputState.MovementKeyPressed || InputState.MovementKeyWasCancelled;
InputState.MovementKeyPressed = false;
animState.Events.OnEnd = () =>
{
PlayAnimation(_Basic_Attack_2);
LockFlipMode();
InputState.MovementKeyWasCancelled = InputState.MovementKeyPressed || InputState.MovementKeyWasCancelled;
InputState.MovementKeyPressed = false;
CanCancelAttackIntoMovement = true;
_EventReceiver.OnEvent.Set(animState, CanOrCantCancelIntoMovement);
animState.Events.OnEnd = ExitBasicAttack;
};
}
else if (animController.IsPlaying(_Basic_Attack_2))
{
InputState.MovementKeyWasCancelled = InputState.MovementKeyPressed || InputState.MovementKeyWasCancelled;
InputState.MovementKeyPressed = false;
animState.Events.OnEnd = () =>
{
PlayAnimation(_Basic_Attack_1);
LockFlipMode();
InputState.MovementKeyWasCancelled = InputState.MovementKeyPressed || InputState.MovementKeyWasCancelled;
InputState.MovementKeyPressed = false;
CanCancelAttackIntoMovement = true;
_EventReceiver.OnEvent.Set(animState, CanOrCantCancelIntoMovement);
animState.Events.OnEnd = ExitBasicAttack;
};
}
else if (IsAttacking)
{
animState.Events.OnEnd = () =>
{
ChainAttackAnimation(Random.value > 0.5f ? _Basic_Attack_1 : _Basic_Attack_2);
InputState.MovementKeyWasCancelled = InputState.MovementKeyPressed || InputState.MovementKeyWasCancelled;
InputState.MovementKeyPressed = false;
_EventReceiver.OnEvent.Set(animState, CanOrCantCancelIntoMovement);
CanCancelAttackIntoMovement = true;
animState.Events.OnEnd = ExitBasicAttack;
};
}
InputState.BasicAttackPressed = false;
return;
}
else if (InputState.BasicAttackPressed && IsSprinting && moveDirection != Vector2.zero)
{
if (!animController.IsPlaying(_DashAttack) && !IsAttacking)
{
PlayAnimation(_DashAttack);
InputState.MovementKeyWasCancelled = InputState.MovementKeyPressed || InputState.MovementKeyWasCancelled;
InputState.MovementKeyPressed = false;
LockInDirection = true;
LockedDirection = InputState.MovementDirection;
SprintEnergy = MaxSprintEnergy;
_EventReceiver.OnEvent.Set(animState, CanOrCantCancelIntoMovement);
CanCancelAttackIntoMovement = false;
InterruptCurrentAnimationCallback = ExitDashAttack;
animState.Events.OnEnd = ExitDashAttack;
}
InputState.BasicAttackPressed = false;
return;
}
if (InputState.StrongAttackPressed)
{
if (!animController.IsPlaying(_Thrust) && !IsAttacking)
{
PlayAnimation(_Thrust);
InputState.MovementKeyWasCancelled = InputState.MovementKeyPressed || InputState.MovementKeyWasCancelled;
InputState.MovementKeyPressed = false;
_EventReceiver.OnEvent.Set(animState, CanOrCantCancelIntoMovement);
CanCancelAttackIntoMovement = false;
animState.Events.OnEnd = ExitBasicAttack;
}
else if (IsAttacking)
{
InputState.MovementKeyWasCancelled = InputState.MovementKeyPressed || InputState.MovementKeyWasCancelled;
InputState.MovementKeyPressed = false;
animState.Events.OnEnd = () =>
{
ChainAttackAnimation(_Thrust);
InputState.MovementKeyWasCancelled = InputState.MovementKeyPressed || InputState.MovementKeyWasCancelled;
InputState.MovementKeyPressed = false;
_EventReceiver.OnEvent.Set(animState, CanOrCantCancelIntoMovement);
animState.Events.OnEnd = ExitBasicAttack;
};
}
InputState.StrongAttackPressed = false;
return;
}
if (InputState.KickAttackPressed)
{
if (!animController.IsPlaying(_Kick) && !IsAttacking)
{
PlayAnimation(_Kick);
InputState.MovementKeyWasCancelled = InputState.MovementKeyPressed || InputState.MovementKeyWasCancelled;
InputState.MovementKeyPressed = false;
_EventReceiver.OnEvent.Set(animState, CanOrCantCancelIntoMovement);
CanCancelAttackIntoMovement = false;
animState.Events.OnEnd = ExitBasicAttack;
}
else if (IsAttacking)
{
InputState.MovementKeyWasCancelled = InputState.MovementKeyPressed || InputState.MovementKeyWasCancelled;
InputState.MovementKeyPressed = false;
animState.Events.OnEnd = () =>
{
ChainAttackAnimation(_Kick);
InputState.MovementKeyWasCancelled = InputState.MovementKeyPressed || InputState.MovementKeyWasCancelled;
InputState.MovementKeyPressed = false;
_EventReceiver.OnEvent.Set(animState, CanOrCantCancelIntoMovement);
animState.Events.OnEnd = ExitBasicAttack;
};
}
InputState.KickAttackPressed = false;
return;
}
if (InputState.ThrowAttackPressed)
{
if (!animController.IsPlaying(_Throw) && !IsAttacking)
{
PlayAnimation(_Throw);
LockFlipMode();
InputState.MovementKeyWasCancelled = InputState.MovementKeyPressed || InputState.MovementKeyWasCancelled;
InputState.MovementKeyPressed = false;
_EventReceiver.OnEvent.Set(animState, CanOrCantCancelIntoMovement);
CanCancelAttackIntoMovement = false;
CanCancelAttackIntoNewAttack = false;
ThrowAttack();
}
else if (IsAttacking)
{
InputState.MovementKeyWasCancelled = InputState.MovementKeyPressed || InputState.MovementKeyWasCancelled;
InputState.MovementKeyPressed = false;
animState.Events.OnEnd = () =>
{
PlayAnimation(_Throw, resetIfAlreadyPlaying: true);
LockFlipMode();
InputState.MovementKeyWasCancelled = InputState.MovementKeyPressed || InputState.MovementKeyWasCancelled;
InputState.MovementKeyPressed = false;
_EventReceiver.OnEvent.Set(animState, CanOrCantCancelIntoMovement);
CanCancelAttackIntoMovement = false;
CanCancelAttackIntoNewAttack = false;
ThrowAttack();
};
}
InputState.ThrowAttackPressed = false;
return;
}
}
private void ThrowAttack()
{
var throwTrigger = new Animancer.AnimancerEvent { normalizedTime = 0.5f };
throwTrigger.callback = () =>
{
var go = Instantiate(ProjectilePrefab, transform.position, Quaternion.identity);
var projectile = go.GetComponent<Projectile>();
var dmgBox = go.GetComponentInChildren<DamageBox>();
dmgBox.OwnerController = this;
dmgBox.OwnerHealth = CharHealth;
projectile.Velocity = new Vector2(transform.localScale.x, 0) * 4f;
};
animState.Events.Add(throwTrigger);
animState.Events.OnEnd = () =>
{
ExitBasicAttack();
};
}
private void ChainAttackAnimation(AnimationClip animation)
{
PlayAnimation(animation);
LockFlipMode();
}
private void ExitDashAttack()
{
if (InterruptCurrentAnimationCallback == ExitDashAttack)
{
InterruptCurrentAnimationCallback = null;
}
LockInDirection = false;
LockedDirection = Vector3.zero;
SprintEnergy = 0f; Debug.Log("On End");
UnlockFlipMode();
MovementState(true);
}
private void ExitBasicAttack()
{
UnlockFlipMode();
MovementState(true);
}
protected override void GetMovementAndAttacksInput()
{
InputState.MovementDirection = controls.Player.Movement.ReadValue<Vector2>();
moveDirection = Vector2.zero;
if (InputState.MovementKeyPressed && CanCancelAttackIntoMovement && WantToCancelAttack && IsAttacking)
{
MovementState();
}
if (InputState.MovementKeyPressed && !InputState.MovementKeyWasCancelled)
{
moveDirection = InputState.MovementDirection;
rb.drag = 0f;
}
if (IsSprinting && moveDirection.sqrMagnitude > 0.1f)
{
SprintEnergy -= Time.deltaTime;
if (SprintEnergy <= 0)
{
IsSprinting = false;
}
}
else
{
if (SprintEnergy < MaxSprintEnergy)
{
SprintEnergy += Time.deltaTime / 2f;
}
}
}
protected new void UpdateAnimator()
{
base.UpdateAnimator();
if (CanMove && !IsAttacking)
{
MovementState();
}
}
private void MovementState(bool FinishedAttack = false)
{
CanCancelAttackIntoMovement = true;
if (InputState.MovementKeyWasCancelled)
{
InputState.MovementKeyPressed = true;
InputState.MovementKeyWasCancelled = false;
}
if ((!IsAttacking || FinishedAttack) && CharHealth.IsAlive)
{
WantToCancelAttack = false;
if (moveDirection.magnitude < 0.1f)
{
PlayAnimation(_Idle);
}
else
{
if (IsSprinting)
{
PlayAnimation(_Run);
_EventReceiver.OnEvent.Set(animState, FootstepSounds);
}
else
{
PlayAnimation(_Walk);
_EventReceiver.OnEvent.Set(animState, FootstepSounds);
}
}
}
}
private void FootstepSounds(AnimationEvent e)
{
if (e.stringParameter == "Step")
{
GetComponent<AudioSource>().PlayOneShot(Common.FootstepSounds.Random());
}
}
protected override void MyHealth_TookDamageEvent(object sender, CharHealth.TookDamageArgs e)
{
if (!animController.IsPlaying(_Hurt) && CharHealth.IsAlive)
{
if (animController.IsPlaying(_DashAttack))
{
ExitDashAttack();
}
var state = PlayAnimation(_Hurt);
Debug.Log(e.Message);
CanCancelAttackIntoMovement = false;
CanCancelAttackIntoNewAttack = false;
state.Events.OnEnd = () =>
{
AnimationPriorityLevel = 0;
MovementState(true);
};
}
}
protected override void MyHealth_DiedEvent(object sender, CharHealth.DiedArgs e)
{
controls.Disable();
Debug.Log(e.Message);
AnimationPriorityLevel = 10;
if (e.Fatality.DamageSource.GetType() != typeof(FallingDamage))
{
var state = PlayAnimation(_Fall);
state.Events.OnEnd = () =>
{
PlayAnimation(_Dead);
var feet = transform.root.GetComponent<CircleCollider2D>();
feet.enabled = false;
CharHealth.TookDamageEvent -= MyHealth_TookDamageEvent;
CharHealth.DiedEvent -= MyHealth_DiedEvent;
Destroy(CharHealth);
ZDepthOffset = -10;
};
}
else
{
PlayAnimation(_Fall, 0f, true);
Debug.Log(rb.velocity);
StartCoroutine(SwitchFallAnimationOnNegativeYVelocity());
}
}
private IEnumerator SwitchFallAnimationOnNegativeYVelocity()
{
Transform spriteChild = transform.GetChild(0);
spriteChild.localPosition -= new Vector3(0, 0.167f, 0);
transform.position += new Vector3(0, 0.167f, 0);
Debug.Log("falling coroutine");
rb.constraints = new RigidbodyConstraints2D { };
rb.angularVelocity = Mathf.Sign(rb.velocity.x) * (Random.value + 0.5f) * 200f;
yield return new WaitForFixedUpdate();
yield return new WaitForFixedUpdate();
yield return new WaitForFixedUpdate();
while (rb.velocity.y > 0)
{
Debug.Log(rb.velocity.y.ToString("00.0000"));
yield return new WaitForFixedUpdate();
}
var state = PlayAnimation(_Fall, 0f, true);
state.NormalizedTime = 1f;
}
private void Sprint_started(UnityEngine.InputSystem.InputAction.CallbackContext obj)
{
InputState.SprintPressed = true;
IsSprinting = true;
}
private void Sprint_canceled(UnityEngine.InputSystem.InputAction.CallbackContext obj)
{
InputState.SprintPressed = false;
IsSprinting = false;
}
private void Movement_started(UnityEngine.InputSystem.InputAction.CallbackContext obj)
{
InputState.MovementKeyPressed = true;
InputState.MovementKeyWasCancelled = false;
if (IsAttacking)
{
WantToCancelAttack = true;
}
}
private void Movement_canceled(UnityEngine.InputSystem.InputAction.CallbackContext obj)
{
InputState.MovementKeyPressed = false;
InputState.MovementKeyWasCancelled = false;
WantToCancelAttack = false;
}
private void BasicAttack_performed(UnityEngine.InputSystem.InputAction.CallbackContext obj)
{
InputState.BasicAttackPressed = true;
}
private void StrongAttack_performed(UnityEngine.InputSystem.InputAction.CallbackContext obj)
{
InputState.StrongAttackPressed = true;
}
private void KickAttack_performed(UnityEngine.InputSystem.InputAction.CallbackContext obj)
{
InputState.KickAttackPressed = true;
}
private void ThrowAttack_performed(UnityEngine.InputSystem.InputAction.CallbackContext obj)
{
InputState.ThrowAttackPressed = true;
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment