Big restructuring - sample game is currently broken

This commit is contained in:
Maddy Thorson
2021-02-04 23:11:51 -08:00
parent 05c79b296e
commit 3d5130b45b
28 changed files with 551 additions and 866 deletions

View 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;
}
}
}

View File

@ -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;
}
}

View 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);
}
}
}

View File

@ -0,0 +1,8 @@
namespace Strawberry
{
[ComponentInterface]
public interface IDebugDraw
{
public void DebugDraw();
}
}

View File

@ -0,0 +1,8 @@
namespace Strawberry
{
[ComponentInterface]
public interface IDraw
{
public void Draw();
}
}

View File

@ -0,0 +1,8 @@
namespace Strawberry
{
[ComponentInterface]
public interface IHasHitbox
{
public Hitbox Hitbox { get; }
}
}

View File

@ -0,0 +1,8 @@
namespace Strawberry
{
[ComponentInterface]
public interface ILateUpdate
{
public void LateUpdate();
}
}

View File

@ -0,0 +1,8 @@
namespace Strawberry
{
[ComponentInterface]
public interface IUpdate
{
public void Update();
}
}

View File

@ -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();
}

View File

@ -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)

View File

@ -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();
}