#nullable enable using UnityEngine; public class Monster : AIEntity { [HideInInspector] public bool thrownFromSafeZone; [HideInInspector] public Vector3 thrownTargetPosition; // Start is called before the first frame update override protected void Start() { base.Start(); base.entityType = EntityFlag.Monster; base.enemies = EntityFlag.Gladiator; } protected override BaseState CreateInitialState() => thrownFromSafeZone ? (BaseStateAI)new NonPhysicThrownState(this, thrownTargetPosition) : new ThrownState(this); protected override bool IsTargetable(Entity other) => other.IsAlive() && other is Gladiator; //Basically a copy of JumpingMovementState protected 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; } } protected class ThrownState : BaseStateAI { public ThrownState(AIEntity entity) : base(entity) {} public override void EnterState() { base.EnterState(); entity.rb.velocity = entity.direction * entity.AIStats.throwForce; } public override BaseState? FixedUpdateState() { return entity.rb.velocity.magnitude < entity.AIStats.MinVelocityWhenThrown ? new FindTargetState(entity) : null; } } }