StateMachine er baseret på denne video, se video og forsøg at implementere statemachine.
using Godot; using System; public partial class State : Node { public StateMachine fsm; public virtual void Ready() { } // ENTER state public virtual void Enter() { } // UPDATE state (Process) public virtual void Update(float delta) { } // EXIT state public virtual void Exit() { } public virtual void PhysicsUpdate(float delta) {} public virtual void HandleInput(InputEvent @event) { } }
using Godot; using System; using System.Collections.Generic; public abstract partial class StateMachine : Node { [Export] public CharacterBody2D npc; [Export] public NodePath initialState; // Start tilstand skal angives... private Dictionary<string, State> _states; // alle tilstande i denne datastruktur private State _currentState; // nuværende tilstand public override void _Ready() { if (npc == null) { GD.Print("You forgot to set NPC..export"); } if (initialState == null) { GD.Print("You forgot to set initialState..export"); } _states = new Dictionary<string, State>(); foreach (Node node in this.GetChildren()) { if (node is State s) { _states[node.Name] = s; s.fsm = this; s.Ready(); s.Exit(); } } _currentState = GetNode<State>(initialState); _currentState.Enter(); GD.Print("StateMachine is ready."); } // Der der skiftes tilstand public void TransitionTo(string stateName){ // sikkerheds tjeck at tilstand eksisterer, eller at den allerede er valgt if (!_states.ContainsKey(stateName) || _currentState == _states[stateName]) { return; } // Der skiftes tilstand _currentState.Exit(); // vi rydder op efter os ! _currentState = _states[stateName]; // Vi skifter til den nye tilstands _currentState.Enter(); // initialisering.. } public override void _Process(double delta) { _currentState.Update((float) delta); } public override void _PhysicsProcess(double delta) { _currentState.PhysicsUpdate((float)delta); } // Sender ikke håndterede events videre til nuværende tilstand (State) public override void _UnhandledInput(InputEvent @event) { _currentState.HandleInput(@event); } }
using Godot; using System; public partial class PatrolState : State { [Export] public float Speed = 40f; [Export] public float visibilityRange = 50f; [Export] public Node2D[] waypoints; // Waypoints som der patruljeres imellem. [Export] public CharacterBody2D player; public int currentWaypointIndex = 0; // Det nuværende waypoint public Vector2 targetPosition; public override void Ready() { targetPosition = waypoints[currentWaypointIndex].GlobalPosition; GD.Print("PatrolState ready."); } public override void Update(float delta) { fsm.npc.Velocity = fsm.npc.GlobalPosition.DirectionTo(targetPosition) * Speed; // Er vi nået til vores nuværende Waypoint? if( fsm.npc.GlobalPosition.DistanceTo( targetPosition ) < 1.5f ){ currentWaypointIndex++; if (currentWaypointIndex > waypoints.Length - 1) { currentWaypointIndex = 0; } targetPosition = waypoints[currentWaypointIndex].GlobalPosition; } // Er vi inde for visibility range af Player? if (fsm.npc.GlobalPosition.DistanceTo(player.GlobalPosition) < this.visibilityRange) { GD.Print("Skift til ChaseState"); fsm.TransitionTo("ChaseState"); } fsm.npc.MoveAndSlide(); } }
using Godot; using System; public partial class ChaseState : State { [Export] public float Speed = 40f; [Export] public Node2D player; public CharacterBody2D skeleton; public override void Ready() { if (player == null) { GD.Print("Du har glemt at lave en reference til Player."); } GD.Print("ChaseState ready."); } public override void PhysicsUpdate(float delta) { fsm.npc.Velocity = fsm.npc.GlobalPosition.DirectionTo(player.GlobalPosition) * this.Speed; if ( fsm.npc.GlobalPosition.DistanceTo( player.GlobalPosition ) > 50f ) { GD.Print("Skift til PatrolState"); fsm.TransitionTo("PatrolState"); } if (fsm.npc.GlobalPosition.DistanceTo(player.GlobalPosition) < 10f) { GD.Print("Skift til AttackState"); fsm.TransitionTo("AttackState"); } fsm.npc.MoveAndSlide(); } }