TowerDefenseGame/Assets/Scripts/Runtime/Characters/Player/PlayerMainController.cs
Nico 4fe5fb18e8 Recreate enemy management
Remove separate states
Will contain all states in one type of enemy management script
Will use enemy manager to update states of each enemy and spawning
2025-07-09 09:54:28 -07:00

267 lines
7.9 KiB
C#

using System.Collections;
using System.Data;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;
[SelectionBase]
public class Player : MonoBehaviour {
public static Player Instance { get; private set; }
[Header("Asset/Prefab")]
[SerializeField] public BuilderManager Builder;
[Header("Movement")]
[SerializeField] private Rigidbody2D Rigidbody;
[SerializeField] public Animator Animator;
[SerializeField] private SpriteRenderer Renderer;
[Header("Character Class")]
[SerializeField] private ParticleSystem Aura;
[SerializeField] private GameObject[] ClassIndicators;
private ClassBase ActiveClass;
[SerializeField] private MeleeFighterClass FighterClass;
public AttackAnimatorFactory AttackAnimator;
[Header("Stamina")]
[SerializeField] public float StaminaMax = 100;
[SerializeField] public float Stamina = 0;
[SerializeField] public float StaminaRegenPerSecond = 5;
[SerializeField] public Slider StaminaSliderHud;
[Header("Movement Attributes")]
[SerializeField] public float MoveSpeed = 8;
[SerializeField] public float MoveSpeedDampener = 1;
[SerializeField] private float DashSpeedInitial = 200;
[SerializeField] private float DashSpeed = 0;
[SerializeField] private float DashDecayRate = 30;
[SerializeField] private float DashDelay1 = 0.05f;
[SerializeField] private float DashDelay2 = 0.05f;
[SerializeField] private float DashCooldown = 0.1f;
//[SerializeField] private float DriftSpeed = 60;
//[SerializeField] private float DriftFactorial = 0.85f;
[SerializeField] private float JumpDelay = 0.3f;
[Header("VFX")]
[SerializeField] private GameObject VfxDash;
private VfxHandlerBase VfxDashHandler;
[SerializeField] private GameObject VfxKineticSurge;
[HideInInspector] public VfxHandlerBase VfxKineticSurgeHandler;
[SerializeField] private GameObject VfxShockwave;
[HideInInspector] public GameObjectPool VfxShockwavePool;
private BoxCollider2D[] BoxColliders;
public Vector2 PrevDirection = Vector2.zero;
private Vector2 MoveDirection = Vector2.zero;
private Vector2 DashDirection = Vector2.zero;
public bool IsJumping { get; set; }
public float LastJumpTime { get; private set; }
public bool ActionAfterJumpReady {
get {
return (!IsJumping || (Time.time - LastJumpTime > 0.03f));
}
}
public bool IsDashing { get; private set; }
public float DashTime { get; private set; }
public bool CanDash { get; private set; } = true;
public bool SkillInUse = false;
private enum Directions { Left, Right, Up, Down }
void Awake() {
Instance = this;
Builder = GetComponent<BuilderManager>();
VfxDashHandler = new VfxHandlerBase(VfxDash, 5, 5);
VfxKineticSurgeHandler = new VfxHandlerBase(VfxKineticSurge, 5, 5);
FighterClass = new MeleeFighterClass(this);
VfxShockwavePool = new GameObjectPool(VfxShockwave, 5, 5);
BoxColliders = GetComponentsInChildren<BoxCollider2D>();
StaminaSliderHud.maxValue = StaminaMax;
SetClass(1);
}
private void Update() {
KeyPressActions();
GatherInput();
UpdatePlayerStatus();
ActiveClass.Tick();
}
private void GatherInput() {
MoveDirection.x = Input.GetAxisRaw("Horizontal");
MoveDirection.y = Input.GetAxisRaw("Vertical");
}
private void KeyPressActions() {
if (Input.GetKeyDown(KeyCode.LeftShift) || Input.GetKeyDown(KeyCode.RightShift)) {
DoDash();
} else if (!IsJumping && Input.GetKeyDown(KeyCode.Space)) {
Jump();
} else if (Input.GetKeyDown(KeyCode.F1)) {
SetClass(0);
} else if (Input.GetKeyDown(KeyCode.F2)) {
SetClass(1);
} else if (Input.GetKeyDown(KeyCode.F3)) {
SetClass(2);
} else if (Input.GetKeyDown(KeyCode.F4)) {
SetClass(3);
}
if (Input.GetKeyDown(KeyCode.X)) ActiveClass.HandlePrimaryAttack();
else if (Input.GetKeyDown(KeyCode.C)) ActiveClass.HandleSecondaryAttack();
}
private void DoDash() {
if (!CanDash) return;
if (!ActionAfterJumpReady) return;
if (Stamina < 25) return;
Stamina -= 25;
CanDash = false;
IsDashing = true;
DashDirection = MoveDirection.normalized;
if (DashDirection == Vector2.zero) return;
DashSpeed = DashSpeedInitial;
}
private void Jump() {
if (SkillInUse) return;
IsJumping = true;
LastJumpTime = Time.time;
foreach (var col in BoxColliders)
col.enabled = false;
if (CoroutineJumpReset != null)
StopCoroutine(CoroutineJumpReset);
CoroutineJumpReset = StartCoroutine(ResetJumpAfterDelay());
MoveSpeedDampener = 2;
}
public Coroutine CoroutineJumpReset { get; private set; }
private IEnumerator ResetJumpAfterDelay() {
yield return new WaitForSeconds(JumpDelay);
foreach (var col in BoxColliders)
col.enabled = true;
IsJumping = false;
MoveSpeedDampener = 1;
}
private void SetClass(int classIdx) {
Builder.SetBuildMode(classIdx == 3);
ActiveClass = FighterClass;
foreach (var (indicator, i) in ClassIndicators.Select((obj, i) => (obj, i)))
if (i != classIdx) {
indicator.transform.localScale = Vector3.one;
indicator.transform.rotation = Quaternion.identity;
} else {
indicator.transform.localScale = Vector3.one * 2;
indicator.transform.rotation = Quaternion.AngleAxis(90, Vector3.forward);
}
RawImage image = ClassIndicators[classIdx].GetComponent<RawImage>();
var main = Aura.main;
main.startColor = image.color;
}
private void UpdatePlayerStatus() {
if (Stamina == StaminaMax) return;
Stamina = Mathf.Min(Stamina + StaminaRegenPerSecond * Time.deltaTime, StaminaMax);
StaminaSliderHud.value = Stamina;
}
private void FixedUpdate() {
MovementUpdate();
UpdateAnimation();
}
private void MovementUpdate() {
var movement = (MoveDirection.normalized * MoveSpeed) / MoveSpeedDampener;
if (IsDashing) {
if (DashSpeed < 0.2f) {
DashSpeed = 0;
CanDash = true;
IsDashing = false;
} else if (DashSpeed > (movement.magnitude * 2)) {
if (IsJumping) Jump();
movement = DashDirection * DashSpeed;
DashSpeed *= Mathf.Exp(-DashDecayRate * Time.deltaTime);
} else {
movement = ((DashDirection * DashSpeed) + movement) / 2;
DashSpeed *= Mathf.Exp(-DashDecayRate * Time.deltaTime);
}
}
Rigidbody.linearVelocity = movement;
}
private void UpdateAnimation() {
string state = GetAnimationState(MoveDirection);
if (state.Last() == '_')
state = state.Replace("_", "");
else
state += LastDirection.ToString();
Animator.CrossFade(state, 0);
}
public enum Direction { Up, Down, Left, Right }
public Direction LastDirection = Direction.Down;
private string GetAnimationState(Vector2 input) {
if (SkillInUse) return ActiveClass.AnimationToPlay;
if (!IsJumping && input.sqrMagnitude < 0.01f) return "Idle";
if (Mathf.Abs(input.x) > 0)
LastDirection = (input.x > 0) ? Direction.Right : Direction.Left;
else if (Mathf.Abs(input.y) > 0)
LastDirection = (input.y > 0) ? Direction.Up : Direction.Down;
if (IsJumping) return "Jump";
return "Run";
}
void OnDrawGizmos() {
DrawPlayerDirection();
}
private void DrawPlayerDirection() {
if (Rigidbody == null) Rigidbody = GetComponent<Rigidbody2D>();
if (Rigidbody == null) return;
Gizmos.color = Color.cyan;
Vector3 start = Rigidbody.transform.position;
Vector3 end = start + (Vector3)(Rigidbody.linearVelocity * 1);
Gizmos.DrawLine(start, end);
DrawArrowHead(end, (end - start).normalized);
}
void DrawArrowHead(Vector3 position, Vector3 direction) {
float arrowHeadAngle = 20f;
float arrowHeadLength = 0.25f;
Vector3 right = Quaternion.Euler(0, 0, arrowHeadAngle) * -direction;
Vector3 left = Quaternion.Euler(0, 0, -arrowHeadAngle) * -direction;
Gizmos.DrawLine(position, position + right * arrowHeadLength);
Gizmos.DrawLine(position, position + left * arrowHeadLength);
}
}