306 lines
9.2 KiB
C#
306 lines
9.2 KiB
C#
using System;
|
|
using System.Collections;
|
|
using System.Data;
|
|
using System.Linq;
|
|
using System.Security.Cryptography.X509Certificates;
|
|
using UnityEditor;
|
|
using UnityEngine;
|
|
using UnityEngine.EventSystems;
|
|
using UnityEngine.UI;
|
|
using static UnityEditor.PlayerSettings;
|
|
using static UnityEngine.EventSystems.EventTrigger;
|
|
|
|
[SelectionBase]
|
|
public class Player : MonoBehaviour {
|
|
public static Player Instance { get; private set; }
|
|
|
|
[Header("Asset/Prefab")]
|
|
[SerializeField] public BuilderManager Builder;
|
|
|
|
[Header("References")]
|
|
[SerializeField] public Rigidbody2D Rigidbody;
|
|
[SerializeField] public Animator Animator;
|
|
[SerializeField] public SpriteRenderer Renderer;
|
|
[SerializeField] public Material MaterialColorOverlay;
|
|
|
|
[Header("Character Class")]
|
|
[SerializeField] private ParticleSystem Aura;
|
|
[SerializeField] private GameObject[] ClassIndicators;
|
|
private ClassBase ActiveClass;
|
|
[SerializeField] private MeleeFighterClass FighterClass;
|
|
public MeleeFighterAttackAnimator 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;
|
|
[SerializeField] private GameObject VfxAirJump;
|
|
[HideInInspector] public GameObjectPool VfxAirJumpPool;
|
|
|
|
private BoxCollider2D[] BoxColliders;
|
|
public bool LockMovement;
|
|
|
|
[SerializeField] public PlayerCombatHandler Combat { get; private set; }
|
|
|
|
|
|
public Vector2 PrevDirection = Vector2.zero;
|
|
private Vector2 MoveDirection = Vector2.zero;
|
|
private Vector2 DashDirection = Vector2.zero;
|
|
|
|
public PlayerJumpHandler Jump;
|
|
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;
|
|
Jump = new PlayerJumpHandler(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);
|
|
VfxAirJumpPool = new GameObjectPool(VfxAirJump, 5, 5);
|
|
BoxColliders = GetComponentsInChildren<BoxCollider2D>();
|
|
StaminaSliderHud.maxValue = StaminaMax;
|
|
SetClass(1);
|
|
|
|
Combat = new PlayerCombatHandler();
|
|
}
|
|
|
|
|
|
public Action DoUpdate;
|
|
private void Update() {
|
|
KeyPressActions();
|
|
GatherInput();
|
|
UpdatePlayerStatus();
|
|
UpdateActiveClass();
|
|
DoUpdate?.Invoke();
|
|
}
|
|
|
|
private void GatherInput() {
|
|
if (LockMovement) return;
|
|
MoveDirection.x = Input.GetAxisRaw("Horizontal");
|
|
MoveDirection.y = Input.GetAxisRaw("Vertical");
|
|
MoveDirection = MoveDirection.NormalizedIso();
|
|
if (MoveDirection.x != 0 || MoveDirection.y != 0)
|
|
PrevDirection = MoveDirection;
|
|
}
|
|
|
|
private void KeyPressActions() {
|
|
if (Input.GetKeyDown(KeyCode.LeftShift) || Input.GetKeyDown(KeyCode.RightShift)) {
|
|
DoDash();
|
|
} else if (Input.GetKeyDown(KeyCode.Space)) {
|
|
Jump.Start();
|
|
} 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 (!Jump.IsNonBlocking) return;
|
|
if (LockMovement) return;
|
|
if (Stamina < 25) return;
|
|
Stamina -= 25;
|
|
CanDash = false;
|
|
IsDashing = true;
|
|
DashDirection = MoveDirection;
|
|
if (DashDirection == Vector2.zero) return;
|
|
DashSpeed = DashSpeedInitial;
|
|
if (Jump.Active) {
|
|
LockMovement = true;
|
|
DashSpeed /= 2;
|
|
}
|
|
}
|
|
|
|
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 UpdateActiveClass() {
|
|
if (ActiveClass == null) return;
|
|
ActiveClass.Tick();
|
|
|
|
if (ActiveClass.HitBoxDraw == null) return;
|
|
if (!ActiveClass.HitBoxDraw.Active) return;
|
|
Collider2D[] hits = Physics2D.OverlapCircleAll(ActiveClass.HitBoxDraw.Center, ActiveClass.HitBoxDraw.Radius);
|
|
foreach (var hit in hits) {
|
|
if (!hit.CompareTag("EnemyHurtBox")) continue;
|
|
|
|
GameObject parent = hit.transform.parent?.gameObject;
|
|
Vector2 knockbakDirection = ActiveClass.HitBoxDraw.Directional ? PrevDirection : parent.transform.position - transform.position;
|
|
EnemySpawnerData.EnemyMap[parent].Damage(ActiveClass.HitBoxDraw.Damage, knockbakDirection, ActiveClass.HitBoxDraw.Knockback);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
private void FixedUpdate() {
|
|
MovementUpdate();
|
|
UpdateAnimation();
|
|
}
|
|
|
|
private void MovementUpdate() {
|
|
if (Combat.TakingDamage) {
|
|
Combat.ApplyKnockback();
|
|
return;
|
|
}
|
|
|
|
var movement = (MoveDirection * MoveSpeed) / MoveSpeedDampener;
|
|
if (IsDashing) {
|
|
if (DashSpeed < (Jump.Active ? 0.4f : 0.2f)) {
|
|
DashSpeed = 0;
|
|
CanDash = true;
|
|
IsDashing = false;
|
|
LockMovement = false;
|
|
Jump.Unpause();
|
|
} else if (DashSpeed > (movement.magnitude * 2)) {
|
|
Jump.Pause();
|
|
movement = DashDirection * DashSpeed;
|
|
if (Jump.Active)
|
|
DashSpeed *= Mathf.Exp(-DashDecayRate * Time.deltaTime / 3);
|
|
else
|
|
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 == "") return;
|
|
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 (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 (SkillInUse) return ActiveClass.AnimationToPlay;
|
|
if (!Jump.Active && input.sqrMagnitude < 0.01f) return "Idle";
|
|
if (Jump.Active) return "Jump2";
|
|
return "Run";
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
public static Action GizmoTick;
|
|
void OnDrawGizmos() {
|
|
DrawPlayerDirection();
|
|
GizmoTick?.Invoke();
|
|
}
|
|
|
|
public static void DrawWireSphere(Color color, Vector3 center, float radius) {
|
|
Gizmos.color = color;
|
|
Gizmos.DrawWireSphere(center, radius);
|
|
}
|
|
|
|
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);
|
|
}
|
|
}
|