mirror of
				https://github.com/MaddyThorson/StrawberryBF.git
				synced 2025-11-03 01:31:32 +08:00 
			
		
		
		
	Big restructuring - sample game is currently broken
This commit is contained in:
		
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -2,3 +2,4 @@
 | 
			
		||||
SampleGame/build/*
 | 
			
		||||
SampleGame/BeefSpace_User.toml
 | 
			
		||||
build/*
 | 
			
		||||
SampleGame/recovery/*
 | 
			
		||||
 | 
			
		||||
@ -7,8 +7,8 @@ namespace Strawberry.Sample
 | 
			
		||||
		public this()
 | 
			
		||||
		{
 | 
			
		||||
			Add(new Player(.(50, 50)));
 | 
			
		||||
			Add(new Solid(.(0, 168), .(0, 0, 320, 12)));
 | 
			
		||||
			Add(new JumpThru(.(200, 132), 48));
 | 
			
		||||
			Add(new OldSolid(.(0, 168), .(0, 0, 320, 12)));
 | 
			
		||||
			Add(new OldJumpThru(.(200, 132), 48));
 | 
			
		||||
			Add(new MovingJumpThru(.(136, 100), 32, .(124, 140), 2f));
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -1,6 +1,6 @@
 | 
			
		||||
namespace Strawberry.Sample
 | 
			
		||||
{
 | 
			
		||||
	public class MovingJumpThru	: JumpThru
 | 
			
		||||
	public class MovingJumpThru	: OldJumpThru
 | 
			
		||||
	{
 | 
			
		||||
		private Point moveFrom;
 | 
			
		||||
		private Point moveTo;
 | 
			
		||||
 | 
			
		||||
@ -2,56 +2,49 @@ using System;
 | 
			
		||||
 | 
			
		||||
namespace Strawberry.Sample
 | 
			
		||||
{
 | 
			
		||||
	[Reflect]
 | 
			
		||||
	public class Actor : Entity
 | 
			
		||||
	public class Physics : Component, IHasHitbox, IUpdate
 | 
			
		||||
	{
 | 
			
		||||
		public Hitbox Hitbox { get; private set; }
 | 
			
		||||
		public Vector Speed;
 | 
			
		||||
 | 
			
		||||
		private Vector remainder;
 | 
			
		||||
 | 
			
		||||
		// The amount that geometry has pushed or carried this Actor since the last frame
 | 
			
		||||
		public Point MovedByGeometry { get; private set; }
 | 
			
		||||
 | 
			
		||||
		public this(Point position)
 | 
			
		||||
			: base(position)
 | 
			
		||||
		public this(Hitbox hitbox)
 | 
			
		||||
		{
 | 
			
		||||
 | 
			
		||||
			Hitbox = hitbox;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Level Level => SceneAs<Level>();
 | 
			
		||||
		public Level Level => Entity.SceneAs<Level>();
 | 
			
		||||
 | 
			
		||||
		public bool Check(Level level)
 | 
			
		||||
		{
 | 
			
		||||
			return level.SolidGrid != null && Check(level.SolidGrid);
 | 
			
		||||
			return level.SolidGrid != null && Hitbox.Check(level.SolidGrid);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check(Level level, Point offset)
 | 
			
		||||
		{
 | 
			
		||||
			return level.SolidGrid != null && Check(level.SolidGrid, offset);
 | 
			
		||||
			return level.SolidGrid != null && Hitbox.Check(level.SolidGrid, offset);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool GroundCheck(int distance = 1)
 | 
			
		||||
		{
 | 
			
		||||
			return Check<Solid>(.(0, distance)) || Check(Level, .(0, distance)) || CheckOutside<JumpThru>(.(0, distance));
 | 
			
		||||
			return Hitbox.Check<Solid>(.(0, distance)) || Check(Level, .(0, distance)) || Hitbox.CheckOutside<JumpThru>(.(0, distance));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public virtual bool IsRiding(Solid solid)
 | 
			
		||||
		{
 | 
			
		||||
			return Check(solid, .(0, 1));
 | 
			
		||||
			return Hitbox.Check(solid, .(0, 1));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public virtual bool IsRiding(JumpThru jumpThru)
 | 
			
		||||
		{
 | 
			
		||||
			return CheckOutside(jumpThru, .(0, 1));
 | 
			
		||||
			return Hitbox.CheckOutside(jumpThru, .(0, 1));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public virtual void Squish(Collision collision)
 | 
			
		||||
		public void Update()
 | 
			
		||||
		{
 | 
			
		||||
			RemoveSelf();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Update()
 | 
			
		||||
		{
 | 
			
		||||
			base.Update();
 | 
			
		||||
			MovedByGeometry = Point.Zero;
 | 
			
		||||
			MoveX(Speed.X * Time.Delta);
 | 
			
		||||
			MoveY(Speed.Y * Time.Delta);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool MoveX(float amount, delegate void(Collision) onCollide = null)
 | 
			
		||||
@ -83,130 +76,85 @@ namespace Strawberry.Sample
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public void MoveToX(float x)
 | 
			
		||||
		{
 | 
			
		||||
			MoveX(x - (X + remainder.X), null);
 | 
			
		||||
			MoveX(x - (Entity.X + remainder.X), null);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public void MoveToY(float y)
 | 
			
		||||
		{
 | 
			
		||||
			MoveY(y - (Y + remainder.Y), null);
 | 
			
		||||
			MoveY(y - (Entity.Y + remainder.Y), null);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool MoveExactX(int amount, delegate void(Collision) onCollide = null, Geometry pusher = null, Geometry carrier = null)
 | 
			
		||||
		public bool MoveExactX(int amount, delegate void(Collision) onCollide = null)
 | 
			
		||||
		{
 | 
			
		||||
			int move = amount;
 | 
			
		||||
			int sign = Math.Sign(amount);
 | 
			
		||||
			bool byGeometry = carrier != null || pusher != null;
 | 
			
		||||
 | 
			
		||||
			while (move != 0)
 | 
			
		||||
			{
 | 
			
		||||
				let hit = First<Solid>(.(sign, 0));
 | 
			
		||||
				if (hit != null)
 | 
			
		||||
				if (Check(Level, .(sign, 0)) || Hitbox.Check<Solid>(.(sign, 0)))
 | 
			
		||||
				{
 | 
			
		||||
					let c = Collision(
 | 
			
		||||
						Cardinals.FromPoint(Point.Right * sign),
 | 
			
		||||
						Math.Abs(amount),
 | 
			
		||||
						Math.Abs(amount - move),
 | 
			
		||||
						hit,
 | 
			
		||||
						pusher
 | 
			
		||||
						Math.Abs(amount - move)
 | 
			
		||||
					);
 | 
			
		||||
 | 
			
		||||
					onCollide?.Invoke(c);
 | 
			
		||||
					return true;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (Check(Level, .(sign, 0)))
 | 
			
		||||
				{
 | 
			
		||||
					let c = Collision(
 | 
			
		||||
						Cardinals.FromPoint(Point.Right * sign),
 | 
			
		||||
						Math.Abs(amount),
 | 
			
		||||
						Math.Abs(amount - move),
 | 
			
		||||
						null,
 | 
			
		||||
						pusher
 | 
			
		||||
					);
 | 
			
		||||
 | 
			
		||||
					onCollide?.Invoke(c);
 | 
			
		||||
					return true;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				X += sign;
 | 
			
		||||
				if (byGeometry)
 | 
			
		||||
					MovedByGeometry.X += sign;
 | 
			
		||||
				Entity.X += sign;
 | 
			
		||||
				move -= sign;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool MoveExactY(int amount, delegate void(Collision) onCollide = null, Geometry pusher = null, Geometry carrier = null)
 | 
			
		||||
		public bool MoveExactY(int amount, delegate void(Collision) onCollide = null)
 | 
			
		||||
		{
 | 
			
		||||
			int move = amount;
 | 
			
		||||
			int sign = Math.Sign(amount);
 | 
			
		||||
			bool byGeometry = carrier != null || pusher != null;
 | 
			
		||||
 | 
			
		||||
			while (move != 0)
 | 
			
		||||
			{
 | 
			
		||||
				Geometry hit = First<Solid>(.(0, sign));
 | 
			
		||||
				if (hit == null && sign == 1)
 | 
			
		||||
					hit = FirstOutside<JumpThru>(.(0, sign));
 | 
			
		||||
 | 
			
		||||
				if (hit != null)
 | 
			
		||||
				if (Check(Level, .(0, sign)) || Hitbox.Check<Solid>(.(0, sign)) || Hitbox.CheckOutside<JumpThru>(.(0, sign)))
 | 
			
		||||
				{
 | 
			
		||||
					let c = Collision(
 | 
			
		||||
						Cardinals.FromPoint(Point.Down * sign),
 | 
			
		||||
						Math.Abs(amount),
 | 
			
		||||
						Math.Abs(amount - move),
 | 
			
		||||
						hit,
 | 
			
		||||
						pusher
 | 
			
		||||
						Math.Abs(amount - move)
 | 
			
		||||
					);
 | 
			
		||||
 | 
			
		||||
					onCollide?.Invoke(c);
 | 
			
		||||
					return true;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				if (Check(Level, .(0, sign)))
 | 
			
		||||
				{
 | 
			
		||||
					let c = Collision(
 | 
			
		||||
						Cardinals.FromPoint(Point.Down * sign),
 | 
			
		||||
						Math.Abs(amount),
 | 
			
		||||
						Math.Abs(amount - move),
 | 
			
		||||
						null,
 | 
			
		||||
						pusher
 | 
			
		||||
					);
 | 
			
		||||
 | 
			
		||||
					onCollide?.Invoke(c);
 | 
			
		||||
					return true;
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				Y += sign;
 | 
			
		||||
				if (byGeometry)
 | 
			
		||||
					MovedByGeometry.Y += sign;
 | 
			
		||||
				Entity.Y += sign;
 | 
			
		||||
				move -= sign;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public void ZeroRemainderX()
 | 
			
		||||
		{
 | 
			
		||||
			remainder.X = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public void ZeroRemainderY()
 | 
			
		||||
		{
 | 
			
		||||
			remainder.Y = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public void ZeroRemainders()
 | 
			
		||||
		{
 | 
			
		||||
			remainder = Vector.Zero;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void MoveByGeometry(Point amount)
 | 
			
		||||
		{
 | 
			
		||||
			MovedByGeometry += amount;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool CornerCorrection(Cardinals direction, int maxAmount, int lookAhead = 1, int onlySign = 0)
 | 
			
		||||
		{
 | 
			
		||||
			Point dir = direction;
 | 
			
		||||
@ -215,10 +163,10 @@ namespace Strawberry.Sample
 | 
			
		||||
			perp.Y = Math.Abs(perp.Y);
 | 
			
		||||
 | 
			
		||||
			delegate bool(Point) checker;
 | 
			
		||||
 			if (dir == Point.Down)
 | 
			
		||||
				checker = scope:: (p) => !Check(Level, p) && !Check<Solid>(p) && !CheckOutside<JumpThru>(p);
 | 
			
		||||
			if (dir == Point.Down)
 | 
			
		||||
				checker = scope:: (p) => !Check(Level, p) && !Hitbox.Check<Solid>(p) && !Hitbox.CheckOutside<JumpThru>(p);
 | 
			
		||||
			else
 | 
			
		||||
				checker = scope:: (p) => !Check(Level, p) && !Check<Solid>(p);
 | 
			
		||||
				checker = scope:: (p) => !Check(Level, p) && !Hitbox.Check<Solid>(p);
 | 
			
		||||
 | 
			
		||||
			for (int i = 1; i <= maxAmount; i++)
 | 
			
		||||
			{
 | 
			
		||||
@ -230,7 +178,7 @@ namespace Strawberry.Sample
 | 
			
		||||
					let offset = dir * lookAhead + perp * i * j;
 | 
			
		||||
					if (checker(offset))
 | 
			
		||||
					{
 | 
			
		||||
						Position += offset;
 | 
			
		||||
						Entity.Position += offset;
 | 
			
		||||
						return true;
 | 
			
		||||
					}	
 | 
			
		||||
				}
 | 
			
		||||
@ -2,7 +2,7 @@ using System;
 | 
			
		||||
 | 
			
		||||
namespace Strawberry.Sample
 | 
			
		||||
{
 | 
			
		||||
	public class Player	: Actor
 | 
			
		||||
	public class Player	: Component, IUpdate
 | 
			
		||||
	{
 | 
			
		||||
		public Vector Speed;
 | 
			
		||||
 | 
			
		||||
@ -18,10 +18,8 @@ namespace Strawberry.Sample
 | 
			
		||||
			Add(tVarJump = new Timer());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Update()
 | 
			
		||||
		public void Update()
 | 
			
		||||
		{
 | 
			
		||||
			base.Update();
 | 
			
		||||
 | 
			
		||||
			const float coyoteTime = 0.1f;		// Time after leaving a ledge when you can still jump
 | 
			
		||||
			const float varJumpTime = 0.2f;		// Time after jumping that you can hold the jump button to continue gaining upward speed
 | 
			
		||||
			const float jumpSpeed = -160;
 | 
			
		||||
 | 
			
		||||
@ -6,16 +6,12 @@ namespace Strawberry.Sample
 | 
			
		||||
		public Cardinals Direction;
 | 
			
		||||
		public int Magnitude;
 | 
			
		||||
		public int Completed;
 | 
			
		||||
		public Geometry Stopper;
 | 
			
		||||
		public Geometry Pusher;
 | 
			
		||||
 | 
			
		||||
		public this(Cardinals direction, int magnitude, int completed, Geometry stopper, Geometry pusher)
 | 
			
		||||
		public this(Cardinals direction, int magnitude, int completed)
 | 
			
		||||
		{
 | 
			
		||||
			Direction = direction;
 | 
			
		||||
			Magnitude = magnitude;
 | 
			
		||||
			Completed = completed;
 | 
			
		||||
			Stopper = stopper;
 | 
			
		||||
			Pusher = pusher;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,83 +0,0 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
 | 
			
		||||
namespace Strawberry.Sample
 | 
			
		||||
{
 | 
			
		||||
	public abstract class Geometry : Entity
 | 
			
		||||
	{
 | 
			
		||||
		private Vector remainder;
 | 
			
		||||
 | 
			
		||||
		public this(Point position)
 | 
			
		||||
			: base(position)
 | 
			
		||||
		{
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void MoveX(float amount)
 | 
			
		||||
		{
 | 
			
		||||
			remainder.X += amount;
 | 
			
		||||
			let move = (int)Math.Round(remainder.X);
 | 
			
		||||
			if (move != 0)
 | 
			
		||||
			{
 | 
			
		||||
				remainder.X -= move;
 | 
			
		||||
				MoveExactX(move);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void MoveY(float amount)
 | 
			
		||||
		{
 | 
			
		||||
			remainder.Y += amount;
 | 
			
		||||
			let move = (int)Math.Round(remainder.Y);
 | 
			
		||||
			if (move != 0)
 | 
			
		||||
			{
 | 
			
		||||
				remainder.Y -= move;
 | 
			
		||||
				MoveExactY(move);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public void Move(Vector amount)
 | 
			
		||||
		{
 | 
			
		||||
			MoveX(amount.X);
 | 
			
		||||
			MoveY(amount.Y);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public void MoveToX(float x)
 | 
			
		||||
		{
 | 
			
		||||
			MoveX(x - (X + remainder.X));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public void MoveToY(float y)
 | 
			
		||||
		{
 | 
			
		||||
			MoveY(y - (Y + remainder.Y));
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public void MoveTo(Vector target)
 | 
			
		||||
		{
 | 
			
		||||
			MoveToX(target.X);
 | 
			
		||||
			MoveToY(target.Y);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public abstract void MoveExactX(int amount);
 | 
			
		||||
		public abstract void MoveExactY(int amount);
 | 
			
		||||
		public abstract List<Actor> GetRiders(List<Actor> into);
 | 
			
		||||
 | 
			
		||||
		public void ZeroRemainderX()
 | 
			
		||||
		{
 | 
			
		||||
			remainder.X = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void ZeroRemainderY()
 | 
			
		||||
		{
 | 
			
		||||
			remainder.Y = 0;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void ZeroRemainders()
 | 
			
		||||
		{
 | 
			
		||||
			remainder = Vector.Zero;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -1,80 +1,14 @@
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Strawberry.Sample
 | 
			
		||||
{
 | 
			
		||||
	public class JumpThru : Geometry
 | 
			
		||||
	public class JumpThru : Component, IHasHitbox
 | 
			
		||||
	{
 | 
			
		||||
		public this(Point position, int width)
 | 
			
		||||
			: base(position)
 | 
			
		||||
		public Hitbox Hitbox { get; private set; }
 | 
			
		||||
 | 
			
		||||
		public this(Hitbox hitbox)
 | 
			
		||||
		{
 | 
			
		||||
			Hitbox = Rect(0, 0, width, 2);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public this(JSON json)
 | 
			
		||||
			: this(.(json), json["width"])
 | 
			
		||||
		{
 | 
			
		||||
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void MoveExactX(int amount)
 | 
			
		||||
		{
 | 
			
		||||
			if (Collidable)
 | 
			
		||||
			{
 | 
			
		||||
				let riders = GetRiders(scope List<Actor>());
 | 
			
		||||
	
 | 
			
		||||
				X += amount;
 | 
			
		||||
				for (var a in riders)
 | 
			
		||||
					a.MoveExactX(amount, null, null, this);
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
				X += amount;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void MoveExactY(int amount)
 | 
			
		||||
		{
 | 
			
		||||
			if (Collidable)
 | 
			
		||||
			{
 | 
			
		||||
				let riders = GetRiders(scope List<Actor>());
 | 
			
		||||
 | 
			
		||||
				if (amount < 0)
 | 
			
		||||
				{
 | 
			
		||||
					for (var a in Scene.All<Actor>(scope List<Actor>()))
 | 
			
		||||
					{
 | 
			
		||||
						if (riders.Contains(a) || CheckOutside(a, Point.UnitY * amount))
 | 
			
		||||
						{
 | 
			
		||||
							let move = (Top + amount) - a.Bottom;
 | 
			
		||||
							a.MoveExactY(move, null, null, this);
 | 
			
		||||
						}
 | 
			
		||||
					}
 | 
			
		||||
					Y += amount;
 | 
			
		||||
				}
 | 
			
		||||
				else
 | 
			
		||||
				{
 | 
			
		||||
					Collidable = false;
 | 
			
		||||
 | 
			
		||||
					for (var a in riders)
 | 
			
		||||
						a.MoveExactY(amount, null, null, this);
 | 
			
		||||
 | 
			
		||||
					Collidable = true;
 | 
			
		||||
					Y += amount;
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
				Y += amount;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override List<Actor> GetRiders(List<Actor> into)
 | 
			
		||||
		{
 | 
			
		||||
			for (var a in Scene.All<Actor>(scope List<Actor>()))
 | 
			
		||||
				if (a.IsRiding(this))
 | 
			
		||||
					into.Add(a);
 | 
			
		||||
			return into;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Draw()
 | 
			
		||||
		{
 | 
			
		||||
			DrawHitbox(.LightGray);
 | 
			
		||||
			Hitbox = hitbox;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -2,93 +2,13 @@ using System.Collections;
 | 
			
		||||
 | 
			
		||||
namespace Strawberry.Sample
 | 
			
		||||
{
 | 
			
		||||
	public class Solid : Geometry
 | 
			
		||||
	public class Solid : Component, IHasHitbox
 | 
			
		||||
	{
 | 
			
		||||
		public this(Point position, Rect hitbox)
 | 
			
		||||
			: base(position)
 | 
			
		||||
		public Hitbox Hitbox { get; private set; }
 | 
			
		||||
 | 
			
		||||
		public this(Hitbox hitbox)
 | 
			
		||||
		{
 | 
			
		||||
			Hitbox = hitbox;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override List<Actor> GetRiders(List<Actor> into)
 | 
			
		||||
		{
 | 
			
		||||
			for (var a in Scene.All<Actor>(scope List<Actor>()))
 | 
			
		||||
				if (a.IsRiding(this))
 | 
			
		||||
					into.Add(a);
 | 
			
		||||
			return into;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void MoveExactX(int amount)
 | 
			
		||||
		{
 | 
			
		||||
			if (Collidable)
 | 
			
		||||
			{
 | 
			
		||||
				let riders = GetRiders(scope List<Actor>());
 | 
			
		||||
 | 
			
		||||
				X += amount;
 | 
			
		||||
				Collidable = false;
 | 
			
		||||
 | 
			
		||||
				for (Actor a in Scene.All<Actor>(scope List<Actor>()))
 | 
			
		||||
				{
 | 
			
		||||
					if (Check(a))
 | 
			
		||||
					{
 | 
			
		||||
						//Push
 | 
			
		||||
						int move;
 | 
			
		||||
						if (amount > 0)
 | 
			
		||||
							move = Right - a.Left;
 | 
			
		||||
						else
 | 
			
		||||
							move = Left - a.Right;
 | 
			
		||||
						a.MoveExactX(move, scope => a.Squish, this);
 | 
			
		||||
					}
 | 
			
		||||
					else if (riders.Contains(a))
 | 
			
		||||
					{
 | 
			
		||||
						//Carry
 | 
			
		||||
						a.MoveExactX(amount, null, null, this);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				Collidable = true;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
				X += amount;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void MoveExactY(int amount)
 | 
			
		||||
		{
 | 
			
		||||
			if (Collidable)
 | 
			
		||||
			{
 | 
			
		||||
				let riders = GetRiders(scope List<Actor>());
 | 
			
		||||
 | 
			
		||||
				Y += amount;
 | 
			
		||||
				Collidable = false;
 | 
			
		||||
 | 
			
		||||
				for (Actor a in Scene.All<Actor>(scope List<Actor>()))
 | 
			
		||||
				{
 | 
			
		||||
					if (Check(a))
 | 
			
		||||
					{
 | 
			
		||||
						//Push
 | 
			
		||||
						int move;
 | 
			
		||||
						if (amount > 0)
 | 
			
		||||
							move = Bottom - a.Top;
 | 
			
		||||
						else
 | 
			
		||||
							move = Top - a.Bottom;
 | 
			
		||||
						a.MoveExactY(move, scope => a.Squish, this);
 | 
			
		||||
					}
 | 
			
		||||
					else if (riders.Contains(a))
 | 
			
		||||
					{
 | 
			
		||||
						//Carry
 | 
			
		||||
						a.MoveExactY(amount, null, null, this);
 | 
			
		||||
					}
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				Collidable = true;
 | 
			
		||||
			}
 | 
			
		||||
			else
 | 
			
		||||
				Y += amount;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Draw()
 | 
			
		||||
		{
 | 
			
		||||
			DrawHitbox(.White);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										288
									
								
								src/Components/Collision/Hitbox.bf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										288
									
								
								src/Components/Collision/Hitbox.bf
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,288 @@
 | 
			
		||||
using System;
 | 
			
		||||
using System.Collections;
 | 
			
		||||
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	public class Hitbox : Component, IDebugDraw
 | 
			
		||||
	{
 | 
			
		||||
		public bool Collidable = true;
 | 
			
		||||
		public Rect Rect;
 | 
			
		||||
 | 
			
		||||
		public void DebugDraw()
 | 
			
		||||
		{
 | 
			
		||||
			Game.Batcher.Rect(SceneHitbox, .Red);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public int Width
 | 
			
		||||
		{
 | 
			
		||||
			[Inline]
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return Rect.Width;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			[Inline]
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Rect.Width = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public int Height
 | 
			
		||||
		{
 | 
			
		||||
			[Inline]
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return Rect.Height;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			[Inline]
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Rect.Height = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Rect SceneHitbox
 | 
			
		||||
		{
 | 
			
		||||
			[Inline]
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return Rect + Entity.Position;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public int Left
 | 
			
		||||
		{
 | 
			
		||||
			[Inline]
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return Entity.X + Rect.Left;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			[Inline]
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Entity.X = value - Rect.Left;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public int Right
 | 
			
		||||
		{
 | 
			
		||||
			[Inline]
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return Entity.X + Rect.Right;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			[Inline]
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Entity.X = value - Rect.Right;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public int Top
 | 
			
		||||
		{
 | 
			
		||||
			[Inline]
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return Entity.Y + Rect.Top;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			[Inline]
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Entity.Y = value - Rect.Top;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public int Bottom
 | 
			
		||||
		{
 | 
			
		||||
			[Inline]
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return Entity.Y + Rect.Bottom;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			[Inline]
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Entity.Y = value - Rect.Bottom;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// ===== Collisions =====
 | 
			
		||||
 | 
			
		||||
		public bool Check(Point point)
 | 
			
		||||
		{
 | 
			
		||||
			return SceneHitbox.Contains(point);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check(Rect rect)
 | 
			
		||||
		{
 | 
			
		||||
			return SceneHitbox.Intersects(rect);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check(Grid grid)
 | 
			
		||||
		{
 | 
			
		||||
			return grid != null && grid.Check(SceneHitbox);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check(Grid grid, Point offset)
 | 
			
		||||
		{
 | 
			
		||||
			return grid != null && grid.Check(SceneHitbox + offset);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check(Hitbox other)
 | 
			
		||||
		{
 | 
			
		||||
			return other.Collidable && SceneHitbox.Intersects(other.SceneHitbox);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check(Hitbox other, Point offset)
 | 
			
		||||
		{
 | 
			
		||||
			return other.Collidable && (SceneHitbox + offset).Intersects(other.SceneHitbox);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool CheckOutside(Hitbox other, Point offset)
 | 
			
		||||
		{
 | 
			
		||||
			return other.Collidable && !SceneHitbox.Intersects(other.SceneHitbox) && (SceneHitbox + offset).Intersects(other.SceneHitbox);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check<T>(T other) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			return Check(other.Hitbox);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check<T>(T other, Point offset) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			return Check(other.Hitbox, offset);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool CheckOutside<T>(T other, Point offset) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			return CheckOutside(other.Hitbox, offset);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check<T>() where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (Check(e.Hitbox))
 | 
			
		||||
					return true;
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check<T>(Point offset) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (Check(e.Hitbox, offset))
 | 
			
		||||
					return true;
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool CheckOutside<T>(Point offset) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (CheckOutside(e.Hitbox, offset))
 | 
			
		||||
					return true;
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T First<T>() where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (Check(e.Hitbox))
 | 
			
		||||
					return e;
 | 
			
		||||
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T First<T>(Point offset) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (Check(e.Hitbox, offset))
 | 
			
		||||
					return e;
 | 
			
		||||
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T FirstOutside<T>(Point offset) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (CheckOutside(e.Hitbox, offset))
 | 
			
		||||
					return e;
 | 
			
		||||
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T LeftmostOutside<T>(Point offset) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			T ret = null;
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (CheckOutside(e.Hitbox, offset) && (ret == null || e.Hitbox.Left < ret.Hitbox.Left))
 | 
			
		||||
					ret = e;
 | 
			
		||||
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T RightmostOutside<T>(Point offset) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			T ret = null;
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (CheckOutside(e.Hitbox, offset) && (ret == null || e.Hitbox.Right > ret.Hitbox.Right))
 | 
			
		||||
					ret = e;
 | 
			
		||||
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T TopmostOutside<T>(Point offset) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			T ret = null;
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (CheckOutside(e.Hitbox, offset) && (ret == null || e.Hitbox.Top < ret.Hitbox.Top))
 | 
			
		||||
					ret = e;
 | 
			
		||||
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T BottommostOutside<T>(Point offset) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			T ret = null;
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (CheckOutside(e.Hitbox, offset) && (ret == null || e.Hitbox.Bottom > ret.Hitbox.Bottom))
 | 
			
		||||
					ret = e;
 | 
			
		||||
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public List<T> All<T>(List<T> into) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (Check(e.Hitbox))
 | 
			
		||||
					into.Add(e);
 | 
			
		||||
 | 
			
		||||
			return into;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public List<T> All<T>(Point offset, List<T> into) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (Check(e.Hitbox, offset))
 | 
			
		||||
					into.Add(e);
 | 
			
		||||
 | 
			
		||||
			return into;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public List<T> AllOutside<T>(Point offset, List<T> into) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (CheckOutside(e.Hitbox, offset))
 | 
			
		||||
					into.Add(e);
 | 
			
		||||
 | 
			
		||||
			return into;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -1,14 +1,16 @@
 | 
			
		||||
using System.Collections;
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	public class OnCollide<T> : Component where T : Entity
 | 
			
		||||
	public class OnCollide<T> : Component, IHasHitbox, IUpdate where T : Component, IHasHitbox
 | 
			
		||||
	{
 | 
			
		||||
		public Hitbox Hitbox { get; private set; }
 | 
			
		||||
 | 
			
		||||
		// Takes as parameter the T collided with. Return false to stop checking for collisions until next frame.
 | 
			
		||||
		public delegate bool(T) Action;
 | 
			
		||||
 | 
			
		||||
		public this(delegate bool(T) action)
 | 
			
		||||
			: base(true, false)
 | 
			
		||||
		public this(Hitbox hitbox, delegate bool(T) action)
 | 
			
		||||
		{
 | 
			
		||||
			Hitbox = hitbox;
 | 
			
		||||
			Action = action;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -17,13 +19,13 @@ namespace Strawberry
 | 
			
		||||
			delete Action;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Update()
 | 
			
		||||
		public void Update()
 | 
			
		||||
		{
 | 
			
		||||
			if (Action != null)
 | 
			
		||||
			{
 | 
			
		||||
				let list = Entity.Scene.All<T>(scope List<T>());
 | 
			
		||||
				for (let t in list)
 | 
			
		||||
					if (Entity.Check(t) && !Action(t))
 | 
			
		||||
					if (Hitbox.Check(t) && !Action(t))
 | 
			
		||||
						break;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
							
								
								
									
										19
									
								
								src/Components/Drawing/DrawHitbox.bf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/Components/Drawing/DrawHitbox.bf
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,19 @@
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	public class DrawHitbox : Component, IHasHitbox, IDraw
 | 
			
		||||
	{
 | 
			
		||||
		public Hitbox Hitbox { get; private set; }
 | 
			
		||||
		public Color Color;
 | 
			
		||||
 | 
			
		||||
		public this(Hitbox hitbox, Color color)
 | 
			
		||||
		{
 | 
			
		||||
			Hitbox = hitbox;
 | 
			
		||||
			Color = color;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Draw()
 | 
			
		||||
		{
 | 
			
		||||
			Game.Batcher.Rect(Hitbox.SceneHitbox, Color);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								src/Components/Interfaces/IDebugDraw.bf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/Components/Interfaces/IDebugDraw.bf
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	[ComponentInterface]
 | 
			
		||||
	public interface IDebugDraw
 | 
			
		||||
	{
 | 
			
		||||
		public void DebugDraw();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								src/Components/Interfaces/IDraw.bf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/Components/Interfaces/IDraw.bf
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	[ComponentInterface]
 | 
			
		||||
	public interface IDraw
 | 
			
		||||
	{
 | 
			
		||||
		public void Draw();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								src/Components/Interfaces/IHasHitbox.bf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/Components/Interfaces/IHasHitbox.bf
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	[ComponentInterface]
 | 
			
		||||
	public interface IHasHitbox
 | 
			
		||||
	{
 | 
			
		||||
		public Hitbox Hitbox { get; }
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								src/Components/Interfaces/ILateUpdate.bf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/Components/Interfaces/ILateUpdate.bf
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	[ComponentInterface]
 | 
			
		||||
	public interface ILateUpdate
 | 
			
		||||
	{
 | 
			
		||||
		public void LateUpdate();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										8
									
								
								src/Components/Interfaces/IUpdate.bf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								src/Components/Interfaces/IUpdate.bf
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,8 @@
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	[ComponentInterface]
 | 
			
		||||
	public interface IUpdate
 | 
			
		||||
	{
 | 
			
		||||
		public void Update();
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -4,7 +4,7 @@ using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	public class StateMachine<TIndex> : Component where TIndex : struct, IHashable
 | 
			
		||||
	public class StateMachine<TIndex> : Component, IUpdate where TIndex : struct, IHashable
 | 
			
		||||
	{
 | 
			
		||||
		private Dictionary<TIndex, State> states = new Dictionary<TIndex, State>() ~ delete _;
 | 
			
		||||
		private TIndex state;
 | 
			
		||||
@ -14,7 +14,6 @@ namespace Strawberry
 | 
			
		||||
		public TIndex NextState { get; private set; }
 | 
			
		||||
 | 
			
		||||
		public this(TIndex startState)
 | 
			
		||||
			: base(true, false)
 | 
			
		||||
		{
 | 
			
		||||
			NextState = PreviousState = state = startState;
 | 
			
		||||
		}
 | 
			
		||||
@ -30,7 +29,7 @@ namespace Strawberry
 | 
			
		||||
			CallEnter();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Update()
 | 
			
		||||
		public void Update()
 | 
			
		||||
		{
 | 
			
		||||
			CallUpdate();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -3,35 +3,27 @@ using System.Diagnostics;
 | 
			
		||||
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	public class Timer : Component
 | 
			
		||||
	public class Timer : Component, IUpdate
 | 
			
		||||
	{
 | 
			
		||||
		private float value;
 | 
			
		||||
 | 
			
		||||
		public Action OnComplete ~ delete _;
 | 
			
		||||
		public bool RemoveOnComplete;
 | 
			
		||||
 | 
			
		||||
		public this()
 | 
			
		||||
			: base(false, false)
 | 
			
		||||
		{
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public this(Action onComplete, bool destroyOnComplete = false)
 | 
			
		||||
			: base(false, false)
 | 
			
		||||
		{
 | 
			
		||||
			OnComplete = onComplete;
 | 
			
		||||
			RemoveOnComplete = destroyOnComplete;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public this(float value, Action onComplete, bool destroyOnComplete = false)
 | 
			
		||||
			: base(false, false)
 | 
			
		||||
		{
 | 
			
		||||
			Value = value;
 | 
			
		||||
			OnComplete = onComplete;
 | 
			
		||||
			RemoveOnComplete = destroyOnComplete;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Update()
 | 
			
		||||
		public void Update()
 | 
			
		||||
		{
 | 
			
		||||
			if (value > 0)
 | 
			
		||||
			{
 | 
			
		||||
@ -39,8 +31,6 @@ namespace Strawberry
 | 
			
		||||
				if (value <= 0)
 | 
			
		||||
				{
 | 
			
		||||
					value = 0;
 | 
			
		||||
					Active = false;
 | 
			
		||||
 | 
			
		||||
					OnComplete?.Invoke();
 | 
			
		||||
					if (RemoveOnComplete)
 | 
			
		||||
						RemoveSelf();
 | 
			
		||||
@ -60,7 +50,6 @@ namespace Strawberry
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				this.value = Math.Max(0, value);
 | 
			
		||||
				Active = (this.value > 0);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -68,7 +57,6 @@ namespace Strawberry
 | 
			
		||||
		public void Clear()
 | 
			
		||||
		{
 | 
			
		||||
			value = 0;
 | 
			
		||||
			Active = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		static public implicit operator bool(Timer timer)
 | 
			
		||||
 | 
			
		||||
@ -1,33 +1,42 @@
 | 
			
		||||
using System;
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	public class Tween : Component
 | 
			
		||||
	public class Tween : Component, IUpdate
 | 
			
		||||
	{
 | 
			
		||||
		public Ease.Easer Easer ~ delete _;
 | 
			
		||||
		public delegate void(float) OnUpdate ~ delete _;
 | 
			
		||||
		public delegate void() OnComplete ~ delete _;
 | 
			
		||||
		public bool RemoveOnComplete;
 | 
			
		||||
 | 
			
		||||
		public bool Playing { get; private set; }
 | 
			
		||||
		public float T { get; private set; }
 | 
			
		||||
 | 
			
		||||
		public this(Ease.Easer easer = null, delegate void(float) onUpdate = null, delegate void() onComplete = null, bool removeOnComplete = true, bool start = true)
 | 
			
		||||
			: base(start, false)
 | 
			
		||||
		{
 | 
			
		||||
			Playing = start;
 | 
			
		||||
			Easer = easer;
 | 
			
		||||
			OnUpdate = onUpdate;
 | 
			
		||||
			OnComplete = onComplete;
 | 
			
		||||
			RemoveOnComplete = removeOnComplete;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public float Eased => Easer != null ? Easer(T) : T;
 | 
			
		||||
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public void Play()
 | 
			
		||||
		{
 | 
			
		||||
			T = 0;
 | 
			
		||||
			Active = true;
 | 
			
		||||
			Playing = true;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public override void Update()
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public void Stop()
 | 
			
		||||
		{
 | 
			
		||||
			Playing = false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void Update()
 | 
			
		||||
		{
 | 
			
		||||
			T = Math.Min(T + Time.Delta, 1);
 | 
			
		||||
			OnUpdate?.Invoke(Eased);
 | 
			
		||||
@ -35,7 +44,7 @@ namespace Strawberry
 | 
			
		||||
			if (T >= 1)
 | 
			
		||||
			{
 | 
			
		||||
				OnComplete?.Invoke();
 | 
			
		||||
				Active = false;
 | 
			
		||||
				Playing = false;
 | 
			
		||||
				if (RemoveOnComplete)
 | 
			
		||||
					RemoveSelf();
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
@ -6,15 +6,6 @@ namespace Strawberry
 | 
			
		||||
	{
 | 
			
		||||
		public Entity Entity { get; private set; }
 | 
			
		||||
 | 
			
		||||
		public bool Active;
 | 
			
		||||
		public bool Visible;
 | 
			
		||||
 | 
			
		||||
		public this(bool active, bool visible)
 | 
			
		||||
		{
 | 
			
		||||
			Active = active;
 | 
			
		||||
			Visible = visible;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void Added(Entity entity)
 | 
			
		||||
		{
 | 
			
		||||
			Entity = entity;
 | 
			
		||||
@ -27,13 +18,20 @@ namespace Strawberry
 | 
			
		||||
 | 
			
		||||
		public virtual void Started() { }
 | 
			
		||||
		public virtual void Ended() { }
 | 
			
		||||
		public virtual void Update() { }
 | 
			
		||||
		public virtual void Draw() { }
 | 
			
		||||
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public void RemoveSelf()
 | 
			
		||||
		{
 | 
			
		||||
			Entity?.Remove(this);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public Scene Scene => Entity?.Scene;
 | 
			
		||||
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public T SceneAs<T>() where T : Scene
 | 
			
		||||
		{
 | 
			
		||||
			return Entity.SceneAs<T>();
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								src/Core/ComponentInterfaceAttribute.bf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								src/Core/ComponentInterfaceAttribute.bf
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,9 @@
 | 
			
		||||
using System;
 | 
			
		||||
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	public struct ComponentInterfaceAttribute : Attribute
 | 
			
		||||
	{
 | 
			
		||||
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
@ -3,13 +3,9 @@ using System.Collections;
 | 
			
		||||
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	public abstract class Entity
 | 
			
		||||
	public sealed class Entity
 | 
			
		||||
	{
 | 
			
		||||
		public Scene Scene { get; private set; }
 | 
			
		||||
		public int Priority;
 | 
			
		||||
		public bool Active = true;
 | 
			
		||||
		public bool Visible = true;
 | 
			
		||||
		public bool Collidable = true;
 | 
			
		||||
		public bool DeleteOnRemove = true;
 | 
			
		||||
 | 
			
		||||
		private List<Component> components = new List<Component>() ~ delete _;
 | 
			
		||||
@ -40,32 +36,18 @@ namespace Strawberry
 | 
			
		||||
			Scene = null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public virtual void Started()
 | 
			
		||||
		public void Started()
 | 
			
		||||
		{
 | 
			
		||||
			for (var c in components)
 | 
			
		||||
				c.Started();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public virtual void Ended()
 | 
			
		||||
		public void Ended()
 | 
			
		||||
		{
 | 
			
		||||
			for (var c in components)
 | 
			
		||||
				c.Ended();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public virtual void Update()
 | 
			
		||||
		{
 | 
			
		||||
			for (var c in components)
 | 
			
		||||
				if (c.Active)
 | 
			
		||||
					c.Update();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public virtual void Draw()
 | 
			
		||||
		{
 | 
			
		||||
			for (var c in components)
 | 
			
		||||
				if (c.Visible)
 | 
			
		||||
					c.Draw();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public void RemoveSelf()
 | 
			
		||||
		{
 | 
			
		||||
@ -195,302 +177,13 @@ namespace Strawberry
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// ===== Hitbox =====
 | 
			
		||||
 | 
			
		||||
		public Rect Hitbox;
 | 
			
		||||
 | 
			
		||||
		public int Width
 | 
			
		||||
		{
 | 
			
		||||
			[Inline]
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return Hitbox.Width;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			[Inline]
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Hitbox.Width = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public int Height
 | 
			
		||||
		{
 | 
			
		||||
			[Inline]
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return Hitbox.Height;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			[Inline]
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Hitbox.Height = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Rect SceneHitbox
 | 
			
		||||
		{
 | 
			
		||||
			[Inline]
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return Hitbox + Position;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public Rect SceneHitboxOutline
 | 
			
		||||
		{
 | 
			
		||||
			[Inline]
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				Rect hb = Hitbox + Position;
 | 
			
		||||
				hb.X -= 1;
 | 
			
		||||
				hb.Y -= 1;
 | 
			
		||||
				hb.Width += 2;
 | 
			
		||||
				hb.Height += 2;
 | 
			
		||||
				return hb;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public int Left
 | 
			
		||||
		{
 | 
			
		||||
			[Inline]
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return Position.X + Hitbox.Left;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			[Inline]
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				X = value - Hitbox.Left;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public int Right
 | 
			
		||||
		{
 | 
			
		||||
			[Inline]
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return Position.X + Hitbox.Right;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			[Inline]
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Y = value - Hitbox.Right;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public int Top
 | 
			
		||||
		{
 | 
			
		||||
			[Inline]
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return Position.Y + Hitbox.Top;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			[Inline]
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Y = value - Hitbox.Top;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public int Bottom
 | 
			
		||||
		{
 | 
			
		||||
			[Inline]
 | 
			
		||||
			get
 | 
			
		||||
			{
 | 
			
		||||
				return Position.Y + Hitbox.Bottom;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			[Inline]
 | 
			
		||||
			set
 | 
			
		||||
			{
 | 
			
		||||
				Y = value - Hitbox.Bottom;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// ===== Collisions =====
 | 
			
		||||
 | 
			
		||||
		public bool Check(Point point)
 | 
			
		||||
		{
 | 
			
		||||
			return SceneHitbox.Contains(point);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check(Rect rect)
 | 
			
		||||
		{
 | 
			
		||||
			return SceneHitbox.Intersects(rect);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check(Grid grid)
 | 
			
		||||
		{
 | 
			
		||||
			return grid != null && grid.Check(SceneHitbox);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check(Grid grid, Point offset)
 | 
			
		||||
		{
 | 
			
		||||
			return grid != null && grid.Check(SceneHitbox + offset);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check(Entity other)
 | 
			
		||||
		{
 | 
			
		||||
			return other.Collidable && SceneHitbox.Intersects(other.SceneHitbox);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check(Entity other, Point offset)
 | 
			
		||||
		{
 | 
			
		||||
			return other.Collidable && (SceneHitbox + offset).Intersects(other.SceneHitbox);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool CheckOutside(Entity other, Point offset)
 | 
			
		||||
		{
 | 
			
		||||
			return other.Collidable && !SceneHitbox.Intersects(other.SceneHitbox) && (SceneHitbox + offset).Intersects(other.SceneHitbox);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check<T>() where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (Check(e))
 | 
			
		||||
					return true;
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check<T>(Point offset) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (Check(e, offset))
 | 
			
		||||
					return true;
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool CheckOutside<T>(Point offset) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (CheckOutside(e, offset))
 | 
			
		||||
					return true;
 | 
			
		||||
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T First<T>() where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (Check(e))
 | 
			
		||||
					return e;
 | 
			
		||||
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T First<T>(Point offset) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (Check(e, offset))
 | 
			
		||||
					return e;
 | 
			
		||||
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T FirstOutside<T>(Point offset) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (CheckOutside(e, offset))
 | 
			
		||||
					return e;
 | 
			
		||||
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T LeftmostOutside<T>(Point offset) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			T ret = null;
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (CheckOutside(e, offset) && (ret == null || e.Left < ret.Left))
 | 
			
		||||
					ret = e;
 | 
			
		||||
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T RightmostOutside<T>(Point offset) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			T ret = null;
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (CheckOutside(e, offset) && (ret == null || e.Right > ret.Right))
 | 
			
		||||
					ret = e;
 | 
			
		||||
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T TopmostOutside<T>(Point offset) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			T ret = null;
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (CheckOutside(e, offset) && (ret == null || e.Top < ret.Top))
 | 
			
		||||
					ret = e;
 | 
			
		||||
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T BottommostOutside<T>(Point offset) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			T ret = null;
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (CheckOutside(e, offset) && (ret == null || e.Bottom > ret.Bottom))
 | 
			
		||||
					ret = e;
 | 
			
		||||
 | 
			
		||||
			return ret;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public List<T> All<T>(List<T> into) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (Check(e))
 | 
			
		||||
					into.Add(e);
 | 
			
		||||
 | 
			
		||||
			return into;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public List<T> All<T>(Point offset, List<T> into) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (Check(e, offset))
 | 
			
		||||
					into.Add(e);
 | 
			
		||||
 | 
			
		||||
			return into;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public List<T> AllOutside<T>(Point offset, List<T> into) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (var e in Scene.All<T>(scope List<T>()))
 | 
			
		||||
				if (CheckOutside(e, offset))
 | 
			
		||||
					into.Add(e);
 | 
			
		||||
 | 
			
		||||
			return into;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// ===== Misc =====
 | 
			
		||||
 | 
			
		||||
		public void DrawHitbox(Color color)
 | 
			
		||||
		{
 | 
			
		||||
			Game.Batcher.Rect(SceneHitbox, color);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public void DrawHitboxOutline(Color color)
 | 
			
		||||
		{
 | 
			
		||||
			Game.Batcher.Rect(SceneHitboxOutline, color);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		[Inline]
 | 
			
		||||
		public T SceneAs<T>() where T : Scene
 | 
			
		||||
		{
 | 
			
		||||
			Runtime.Assert(Scene is T, "Scene type mismatch!");
 | 
			
		||||
			return Scene as T;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		static public int Compare(Entity a, Entity b)
 | 
			
		||||
		{
 | 
			
		||||
			return a.Priority <=> b.Priority; 
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -25,8 +25,6 @@ namespace Strawberry
 | 
			
		||||
		private Scene scene;
 | 
			
		||||
		private Scene switchToScene;
 | 
			
		||||
		private bool updating;
 | 
			
		||||
		private Dictionary<Type, List<Type>> entityAssignableLists;
 | 
			
		||||
		private Dictionary<Type, List<Type>> componentAssignableLists;
 | 
			
		||||
 | 
			
		||||
		public PlatformLayer PlatformLayer { get; private set; }
 | 
			
		||||
		public Batcher Batcher { get; private set; }
 | 
			
		||||
@ -60,9 +58,9 @@ namespace Strawberry
 | 
			
		||||
			VirtualInputs = new List<VirtualInput>();
 | 
			
		||||
			Input.[Friend]Init();
 | 
			
		||||
 | 
			
		||||
			BuildTypeLists();
 | 
			
		||||
			Tracker.[Friend]BuildAssignmentLists();
 | 
			
		||||
			Assets.LoadAll();
 | 
			
		||||
			Strawberry.Console.Init();
 | 
			
		||||
			Strawberry.StrwConsole.Init();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public ~this()
 | 
			
		||||
@ -83,9 +81,8 @@ namespace Strawberry
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			Assets.DisposeAll();
 | 
			
		||||
			DisposeTypeLists();
 | 
			
		||||
			Input.[Friend]Dispose();
 | 
			
		||||
			Strawberry.Console.Dispose();
 | 
			
		||||
			Strawberry.StrwConsole.Dispose();
 | 
			
		||||
 | 
			
		||||
			delete Batcher;
 | 
			
		||||
 | 
			
		||||
@ -157,7 +154,7 @@ namespace Strawberry
 | 
			
		||||
				Time.Elapsed += Time.Delta;
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			Strawberry.Console.[Friend]Update();
 | 
			
		||||
			Strawberry.StrwConsole.[Friend]Update();
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void Render()
 | 
			
		||||
@ -171,8 +168,8 @@ namespace Strawberry
 | 
			
		||||
		{
 | 
			
		||||
			Scene?.Draw();
 | 
			
		||||
 | 
			
		||||
			if (Strawberry.Console.Enabled)
 | 
			
		||||
				Strawberry.Console.[Friend]Draw();
 | 
			
		||||
			if (Strawberry.StrwConsole.Enabled)
 | 
			
		||||
				Strawberry.StrwConsole.[Friend]Draw();
 | 
			
		||||
 | 
			
		||||
			Batcher.Draw();
 | 
			
		||||
		}
 | 
			
		||||
@ -191,57 +188,5 @@ namespace Strawberry
 | 
			
		||||
				switchToScene = value;
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Type assignable caching
 | 
			
		||||
 | 
			
		||||
		private void BuildTypeLists()
 | 
			
		||||
		{
 | 
			
		||||
			/*
 | 
			
		||||
				For each Type that extends Entity, we build a list of all the other Entity Types that it is assignable to.
 | 
			
		||||
				We cache these lists, and use them later to bucket Entities as they are added to the Scene.
 | 
			
		||||
				This allows us to retrieve Entities by type very easily.
 | 
			
		||||
			*/
 | 
			
		||||
 | 
			
		||||
			entityAssignableLists = new Dictionary<Type, List<Type>>();
 | 
			
		||||
			for (let type in Type.Enumerator())
 | 
			
		||||
			{	
 | 
			
		||||
				if (type != typeof(Entity) && type.IsSubtypeOf(typeof(Entity)))
 | 
			
		||||
				{
 | 
			
		||||
					let list = new List<Type>();
 | 
			
		||||
					for (let check in Type.Enumerator())
 | 
			
		||||
						if (check != typeof(Entity) && check.IsSubtypeOf(typeof(Entity)) && type.IsSubtypeOf(check))
 | 
			
		||||
							list.Add(check);
 | 
			
		||||
					entityAssignableLists.Add(type, list);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			/*
 | 
			
		||||
				And then we also do this for components
 | 
			
		||||
			*/
 | 
			
		||||
 | 
			
		||||
			componentAssignableLists = new Dictionary<Type, List<Type>>();
 | 
			
		||||
			for (let type in Type.Enumerator())
 | 
			
		||||
			{	
 | 
			
		||||
				if (type != typeof(Component) && type.IsSubtypeOf(typeof(Component)))
 | 
			
		||||
				{
 | 
			
		||||
					let list = new List<Type>();
 | 
			
		||||
					for (let check in Type.Enumerator())
 | 
			
		||||
						if (check != typeof(Component) && check.IsSubtypeOf(typeof(Component)) && type.IsSubtypeOf(check))
 | 
			
		||||
							list.Add(check);
 | 
			
		||||
					componentAssignableLists.Add(type, list);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void DisposeTypeLists()
 | 
			
		||||
		{
 | 
			
		||||
			for (let list in entityAssignableLists.Values)
 | 
			
		||||
				delete list;
 | 
			
		||||
			delete entityAssignableLists;
 | 
			
		||||
 | 
			
		||||
			for (let list in componentAssignableLists.Values)
 | 
			
		||||
				delete list;
 | 
			
		||||
			delete componentAssignableLists;
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -10,7 +10,6 @@ namespace Strawberry
 | 
			
		||||
		private List<Entity> entities;
 | 
			
		||||
		private HashSet<Entity> toRemove;
 | 
			
		||||
		private HashSet<Entity> toAdd;
 | 
			
		||||
		private Dictionary<Type, List<Entity>> entityTracker;
 | 
			
		||||
		private Dictionary<Type, List<Component>> componentTracker;
 | 
			
		||||
 | 
			
		||||
		public this()
 | 
			
		||||
@ -19,12 +18,10 @@ namespace Strawberry
 | 
			
		||||
			toAdd = new HashSet<Entity>();
 | 
			
		||||
			toRemove = new HashSet<Entity>();
 | 
			
		||||
 | 
			
		||||
			entityTracker = new Dictionary<Type, List<Entity>>();
 | 
			
		||||
			for (let type in Game.[Friend]entityAssignableLists.Keys)
 | 
			
		||||
				entityTracker.Add(type, new List<Entity>());
 | 
			
		||||
 | 
			
		||||
			componentTracker = new Dictionary<Type, List<Component>>();
 | 
			
		||||
			for (let type in Game.[Friend]componentAssignableLists.Keys)
 | 
			
		||||
			for (let type in Tracker.AssignmentLists.Keys)
 | 
			
		||||
				componentTracker.Add(type, new List<Component>());
 | 
			
		||||
			for (let type in Tracker.Interfaces)
 | 
			
		||||
				componentTracker.Add(type, new List<Component>());
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -42,10 +39,6 @@ namespace Strawberry
 | 
			
		||||
 | 
			
		||||
			delete toRemove;
 | 
			
		||||
 | 
			
		||||
			for (let list in entityTracker.Values)
 | 
			
		||||
				delete list;
 | 
			
		||||
			delete entityTracker;
 | 
			
		||||
 | 
			
		||||
			for (let list in componentTracker.Values)
 | 
			
		||||
				delete list;
 | 
			
		||||
			delete componentTracker;
 | 
			
		||||
@ -59,26 +52,23 @@ namespace Strawberry
 | 
			
		||||
		public virtual void Update()
 | 
			
		||||
		{
 | 
			
		||||
			UpdateLists();
 | 
			
		||||
			for (let e in entities)
 | 
			
		||||
				if (e.Active)
 | 
			
		||||
					e.Update();
 | 
			
		||||
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public virtual void Draw()
 | 
			
		||||
		{
 | 
			
		||||
			for (let e in entities)
 | 
			
		||||
				if (e.Visible)
 | 
			
		||||
					e.Draw();
 | 
			
		||||
			
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T Add<T>(T e) where T : Entity
 | 
			
		||||
		public Entity Add(Entity e)
 | 
			
		||||
		{
 | 
			
		||||
			if (e.Scene == null)
 | 
			
		||||
				toAdd.Add(e);
 | 
			
		||||
			return e;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T Remove<T>(T e) where T : Entity
 | 
			
		||||
		public Entity Remove(Entity e)
 | 
			
		||||
		{
 | 
			
		||||
			if (e.Scene == this)
 | 
			
		||||
				toRemove.Add(e);
 | 
			
		||||
@ -92,7 +82,6 @@ namespace Strawberry
 | 
			
		||||
				for (let e in toRemove)
 | 
			
		||||
				{
 | 
			
		||||
					entities.Remove(e);
 | 
			
		||||
					UntrackEntity(e);
 | 
			
		||||
					e.[Friend]Removed();
 | 
			
		||||
					if (e.DeleteOnRemove)
 | 
			
		||||
						delete e;
 | 
			
		||||
@ -106,11 +95,8 @@ namespace Strawberry
 | 
			
		||||
				for (let e in toAdd)
 | 
			
		||||
				{
 | 
			
		||||
					entities.Add(e);
 | 
			
		||||
					TrackEntity(e);
 | 
			
		||||
					e.[Friend]Added(this);
 | 
			
		||||
				}
 | 
			
		||||
 | 
			
		||||
				entities.Sort(scope => Entity.Compare);
 | 
			
		||||
			}
 | 
			
		||||
 | 
			
		||||
			for (let e in entities)
 | 
			
		||||
@ -126,33 +112,15 @@ namespace Strawberry
 | 
			
		||||
 | 
			
		||||
		// Tracking
 | 
			
		||||
 | 
			
		||||
		private void TrackEntity(Entity e)
 | 
			
		||||
		{
 | 
			
		||||
			for (let t in Game.[Friend]entityAssignableLists[e.GetType()])
 | 
			
		||||
				entityTracker[t].Add(e);
 | 
			
		||||
 | 
			
		||||
			for (let c in e.[Friend]components)
 | 
			
		||||
				TrackComponent(c);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void UntrackEntity(Entity e)
 | 
			
		||||
		{
 | 
			
		||||
			for (let t in Game.[Friend]entityAssignableLists[e.GetType()])
 | 
			
		||||
				entityTracker[t].Remove(e);
 | 
			
		||||
 | 
			
		||||
			for (let c in e.[Friend]components)
 | 
			
		||||
				UntrackComponent(c);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void TrackComponent(Component c)
 | 
			
		||||
		{
 | 
			
		||||
			for (let t in Game.[Friend]componentAssignableLists[c.GetType()])
 | 
			
		||||
			for (let t in Tracker.AssignmentLists[c.GetType()])
 | 
			
		||||
				componentTracker[t].Add(c);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		private void UntrackComponent(Component c)
 | 
			
		||||
		{
 | 
			
		||||
			for (let t in Game.[Friend]componentAssignableLists[c.GetType()])
 | 
			
		||||
			for (let t in Tracker.AssignmentLists[c.GetType()])
 | 
			
		||||
				componentTracker[t].Remove(c);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -171,75 +139,6 @@ namespace Strawberry
 | 
			
		||||
			return (TimeElapsed - offset) % (interval * 2) >= interval;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		// Finding Entities
 | 
			
		||||
 | 
			
		||||
		public int Count<T>() where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			return entityTracker[typeof(T)].Count;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check<T>(Point point) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (let e in entityTracker[typeof(T)])
 | 
			
		||||
				if (e.Check(point))
 | 
			
		||||
					return true;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check<T>(Rect rect) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (let e in entityTracker[typeof(T)])
 | 
			
		||||
				if (e.Check(rect))
 | 
			
		||||
					return true;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T First<T>() where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (let e in entityTracker[typeof(T)])
 | 
			
		||||
				return e as T;
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T First<T>(Point point) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (let e in entityTracker[typeof(T)])
 | 
			
		||||
				if (e.Check(point))
 | 
			
		||||
					return e as T;
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T First<T>(Rect rect) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (let e in entityTracker[typeof(T)])
 | 
			
		||||
				if (e.Check(rect))
 | 
			
		||||
					return e as T;
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public List<T> All<T>(List<T> into) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (let e in entityTracker[typeof(T)])
 | 
			
		||||
				into.Add(e as T);
 | 
			
		||||
			return into;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public List<T> All<T>(Point point, List<T> into) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (let e in entityTracker[typeof(T)])
 | 
			
		||||
				if (e.Check(point))
 | 
			
		||||
					into.Add(e as T);
 | 
			
		||||
			return into;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public List<T> All<T>(Rect rect, List<T> into) where T : Entity
 | 
			
		||||
		{
 | 
			
		||||
			for (let e in entityTracker[typeof(T)])
 | 
			
		||||
				if (e.Check(rect))
 | 
			
		||||
					into.Add(e as T);
 | 
			
		||||
			return into;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		/*
 | 
			
		||||
			Finding Components
 | 
			
		||||
		*/
 | 
			
		||||
@ -249,25 +148,64 @@ namespace Strawberry
 | 
			
		||||
			return componentTracker[typeof(T)].Count;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public List<T> All<T>(List<T> into) where T : Component
 | 
			
		||||
		public bool Check<T>(Point point) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (let c in componentTracker[typeof(T)])
 | 
			
		||||
			for (T c in componentTracker[typeof(T)])
 | 
			
		||||
				if (c.Hitbox.Check(point))
 | 
			
		||||
					return true;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check<T>(Rect rect) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (T c in componentTracker[typeof(T)])
 | 
			
		||||
				if (c.Hitbox.Check(rect))
 | 
			
		||||
					return true;
 | 
			
		||||
			return false;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T First<T>() where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (T c in componentTracker[typeof(T)])
 | 
			
		||||
				return c;
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T First<T>(Point point) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (T c in componentTracker[typeof(T)])
 | 
			
		||||
				if (c.Hitbox.Check(point))
 | 
			
		||||
					return c as T;
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public T First<T>(Rect rect) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (T c in componentTracker[typeof(T)])
 | 
			
		||||
				if (c.Hitbox.Check(rect))
 | 
			
		||||
					return c as T;
 | 
			
		||||
			return null;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public List<T> All<T>(List<T> into) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (T c in componentTracker[typeof(T)])
 | 
			
		||||
				into.Add(c as T);
 | 
			
		||||
			return into;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public List<T> All<T>(Point point, List<T> into) where T : Component
 | 
			
		||||
		public List<T> All<T>(Point point, List<T> into) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (let c in componentTracker[typeof(T)])
 | 
			
		||||
				if (c.Entity.Check(point))
 | 
			
		||||
			for (T c in componentTracker[typeof(T)])
 | 
			
		||||
				if (c.Hitbox.Check(point))
 | 
			
		||||
					into.Add(c as T);
 | 
			
		||||
			return into;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public List<T> All<T>(Rect rect, List<T> into) where T : Component
 | 
			
		||||
		public List<T> All<T>(Rect rect, List<T> into) where T : Component, IHasHitbox
 | 
			
		||||
		{
 | 
			
		||||
			for (let c in componentTracker[typeof(T)])
 | 
			
		||||
				if (c.Entity.Check(rect))
 | 
			
		||||
			for (T c in componentTracker[typeof(T)])
 | 
			
		||||
				if (c.Hitbox.Check(rect))
 | 
			
		||||
					into.Add(c as T);
 | 
			
		||||
			return into;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
@ -143,9 +143,14 @@ namespace Strawberry
 | 
			
		||||
			return p.X >= 0 && p.Y >= 0 && p.X < CellsX && p.Y < CellsY;
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check(Entity entity)
 | 
			
		||||
		public bool Check(Hitbox hitbox)
 | 
			
		||||
		{
 | 
			
		||||
			return Check(entity.SceneHitbox);
 | 
			
		||||
			return Check(hitbox.SceneHitbox);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check(IHasHitbox other)
 | 
			
		||||
		{
 | 
			
		||||
			return Check(other.Hitbox.SceneHitbox);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		public bool Check(Rect rect)
 | 
			
		||||
 | 
			
		||||
@ -19,7 +19,7 @@ namespace Strawberry
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	[Reflect]
 | 
			
		||||
	static public class Console
 | 
			
		||||
	static public class StrwConsole
 | 
			
		||||
	{
 | 
			
		||||
		static public bool Open;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										38
									
								
								src/Static/Tracker.bf
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								src/Static/Tracker.bf
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,38 @@
 | 
			
		||||
using System.Collections;
 | 
			
		||||
using System;
 | 
			
		||||
namespace Strawberry
 | 
			
		||||
{
 | 
			
		||||
	static public class Tracker
 | 
			
		||||
	{
 | 
			
		||||
		static public Dictionary<Type, List<Type>> AssignmentLists = new .() ~ DeleteDictionaryAndValues!(_);
 | 
			
		||||
		static public List<Type> Interfaces = new .() ~ delete _;
 | 
			
		||||
 | 
			
		||||
		static private void BuildAssignmentLists()
 | 
			
		||||
		{
 | 
			
		||||
			// Find all interfaces with ComponentInterfaceAttribute
 | 
			
		||||
			for (let type in Type.Enumerator())
 | 
			
		||||
				if (type.IsInterface && type.HasCustomAttribute<ComponentInterfaceAttribute>())
 | 
			
		||||
					Interfaces.Add(type);
 | 
			
		||||
 | 
			
		||||
			/*
 | 
			
		||||
				For each Type that extends Component, we build a list of all the tracked Interfaces it implements.
 | 
			
		||||
				We use these lists later to bucket Components as they are added to the Scene.
 | 
			
		||||
				This allows us to retrieve Components by their type or by any of their implemented interface types.
 | 
			
		||||
			*/
 | 
			
		||||
 | 
			
		||||
			for (let type in Type.Enumerator())
 | 
			
		||||
			{	
 | 
			
		||||
				if (type != typeof(Component) && type.IsSubtypeOf(typeof(Component)))
 | 
			
		||||
				{
 | 
			
		||||
					let list = new List<Type>();
 | 
			
		||||
					list.Add(type);
 | 
			
		||||
					for (let check in Interfaces)
 | 
			
		||||
						if (type.IsSubtypeOf(check))
 | 
			
		||||
							list.Add(check);
 | 
			
		||||
 | 
			
		||||
					AssignmentLists.Add(type, list);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user