diff options
| author | Sarah B <git@sarahduck.ca> | 2023-12-24 22:42:28 -0800 |
|---|---|---|
| committer | Sarah B <git@sarahduck.ca> | 2023-12-24 22:42:28 -0800 |
| commit | 0bd51a156b56f661c794782e77c67d616d39f333 (patch) | |
| tree | 2d80fa6d74e58452739f8e308c684b2fd8be537a | |
| parent | a4874e186e24ce1736bfbda1deb0227597d2d690 (diff) | |
Moved current behavior into seperate AI states
also added new behavior
| -rw-r--r-- | OnekoLocal.cs | 118 |
1 files changed, 98 insertions, 20 deletions
diff --git a/OnekoLocal.cs b/OnekoLocal.cs index 249c5d1..d8c40f3 100644 --- a/OnekoLocal.cs +++ b/OnekoLocal.cs @@ -11,10 +11,8 @@ class OnekoLocal : Oneko static int Id => OnekoOnline.Client?.Id ?? -1; - OnekoAIState? CurrentAIState; - - Vector2 TargetPosition = Vector2.Zero; - float InactivityTimer = 0f; + OnekoAIState CurrentAIState; + readonly OnekoAIState[] AIStates; OnekoAnimation Animation; float updateTimer = 0f; @@ -29,6 +27,9 @@ class OnekoLocal : Oneko Client.UserConnected += OnekoNet.SpawnNetNeko; Name = OnekoOnline.Config.GetValue("NekoName", "Oneko"); + + AIStates = [new BoredState(this), new ChaseMouseState(this), new ItchyState(this)]; + CurrentAIState = AIStates[0]; } public override void Update(float delta) @@ -42,23 +43,14 @@ class OnekoLocal : Oneko public void OnekoUpdate(float delta) { - InactivityTimer += delta; - - Mouse? NearestMouse = Mouse.AllMice.Where(m => m.Visible).MinBy(m => Vector2.Distance(m.Position, Position)); - if (NearestMouse != null) TargetPosition = NearestMouse.Position; - else TargetPosition = new Vector2(Math.Clamp((Id+1)*40, 20, 300), 240/2); - - Vector2 TargetDirection = (TargetPosition-Position).LimitLength(10f); - if (TargetDirection.Length() > 1) { - Animation = GetDirectionalRun(TargetDirection); - InactivityTimer = 0f; + //AI STUFF + OnekoAIState HighestPriority = AIStates.MaxBy(state => state.GetPriority())!; + if (HighestPriority != CurrentAIState) { + CurrentAIState.ExitState(); + CurrentAIState = HighestPriority; + CurrentAIState.StartState(); } - else Animation = Idle; - Position += TargetDirection; - - if (InactivityTimer > 3f) Animation = ScratchSelf; - if (InactivityTimer > 5f) Animation = Yawn; - if (InactivityTimer > 6f) Animation = Sleep; + CurrentAIState.Update(delta); FrameCounter = (FrameCounter+1)%(Animation.AnimSpeed+1); Frame = (int)MathF.Round(FrameCounter/(float)Animation.AnimSpeed); @@ -74,12 +66,98 @@ class OnekoLocal : Oneko } } + void MoveTowardsPosition(Vector2 TargetPosition) + { + Vector2 TargetDirection = (TargetPosition-Position).LimitLength(10f); + if (TargetDirection.Length() > 1) { + Animation = GetDirectionalRun(TargetDirection); + } + + Position += TargetDirection; + } + protected abstract class OnekoAIState(OnekoLocal neko) { protected OnekoLocal Neko = neko; public abstract int GetPriority(); public abstract void Update(float delta); + public virtual void StartState() {} + public virtual void ExitState() {} protected bool IsCurrentState => Neko.CurrentAIState == this; } + + class BoredState(OnekoLocal neko) : OnekoAIState(neko) + { + float InactivityTimer = 0f; + + public override int GetPriority() => 0; + + public override void Update(float delta) + { + InactivityTimer += delta; + + Neko.Animation = Idle; + if (InactivityTimer > 3f) Neko.Animation = ScratchSelf; + if (InactivityTimer > 5f) Neko.Animation = Yawn; + if (InactivityTimer > 6f) Neko.Animation = Sleep; + } + + public override void ExitState() => InactivityTimer = 0f; + } + + class ChaseMouseState : OnekoAIState + { + Mouse? MouseToChase; + float AlertTimer = 0f; + + public ChaseMouseState(OnekoLocal neko) : base(neko) + { + Mouse.Clicked += mouse => { + if (Random.Shared.NextSingle() > 0.4f) MouseToChase = mouse; + }; + } + + public override int GetPriority() + { + MouseToChase ??= Mouse.AllMice.Where(m => m.Visible).MinBy(m => Vector2.Distance(m.Position, Neko.Position)); + if (MouseToChase != null && MouseToChase.Visible && Vector2.Distance(MouseToChase.Position, Neko.Position) > 15) return 100; + return -1; + } + + public override void Update(float delta) + { + if (AlertTimer < 1f) { + AlertTimer += delta; + Neko.Animation = Alert; + return; + } + + if (MouseToChase is null || !MouseToChase.Visible) return; + Neko.MoveTowardsPosition(MouseToChase.Position); + } + + public override void ExitState() { + MouseToChase = null; + AlertTimer = 0f; + } + } + + class ItchyState(OnekoLocal neko) : OnekoAIState(neko) + { + float ItchTimer = -1f; + + public override int GetPriority() + { + if (ItchTimer > 0f || Random.Shared.NextSingle() > 0.997f) return 1000; + else return -1; + } + + public override void StartState() => ItchTimer = 0.6f + Random.Shared.NextSingle()*3f; + + public override void Update(float delta) { + ItchTimer -= delta; + Neko.Animation = ScratchSelf; + } + } }
\ No newline at end of file |
