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
This commit is contained in:
parent
0107e33438
commit
4fe5fb18e8
@ -184,8 +184,7 @@ GameObject:
|
||||
m_Component:
|
||||
- component: {fileID: 8417872790204748578}
|
||||
- component: {fileID: 5305176699257483480}
|
||||
- component: {fileID: 1850048545141446338}
|
||||
m_Layer: 7
|
||||
m_Layer: 0
|
||||
m_Name: HitBox
|
||||
m_TagString: EnemyHitBox
|
||||
m_Icon: {fileID: 0}
|
||||
@ -244,33 +243,6 @@ CapsuleCollider2D:
|
||||
m_Offset: {x: 0, y: 0}
|
||||
m_Size: {x: 1, y: 2}
|
||||
m_Direction: 0
|
||||
--- !u!50 &1850048545141446338
|
||||
Rigidbody2D:
|
||||
serializedVersion: 5
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6288550889223568635}
|
||||
m_BodyType: 1
|
||||
m_Simulated: 1
|
||||
m_UseFullKinematicContacts: 0
|
||||
m_UseAutoMass: 0
|
||||
m_Mass: 1
|
||||
m_LinearDamping: 0
|
||||
m_AngularDamping: 0.05
|
||||
m_GravityScale: 1
|
||||
m_Material: {fileID: 0}
|
||||
m_IncludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_ExcludeLayers:
|
||||
serializedVersion: 2
|
||||
m_Bits: 0
|
||||
m_Interpolate: 0
|
||||
m_SleepingMode: 1
|
||||
m_CollisionDetection: 0
|
||||
m_Constraints: 0
|
||||
--- !u!1 &6411951171763069002
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@ -280,7 +252,6 @@ GameObject:
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 243343966221896818}
|
||||
- component: {fileID: 4923938647755769837}
|
||||
- component: {fileID: 3140493390153182690}
|
||||
- component: {fileID: 9193586887117248369}
|
||||
m_Layer: 0
|
||||
@ -308,24 +279,6 @@ Transform:
|
||||
- {fileID: 8417872790204748578}
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!114 &4923938647755769837
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 6411951171763069002}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: a5c89455bac58d943a2e1e110d37a24d, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
WalkState: {fileID: 11400000, guid: 5cd5bb6e94e95cf4c961f0433390f59f, type: 2}
|
||||
ChaseState: {fileID: 11400000, guid: 71a5afe255167e14cad7bb413bdef532, type: 2}
|
||||
AttackState: {fileID: 11400000, guid: 0b9cc3e63ee0125479639c05b89977f8, type: 2}
|
||||
DamagedState: {fileID: 0}
|
||||
ChaseDistance: 7
|
||||
AttackDistance: 1
|
||||
--- !u!70 &3140493390153182690
|
||||
CapsuleCollider2D:
|
||||
m_ObjectHideFlags: 0
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@ -1,40 +0,0 @@
|
||||
using System;
|
||||
using Unity.IO.LowLevel.Unsafe;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AI.Base {
|
||||
abstract public class StateManager : MonoBehaviour {
|
||||
protected IState CurrentState;
|
||||
|
||||
virtual protected void Update() {
|
||||
CurrentState?.Tick();
|
||||
IState next = GetNextState();
|
||||
if (next != null && next != CurrentState) {
|
||||
CurrentState.Stop();
|
||||
CurrentState = next;
|
||||
CurrentState.Start();
|
||||
}
|
||||
}
|
||||
|
||||
abstract protected IState GetNextState();
|
||||
}
|
||||
|
||||
public class StateNode : ScriptableObject, IState {
|
||||
protected Transform Owner;
|
||||
|
||||
virtual public void Initialize(Transform ownerTransform) {
|
||||
Owner = ownerTransform;
|
||||
}
|
||||
|
||||
virtual public StateNode InitializeCopy(Transform ownerTransform) {
|
||||
Owner = ownerTransform;
|
||||
return ScriptableObject.CreateInstance(this.GetType()) as StateNode;
|
||||
}
|
||||
|
||||
virtual public void Start() {}
|
||||
virtual public void Stop() {}
|
||||
virtual public void Tick() {}
|
||||
|
||||
virtual public IState GetNextState() => this;
|
||||
}
|
||||
}
|
||||
25
Assets/Scripts/Runtime/AI/EnemyManager/EnemyStateManager.cs
Normal file
25
Assets/Scripts/Runtime/AI/EnemyManager/EnemyStateManager.cs
Normal file
@ -0,0 +1,25 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Unity.IO.LowLevel.Unsafe;
|
||||
using UnityEngine;
|
||||
|
||||
namespace AI.Base {
|
||||
public class EnemyStateManager : MonoBehaviour {
|
||||
public static EnemyStateManager Instance;
|
||||
public static List<GoblerStateManager> Goblers = new List<GoblerStateManager>();
|
||||
public static Action UpdateTick;
|
||||
public static Action GizmoTick;
|
||||
|
||||
public void Awake() {
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public void Update() {
|
||||
UpdateTick?.Invoke();
|
||||
}
|
||||
|
||||
public static void OnDrawGizmos() {
|
||||
GizmoTick?.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
179
Assets/Scripts/Runtime/AI/EnemyManager/GoblerStateManager.cs
Normal file
179
Assets/Scripts/Runtime/AI/EnemyManager/GoblerStateManager.cs
Normal file
@ -0,0 +1,179 @@
|
||||
using AI.Base;
|
||||
using NUnit.Framework.Internal.Execution;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Xml.Linq;
|
||||
using UnityEngine;
|
||||
|
||||
public class GoblerStateManager {
|
||||
[Header("Mechanics Attributes")]
|
||||
[SerializeField] public float ChaseDistance = 10f;
|
||||
[SerializeField] public float ChaseDistanceBuffer = 1f;
|
||||
[SerializeField] public float AttackDistance = 1f;
|
||||
[SerializeField] public float AttackMaskDiameter = 1f;
|
||||
|
||||
|
||||
[Header("Enemy Attributes")]
|
||||
[SerializeField] public float Attack = 10f;
|
||||
[SerializeField] public float Speed = 10f;
|
||||
[SerializeField] public float Health = 10f;
|
||||
[SerializeField] public float Energy = 10f;
|
||||
|
||||
|
||||
|
||||
private Player Player { get { return Player.Instance; } }
|
||||
private Transform PlayerTransform { get { return Player.transform; } }
|
||||
private Vector2 PlayerPos { get { return PlayerTransform.position; } }
|
||||
|
||||
private GameObject Owner;
|
||||
private Transform MyTransform { get { return Owner.transform; } }
|
||||
private Vector2 MyPos { get { return MyTransform.position; } set { MyTransform.position = value; } }
|
||||
|
||||
|
||||
public GoblerStateManager(GameObject owner) {
|
||||
Owner = owner;
|
||||
EnemySpawnerManager.UpdateTick += Update;
|
||||
EnemySpawnerManager.GizmoTick += OnDrawGizmos;
|
||||
}
|
||||
|
||||
public float DistFromPlayer { get; private set; }
|
||||
public float DistFromCrystal { get; private set; }
|
||||
|
||||
|
||||
public State CurrentState;
|
||||
public enum State {
|
||||
None,
|
||||
GoToCrystal,
|
||||
AttackCrystal,
|
||||
ChasePlayer,
|
||||
AttackPlayer,
|
||||
Damaged,
|
||||
Die
|
||||
}
|
||||
|
||||
|
||||
protected void SetPriorityState() {
|
||||
if (CurrentState == State.ChasePlayer) return;
|
||||
if (CurrentState == State.Damaged) return;
|
||||
if (CurrentState == State.Die) return;
|
||||
if (DistFromPlayer > ChaseDistance) return;
|
||||
SetState(State.ChasePlayer);
|
||||
}
|
||||
|
||||
private bool IsUpdating;
|
||||
protected void Update() {
|
||||
if (Owner == null) return;
|
||||
if (IsUpdating) return;
|
||||
IsUpdating = true;
|
||||
|
||||
DistFromPlayer = Vector2.Distance(MyPos, PlayerPos);
|
||||
SetPriorityState();
|
||||
|
||||
switch (CurrentState) {
|
||||
case State.None:
|
||||
break;
|
||||
|
||||
|
||||
case State.GoToCrystal:
|
||||
break;
|
||||
|
||||
|
||||
case State.AttackCrystal:
|
||||
break;
|
||||
|
||||
|
||||
case State.ChasePlayer:
|
||||
MyPos += (PlayerPos - MyPos).normalized * Speed * Time.deltaTime;
|
||||
|
||||
if (DistFromPlayer >= ChaseDistance + ChaseDistanceBuffer)
|
||||
SetState(State.AttackCrystal);
|
||||
else if (DistFromPlayer < 1)
|
||||
SetState(State.Die);
|
||||
break;
|
||||
|
||||
|
||||
case State.AttackPlayer:
|
||||
break;
|
||||
|
||||
case State.Damaged:
|
||||
break;
|
||||
|
||||
|
||||
case State.Die:
|
||||
EnemySpawnerManager.RemoveGobler(this);
|
||||
SetState(State.None);
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
|
||||
IsUpdating = false;
|
||||
}
|
||||
|
||||
|
||||
protected void SetState(State newState) {
|
||||
CurrentState = newState;
|
||||
switch (CurrentState) {
|
||||
case State.None:
|
||||
break;
|
||||
|
||||
|
||||
case State.GoToCrystal:
|
||||
break;
|
||||
|
||||
|
||||
case State.AttackCrystal:
|
||||
break;
|
||||
|
||||
|
||||
case State.ChasePlayer:
|
||||
break;
|
||||
|
||||
|
||||
case State.AttackPlayer:
|
||||
break;
|
||||
|
||||
|
||||
case State.Damaged:
|
||||
break;
|
||||
|
||||
|
||||
case State.Die:
|
||||
break;
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
protected void OnDrawGizmos() {
|
||||
if (Owner == null) return;
|
||||
|
||||
DrawChaseDistance();
|
||||
DrawAttackDistance();
|
||||
DrawAttackReach();
|
||||
}
|
||||
|
||||
private void DrawChaseDistance() {
|
||||
Gizmos.color = Color.green;
|
||||
Vector2 center = MyPos;
|
||||
Gizmos.DrawWireSphere(center, ChaseDistance);
|
||||
}
|
||||
|
||||
private void DrawAttackDistance() {
|
||||
//Gizmos.color = CurrentState == (IState)AttackState ? Color.red : Color.green;
|
||||
//Vector2 center = this.transform.position;
|
||||
//Gizmos.DrawWireSphere(center, AttackDistance);
|
||||
}
|
||||
|
||||
private void DrawAttackReach() {
|
||||
//if (CurrentState != (IState)AttackState) return;
|
||||
Gizmos.color = Color.red;
|
||||
|
||||
Vector2 direction2D = (PlayerPos - MyPos).normalized;
|
||||
Vector2 point2D = MyPos + direction2D * AttackDistance;
|
||||
Gizmos.DrawWireSphere(point2D, AttackMaskDiameter);
|
||||
}
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
using AI.Base;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
[CreateAssetMenu(menuName = "AI/Enemy/EnemyAttackState")]
|
||||
public class EnemyAttackState : StateNode {
|
||||
override public void Start() { Debug.Log("Entering Idle"); }
|
||||
override public void Tick() { }
|
||||
override public void Stop() { Debug.Log("Exiting Idle"); }
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8dc550eabcee2e84e94ae0bc898d72b4
|
||||
@ -1,33 +0,0 @@
|
||||
using AI.Base;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
[CreateAssetMenu(menuName = "AI/Enemy/EnemyChaseState")]
|
||||
public class EnemyChaseState : StateNode {
|
||||
public float Speed = 3f;
|
||||
|
||||
private Transform Player;
|
||||
|
||||
override public StateNode InitializeCopy(Transform ownerTransform) {
|
||||
var copy = ScriptableObject.CreateInstance(this.GetType()) as EnemyChaseState;
|
||||
copy.Owner = ownerTransform;
|
||||
copy.Speed = Speed;
|
||||
return copy;
|
||||
}
|
||||
|
||||
override public void Start() {
|
||||
Player = GameObject.FindGameObjectWithTag("Player").transform;
|
||||
Debug.Log("Entering Chase");
|
||||
}
|
||||
|
||||
override public void Tick() {
|
||||
if (Owner != null && Player != null) {
|
||||
Vector2 dir = (Player.position - Owner.position).normalized;
|
||||
Owner.position += (Vector3)dir * Speed * Time.deltaTime;
|
||||
}
|
||||
}
|
||||
|
||||
override public void Stop() {
|
||||
Debug.Log("Exiting Chase");
|
||||
}
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5f2962a1dddd6484e913c62893d7e512
|
||||
@ -1,10 +0,0 @@
|
||||
using AI.Base;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
[CreateAssetMenu(menuName = "AI/Enemy/EnemyDamagedState")]
|
||||
public class EnemyDamagedState : StateNode {
|
||||
override public void Start() { Debug.Log("Entering Idle"); }
|
||||
override public void Tick() { }
|
||||
override public void Stop() { Debug.Log("Exiting Idle"); }
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7457688d54e7e8342b034cc3b7fd589e
|
||||
@ -1,71 +0,0 @@
|
||||
using AI.Base;
|
||||
using UnityEngine;
|
||||
|
||||
public class EnemyStateManager : StateManager {
|
||||
[Header("States")]
|
||||
[SerializeField] public StateNode WalkState;
|
||||
[SerializeField] public StateNode ChaseState;
|
||||
[SerializeField] public StateNode AttackState;
|
||||
[SerializeField] public StateNode DamagedState;
|
||||
|
||||
[Header("Attributes")]
|
||||
[SerializeField] private float ChaseDistance = 10f;
|
||||
[SerializeField] private float AttackDistance = 1f;
|
||||
|
||||
private Transform Player;
|
||||
|
||||
|
||||
protected void Start() {
|
||||
Player = GameObject.FindGameObjectWithTag("Player")?.transform;
|
||||
WalkState = ScriptableObject.CreateInstance(WalkState.GetType()) as StateNode;
|
||||
|
||||
WalkState = WalkState.InitializeCopy(this.transform);
|
||||
ChaseState = ChaseState.InitializeCopy(this.transform);
|
||||
//DamagedState = DamagedState.InitializeCopy(this.transform);
|
||||
AttackState = AttackState.InitializeCopy(this.transform);
|
||||
|
||||
AttackState.Initialize(this.transform);
|
||||
|
||||
CurrentState = WalkState;
|
||||
CurrentState.Start();
|
||||
}
|
||||
|
||||
protected void InitializeStateNode(StateNode node){
|
||||
node = ScriptableObject.CreateInstance(node.GetType()) as StateNode;
|
||||
node.Initialize(this.transform);
|
||||
}
|
||||
|
||||
override protected IState GetNextState() {
|
||||
if (Player == null)
|
||||
return CurrentState;
|
||||
|
||||
float dist = Vector2.Distance(transform.position, Player.position);
|
||||
if (dist < AttackDistance)
|
||||
return AttackState.GetNextState();
|
||||
else if (dist < ChaseDistance)
|
||||
return ChaseState.GetNextState();
|
||||
else
|
||||
return WalkState.GetNextState();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private void OnDrawGizmos() {
|
||||
DrawChaseDistance();
|
||||
DrawAttackDistance();
|
||||
}
|
||||
private void DrawChaseDistance() {
|
||||
Gizmos.color = CurrentState == (IState)ChaseState ? Color.yellow : Color.green;
|
||||
Vector2 center = this.transform.position;
|
||||
Gizmos.DrawWireSphere(center, ChaseDistance);
|
||||
}
|
||||
private void DrawAttackDistance() {
|
||||
Gizmos.color = CurrentState == (IState)AttackState ? Color.red : Color.green;
|
||||
Vector2 center = this.transform.position;
|
||||
Gizmos.DrawWireSphere(center, AttackDistance);
|
||||
}
|
||||
}
|
||||
@ -1,12 +0,0 @@
|
||||
using AI.Base;
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
[CreateAssetMenu(menuName = "AI/Enemy/EnemyWalkState")]
|
||||
public class EnemyWalkState : StateNode {
|
||||
|
||||
override public void Start() { Debug.Log("Entering Idle"); }
|
||||
override public void Tick() { }
|
||||
override public void Stop() { Debug.Log("Exiting Idle"); }
|
||||
|
||||
}
|
||||
@ -1,2 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e82366a8b141d1c4587e07f13e902f29
|
||||
@ -8,6 +8,8 @@ using UnityEngine.UI;
|
||||
|
||||
[SelectionBase]
|
||||
public class Player : MonoBehaviour {
|
||||
public static Player Instance { get; private set; }
|
||||
|
||||
[Header("Asset/Prefab")]
|
||||
[SerializeField] public BuilderManager Builder;
|
||||
|
||||
@ -62,7 +64,7 @@ public class Player : MonoBehaviour {
|
||||
public float LastJumpTime { get; private set; }
|
||||
|
||||
public bool ActionAfterJumpReady {
|
||||
get {
|
||||
get {
|
||||
return (!IsJumping || (Time.time - LastJumpTime > 0.03f));
|
||||
}
|
||||
}
|
||||
@ -74,6 +76,7 @@ public class Player : MonoBehaviour {
|
||||
private enum Directions { Left, Right, Up, Down }
|
||||
|
||||
void Awake() {
|
||||
Instance = this;
|
||||
Builder = GetComponent<BuilderManager>();
|
||||
|
||||
VfxDashHandler = new VfxHandlerBase(VfxDash, 5, 5);
|
||||
|
||||
48
Assets/Scripts/Runtime/GameManagement/EnemySpawnerManager.cs
Normal file
48
Assets/Scripts/Runtime/GameManagement/EnemySpawnerManager.cs
Normal file
@ -0,0 +1,48 @@
|
||||
using AI.Base;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
public class EnemySpawnerManager : MonoBehaviour {
|
||||
public static EnemySpawnerManager Instance;
|
||||
[SerializeField] public GameObject GoblerPreFab;
|
||||
public static Dictionary<GoblerStateManager, GameObject> Goblers = new Dictionary<GoblerStateManager, GameObject>();
|
||||
public static Action UpdateTick;
|
||||
public static Action GizmoTick;
|
||||
public static int MaxGoblers = 1;
|
||||
|
||||
public class Gobler {
|
||||
public GameObject Object;
|
||||
public GoblerStateManager Manager;
|
||||
|
||||
public Gobler(GameObject obj, GoblerStateManager manager) {
|
||||
Object = obj;
|
||||
Manager = manager;
|
||||
}
|
||||
}
|
||||
|
||||
public void Awake() {
|
||||
Instance = this;
|
||||
}
|
||||
|
||||
public static void RemoveGobler(GoblerStateManager goblerManager){
|
||||
Destroy(Goblers[goblerManager]);
|
||||
Goblers.Remove(goblerManager);
|
||||
}
|
||||
|
||||
public void Update() {
|
||||
if (Goblers.Count() < MaxGoblers){
|
||||
var gobler = Instantiate(GoblerPreFab, this.transform.position, Quaternion.identity);
|
||||
Goblers.Add(new GoblerStateManager(gobler), gobler);
|
||||
}
|
||||
UpdateTick?.Invoke();
|
||||
}
|
||||
|
||||
public static void OnDrawGizmos() {
|
||||
GizmoTick?.Invoke();
|
||||
}
|
||||
}
|
||||
@ -1,23 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
public class SpawnManager : MonoBehaviour {
|
||||
public static bool IsPaused { get; private set; }
|
||||
[SerializeField] private GameObject pauseMenuUI;
|
||||
|
||||
void Update() {
|
||||
if (Input.GetKeyDown(KeyCode.Escape))
|
||||
TogglePause();
|
||||
}
|
||||
|
||||
public void TogglePause() {
|
||||
IsPaused = !IsPaused;
|
||||
Time.timeScale = IsPaused ? 0f : 1f;
|
||||
AudioListener.pause = IsPaused;
|
||||
pauseMenuUI.SetActive(IsPaused);
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user