mirror of
				https://github.com/MaddyThorson/StrawberryBF.git
				synced 2025-11-04 01:41:33 +08:00 
			
		
		
		
	StateMachine Component
This commit is contained in:
		
							
								
								
									
										137
									
								
								src/Components/Logic/StateMachine.bf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										137
									
								
								src/Components/Logic/StateMachine.bf
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,137 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	public class StateMachine<TIndex> : Component where TIndex : struct, IHashable
 | 
			
		||||
	{
 | 
			
		||||
		private Dictionary<TIndex, State> states = new Dictionary<TIndex, State>() ~ delete _;
 | 
			
		||||
		private TIndex state;
 | 
			
		||||
		private bool inStateCall;
 | 
			
		||||
 | 
			
		||||
		public TIndex PreviousState { get; private set; }
 | 
			
		||||
		public TIndex NextState { get; private set; }
 | 
			
		||||
 | 
			
		||||
		public this(TIndex startState)
 | 
			
		||||
			: base(true, false)
 | 
			
		||||
		{
 | 
			
		||||
			NextState = PreviousState = state = startState;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public ~this()
 | 
			
		||||
		{
 | 
			
		||||
			for (let s in states.Values)
 | 
			
		||||
				 delete s;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Started()
 | 
			
		||||
		{
 | 
			
		||||
			CallEnter();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Update()
 | 
			
		||||
		{
 | 
			
		||||
			CallUpdate();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Draw()
 | 
			
		||||
		{
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Add(TIndex state, delegate TIndex() enter = null, delegate TIndex() update = null, delegate TIndex() exit = null)
 | 
			
		||||
		{
 | 
			
		||||
			let s = new State();
 | 
			
		||||
			s.Enter = enter;
 | 
			
		||||
			s.Update = update;
 | 
			
		||||
			s.Exit = exit;
 | 
			
		||||
			states[state] = s;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public TIndex State
 | 
			
		||||
		{
 | 
			
		||||
			get => state;
 | 
			
		||||
			set => Set(value);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private Result<bool> Set(TIndex to)
 | 
			
		||||
		{
 | 
			
		||||
			if (inStateCall)
 | 
			
		||||
				Runtime.FatalError("Cannot set State directly from inside a State Enter/Exit/Update call. Return the desired State change instead.");
 | 
			
		||||
 | 
			
		||||
			if (to != state)
 | 
			
		||||
			{
 | 
			
		||||
				NextState = to;
 | 
			
		||||
				if (CallExit())
 | 
			
		||||
					return true;
 | 
			
		||||
 | 
			
		||||
				PreviousState = state;
 | 
			
		||||
				state = to;
 | 
			
		||||
 | 
			
		||||
				CallEnter();
 | 
			
		||||
				return true;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
				return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private bool CallEnter()
 | 
			
		||||
		{
 | 
			
		||||
			let s = states[state];
 | 
			
		||||
			if (s != null)
 | 
			
		||||
			{
 | 
			
		||||
				inStateCall = true;
 | 
			
		||||
				let set = s.Enter();
 | 
			
		||||
				inStateCall = false;
 | 
			
		||||
				return Set(set);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
				return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private bool CallUpdate()
 | 
			
		||||
		{
 | 
			
		||||
			let s = states[state];
 | 
			
		||||
			if (s != null)
 | 
			
		||||
			{
 | 
			
		||||
				inStateCall = true;
 | 
			
		||||
				let set = s.Update();
 | 
			
		||||
				inStateCall = false;
 | 
			
		||||
				return Set(set);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
				return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private bool CallExit()
 | 
			
		||||
		{
 | 
			
		||||
			let s = states[state];
 | 
			
		||||
			if (s != null)
 | 
			
		||||
			{
 | 
			
		||||
				inStateCall = true;
 | 
			
		||||
				let set = s.Exit();
 | 
			
		||||
				inStateCall = false;
 | 
			
		||||
				return Set(set);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
				return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public class State
 | 
			
		||||
		{
 | 
			
		||||
			public delegate TIndex() Enter;
 | 
			
		||||
			public delegate TIndex() Update;
 | 
			
		||||
			public delegate TIndex() Exit;
 | 
			
		||||
 | 
			
		||||
			public ~this()
 | 
			
		||||
			{
 | 
			
		||||
				if (Enter != null)
 | 
			
		||||
					delete Enter;
 | 
			
		||||
				if (Update != null)
 | 
			
		||||
					delete Update;
 | 
			
		||||
				if (Exit != null)
 | 
			
		||||
					delete Exit;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -24,6 +24,33 @@ namespace Strawberry
 | 
			
		||||
			RemoveOnComplete = destroyOnComplete;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Started()
 | 
			
		||||
		{
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Update()
 | 
			
		||||
		{
 | 
			
		||||
			if (value > 0)
 | 
			
		||||
			{
 | 
			
		||||
				value -= Time.Delta;
 | 
			
		||||
				if (value <= 0)
 | 
			
		||||
				{
 | 
			
		||||
					value = 0;
 | 
			
		||||
					Active = false;
 | 
			
		||||
 | 
			
		||||
					OnComplete?.Invoke();
 | 
			
		||||
					if (RemoveOnComplete)
 | 
			
		||||
						RemoveSelf();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Draw()
 | 
			
		||||
		{
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public float Value
 | 
			
		||||
		{
 | 
			
		||||
			[Inline]
 | 
			
		||||
@ -47,23 +74,6 @@ namespace Strawberry
 | 
			
		||||
			Active = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Update()
 | 
			
		||||
		{
 | 
			
		||||
			if (value > 0)
 | 
			
		||||
			{
 | 
			
		||||
				value -= Time.Delta;
 | 
			
		||||
				if (value <= 0)
 | 
			
		||||
				{
 | 
			
		||||
					value = 0;
 | 
			
		||||
					Active = false;
 | 
			
		||||
 | 
			
		||||
					OnComplete?.Invoke();
 | 
			
		||||
					if (RemoveOnComplete)
 | 
			
		||||
						RemoveSelf();
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		static public implicit operator bool(Timer timer)
 | 
			
		||||
		{
 | 
			
		||||
			return timer.value > 0;
 | 
			
		||||
@ -15,30 +15,19 @@ namespace Strawberry
 | 
			
		||||
			Visible = visible;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void	Added(Entity entity)
 | 
			
		||||
		private void Added(Entity entity)
 | 
			
		||||
		{
 | 
			
		||||
			Entity = entity;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Removed()
 | 
			
		||||
		private void Removed()
 | 
			
		||||
		{
 | 
			
		||||
			Entity = null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public virtual void Started()
 | 
			
		||||
		{
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public virtual void Update()
 | 
			
		||||
		{
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public virtual void Draw()
 | 
			
		||||
		{
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
		public abstract void Started();
 | 
			
		||||
		public abstract void Update();
 | 
			
		||||
		public abstract void Draw();
 | 
			
		||||
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public void RemoveSelf()
 | 
			
		||||
 | 
			
		||||
@ -89,7 +89,7 @@ namespace Strawberry
 | 
			
		||||
				{
 | 
			
		||||
					components.Remove(c);
 | 
			
		||||
					Scene.[Friend]UntrackComponent(c);
 | 
			
		||||
					c.Removed();
 | 
			
		||||
					c.[Friend]Removed();
 | 
			
		||||
					delete c;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
@ -102,7 +102,7 @@ namespace Strawberry
 | 
			
		||||
				{
 | 
			
		||||
					components.Add(c);
 | 
			
		||||
					Scene.[Friend]TrackComponent(c);
 | 
			
		||||
					c.Added(this);
 | 
			
		||||
					c.[Friend]Added(this);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				toAdd.Clear();
 | 
			
		||||
 | 
			
		||||
@ -39,7 +39,6 @@ namespace Strawberry
 | 
			
		||||
		public override void Update()
 | 
			
		||||
		{
 | 
			
		||||
			base.Update();
 | 
			
		||||
 | 
			
		||||
			MovedByGeometry = Point.Zero;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
		Reference in New Issue
	
	Block a user