#nullable enable using System.Collections; using System.Collections.Generic; using UnityEngine; using UnityEngine.Serialization; public class AIEntity : Entity { [FormerlySerializedAs("stats")] [SerializeField] AIStats AIStats = null!; public string? ennemyName {get; protected set; } abstract class BaseStateAI : BaseState{ protected AIEntity entity; public BaseStateAI(AIEntity entity){ this.entity = entity; } } /*//Basically a copy of JumpingMovementState class NonPhysicThrownState : BaseStateAI { readonly Vector3 target; Vector3 startPosition; float duration; float startTime; public NonPhysicThrownState(AIEntity entity, Vector3 target) : base(entity) { this.target = target; } public override void EnterState() { base.EnterState(); duration = entity.AIStats.ThrownDurationPerMeter * Vector3.Distance(entity.transform.position, target); startPosition = entity.transform.position; startTime = Time.time; entity.rb.SetEnabled(false); } public override void LeaveState() { base.LeaveState(); entity.rb.SetEnabled(true); } public override BaseState? FixedUpdateState() { float currentTime = Time.time - startTime; if (currentTime >= duration) return new FindTargetState(entity); entity.rb.MovePosition(Vector3.Lerp( startPosition, target, entity.AIStats.ThrownCurve.Evaluate(currentTime / duration) )); return null; } }*/ class ThrownState : BaseStateAI { public ThrownState(AIEntity entity) : base(entity) {} public override void EnterState() { base.EnterState(); entity.rb.SetEnabled(false); } public override void LeaveState() { base.LeaveState(); entity.rb.SetEnabled(true); } public override BaseState? FixedUpdateState() => entity.rb.velocity.magnitude < entity.stats.MinVelocityWhenThrown ? new FindTargetState(entity) : null; } class SeekState : BaseStateAI{ public SeekState(AIEntity entity) : base(entity){ } public override BaseState? UpdateState(){ Entity targetEntity = entity.GetTarget().GetComponent(); if(targetEntity != null){ if(targetEntity.IsAlive()){//target is alive, keep chasing it return null; }else{//target is dead, go to findTargetState return new FindTargetState(entity);; } } return null; } public override BaseState? FixedUpdateState(){ Transform target = entity.GetTarget(); entity.direction = Vector3.RotateTowards(entity.direction, (target.position - entity.transform.position), entity.rotSpeed*Time.fixedDeltaTime, 0.0f); if(!entity.IsInAttackRange()){ entity.rb.MovePosition(entity.transform.position + entity.direction * entity.movementSpeed * Time.fixedDeltaTime); }else{ return new AttackState(entity); } return null; } } class FindTargetState : BaseStateAI{ float closeEnough; public FindTargetState(AIEntity entity) : base(entity){ } public override BaseState? UpdateState(){ Entity[] entities = FindObjectsOfType(); float lastDist = -1; Entity chosenEntity = null!; foreach (Entity other in entities){// Find the closest entity if(other.name == entity.ennemyName){ float distance = Vector2.Distance(other.transform.position, entity.transform.position); if(distance < lastDist){ lastDist = distance; chosenEntity = other; if(lastDist <= entity.AIStats.closeEnough)break; } } } if(chosenEntity != null){ entity.SetTarget(chosenEntity.transform); } return new SeekState(entity); } } class AttackState : BaseStateAI{ public AttackState(AIEntity entity) : base(entity){ } public override BaseState? UpdateState(){ if(entity.IsInAttackRange()){ if(entity.attackTimer >= entity.attackCooldown){ entity.attackTimer = 0; return Attack(); }else{ entity.attackTimer += Time.deltaTime; } } return null; } private BaseState? Attack(){ Entity targetEntity = entity.GetTarget().GetComponent(); if(targetEntity != null){ targetEntity.TakeDamage(entity.attackDmg); bool isTargetAlive = targetEntity.IsAlive(); if(!isTargetAlive){ return new FindTargetState(entity); } } return null; } } }