Initial commit

This commit is contained in:
Matt Thorson 2020-05-04 20:50:38 -07:00
commit 4a44eb0f26
15 changed files with 1457 additions and 0 deletions

2
.gitattributes vendored Normal file
View File

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

8
BeefProj.toml Normal file
View File

@ -0,0 +1,8 @@
FileVersion = 1
Dependencies = {corlib = "*", SDL2 = "*"}
[Project]
Name = "Strawberry"
TargetType = "BeefLib"
StartupObject = "Program"
DefaultNamespace = "Strawberry"

16
src/Draw.bf Normal file
View File

@ -0,0 +1,16 @@
namespace Strawberry
{
static public class Draw
{
static public void Rect(int x, int y, int w, int h, SDL2.SDL.Color color)
{
SDL2.SDL.SetRenderDrawColor(Game.mRenderer, color.r, color.g, color.b, color.a);
SDL2.SDL.RenderFillRect(Game.mRenderer, &SDL2.SDL.Rect((int32)x, (int32)y, (int32)w, (int32)h));
}
static public void Rect(Rect rect, SDL2.SDL.Color color)
{
Rect(rect.X, rect.Y, rect.Width, rect.Height, color);
}
}
}

347
src/Entity.bf Normal file
View File

@ -0,0 +1,347 @@
using System;
using System.Collections;
namespace BeefMonocle
{
public class Entity
{
public Scene Scene { get; private set; }
public int Depth;
public bool Active = true;
public bool Visible = true;
public bool Collidable = true;
public bool DeleteOnRemove = true;
public this(int x, int y)
{
Positionf = .(x, y);
}
public void Added(Scene scene)
{
Scene = scene;
}
public void Removed()
{
Scene = null;
}
public virtual void Started()
{
}
public virtual void Update()
{
}
public virtual void Draw()
{
}
// ===== Position =====
public Vector Positionf;
public float Xf
{
[Inline]
get
{
return Positionf.X;
}
[Inline]
set
{
Positionf.X = value;
}
}
public float Yf
{
[Inline]
get
{
return Positionf.Y;
}
[Inline]
set
{
Positionf.Y = value;
}
}
public Point Position
{
[Inline]
get
{
return Positionf.Round();
}
[Inline]
set
{
Positionf = value;
}
}
public int X
{
[Inline]
get
{
return (int)Math.Round(Positionf.X);
}
[Inline]
set
{
Positionf.X = value;
}
}
public int Y
{
[Inline]
get
{
return (int)Math.Round(Positionf.Y);
}
[Inline]
set
{
Positionf.Y = value;
}
}
// ===== 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 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(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 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(SDL2.SDL.Color color)
{
Draw.Rect(SceneHitbox, color);
}
static public int operator<=>(Entity a, Entity b)
{
return a.Depth <=> b.Depth;
}
}
}

105
src/Game.bf Normal file
View File

@ -0,0 +1,105 @@
using SDL2;
using System;
using System.Collections;
namespace BeefMonocle
{
static
{
static public Game Game;
}
public class Game : SDLApp
{
public List<VirtualInput> VirtualInputs;
public float DeltaTime { get; private set; }
public float Time { get; private set; }
public float PreviousTime { get; private set; }
private Scene scene;
private Scene switchToScene;
private bool updating;
private SDL.Rect screenRect;
public this(String windowTitle, int32 width, int32 height)
: base()
{
Game = this;
VirtualInputs = new List<VirtualInput>();
DeltaTime = 1 / 60f;
mTitle.Set(windowTitle);
mWidth = width;
mHeight = height;
screenRect = SDL.Rect(0, 0, width, height);
}
public ~this()
{
if (scene != null)
delete scene;
if (switchToScene != scene && switchToScene != null)
delete switchToScene;
delete VirtualInputs;
Game = null;
}
public new virtual void Init()
{
base.Init();
}
public override void Update()
{
base.Update();
//Switch scenes
if (switchToScene != scene)
{
if (scene != null)
delete scene;
scene = switchToScene;
scene.Started();
}
for (var i in VirtualInputs)
i.Update();
if (scene != null)
scene.Update();
PreviousTime = Time;
Time += DeltaTime;
}
public override void Draw()
{
base.Draw();
SDL2.SDL.SetRenderDrawColor(mRenderer, 0, 0, 0, 255);
SDL2.SDL.RenderFillRect(mRenderer, &screenRect);
if (Scene != null)
Scene.Draw();
}
public Scene Scene
{
get
{
return scene;
}
set
{
if (switchToScene != scene && switchToScene != null)
delete switchToScene;
switchToScene = value;
}
}
}
}

194
src/Input/VirtualAxis.bf Normal file
View File

@ -0,0 +1,194 @@
using System.Collections;
using System;
namespace Strawberry
{
public class VirtualAxis : VirtualInput
{
public enum OverlapBehaviors { TakeNewer, TakeOlder, CancelOut }
public float Value { get; private set; }
public int IntValue { get; private set; }
public bool Pressed { get; private set; }
public bool Released { get; private set; }
public bool Repeating { get; private set; }
private List<Node> nodes;
private float pressBuffer;
private float releaseBuffer;
private float repeatStart;
private float repeatInterval;
private float lastPress;
private float lastRelease;
private float lastPressClear;
private float lastReleaseClear;
public this()
{
nodes = new List<Node>();
}
public ~this()
{
for (var n in nodes)
delete n;
delete nodes;
}
public override void Update()
{
for (var n in nodes)
n.Update();
//Value
let last = IntValue;
Value = 0;
for (var n in nodes)
{
if (n.Value != 0)
{
Value = n.Value;
break;
}
}
IntValue = Math.Sign(Value);
//Press
if (last != IntValue && IntValue != 0)
lastPress = Game.Time;
Pressed = IntValue != 0 && lastPress > lastPressClear && Game.Time - lastPress <= pressBuffer;
//Repeat
if (IntValue != 0 && repeatStart > 0 && Game.Time - lastPress >= repeatStart)
{
Repeating = true;
int a = (int)((Game.PreviousTime - lastPress) / repeatInterval);
int b = (int)((Game.Time - lastPress) / repeatInterval);
if (a != b)
Pressed = true;
}
else
Repeating = false;
//Release
if (last != 0 && IntValue == 0)
lastRelease = Game.Time;
Released = IntValue == 0 && lastRelease > lastReleaseClear && Game.Time - lastRelease <= releaseBuffer;
}
public void ClearPressBuffer()
{
lastPressClear = Game.Time;
}
public void ClearReleaseBuffer()
{
lastReleaseClear = Game.Time;
}
// Setup Calls
public VirtualAxis Keys(SDL2.SDL.Scancode negativeKey, SDL2.SDL.Scancode positiveKey, OverlapBehaviors overlapBehavior = .TakeNewer)
{
nodes.Add(new KeyboardKeys(negativeKey, positiveKey, overlapBehavior));
return this;
}
public VirtualAxis PressBuffer(float time)
{
pressBuffer = time;
return this;
}
public VirtualAxis ReleaseBuffer(float time)
{
releaseBuffer = time;
return this;
}
public VirtualAxis Repeat(float start, float interval)
{
repeatStart = start;
repeatInterval = interval;
return this;
}
// Nodes
private abstract class Node
{
public abstract float Value { get; }
public virtual void Update() { }
}
private class KeyboardKeys : Node
{
public OverlapBehaviors OverlapBehavior;
public SDL2.SDL.Scancode NegativeKeycode;
public SDL2.SDL.Scancode PositiveKeycode;
private float value;
private bool turned;
public this(SDL2.SDL.Scancode negativeKey, SDL2.SDL.Scancode positiveKey, OverlapBehaviors overlapBehavior = .TakeNewer)
{
NegativeKeycode = negativeKey;
PositiveKeycode = positiveKey;
OverlapBehavior = overlapBehavior;
}
public override void Update()
{
if (Game.IsKeyDown(PositiveKeycode))
{
if (Game.IsKeyDown(NegativeKeycode))
{
switch (OverlapBehavior)
{
case OverlapBehaviors.CancelOut:
value = 0;
break;
case OverlapBehaviors.TakeNewer:
if (!turned)
{
value *= -1;
turned = true;
}
break;
case OverlapBehaviors.TakeOlder:
//value stays the same
break;
}
}
else
{
turned = false;
value = 1;
}
}
else if (Game.IsKeyDown(NegativeKeycode))
{
turned = false;
value = -1;
}
else
{
turned = false;
value = 0;
}
}
public override float Value
{
get
{
return value;
}
}
}
}
}

137
src/Input/VirtualButton.bf Normal file
View File

@ -0,0 +1,137 @@
using System.Collections;
using System;
using System.Diagnostics;
namespace Strawberry
{
public class VirtualButton : VirtualInput
{
public bool Check { get; private set; }
public bool Pressed { get; private set; }
public bool Released { get; private set; }
public bool Repeating { get; private set; }
private List<Node> nodes;
private float pressBuffer;
private float releaseBuffer;
private float repeatStart;
private float repeatInterval;
private float lastPress;
private float lastRelease;
private float lastPressClear;
private float lastReleaseClear;
public this()
{
nodes = new List<Node>();
}
public ~this()
{
for (var n in nodes)
delete n;
delete nodes;
}
override public void Update()
{
//Check
let last = Check;
Check = false;
for (var n in nodes)
{
if (n.Check)
{
Check = true;
break;
}
}
//Press
if (!last && Check)
lastPress = Game.Time;
Pressed = Check && lastPress > lastPressClear && Game.Time - lastPress <= pressBuffer;
//Repeat
if (Check && repeatStart > 0 && Game.Time - lastPress >= repeatStart)
{
Repeating = true;
int a = (int)((Game.PreviousTime - lastPress) / repeatInterval);
int b = (int)((Game.Time - lastPress) / repeatInterval);
if (a != b)
Pressed = true;
}
else
Repeating = false;
//Release
if (last && !Check)
lastRelease = Game.Time;
Released = !Check && lastRelease > lastReleaseClear && Game.Time - lastRelease <= releaseBuffer;
}
public void ClearPressBuffer()
{
lastPressClear = Game.Time;
}
public void ClearReleaseBuffer()
{
lastReleaseClear = Game.Time;
}
// Setup Calls
public VirtualButton Key(SDL2.SDL.Scancode keycode)
{
nodes.Add(new KeyboardKey(keycode));
return this;
}
public VirtualButton PressBuffer(float time)
{
pressBuffer = time;
return this;
}
public VirtualButton ReleaseBuffer(float time)
{
releaseBuffer = time;
return this;
}
public VirtualButton Repeat(float start, float interval)
{
repeatStart = start;
repeatInterval = interval;
return this;
}
// Nodes
private abstract class Node
{
public abstract bool Check { get; }
}
private class KeyboardKey : Node
{
public SDL2.SDL.Scancode Keycode;
public this(SDL2.SDL.Scancode keycode)
{
Keycode = keycode;
}
override public bool Check
{
get
{
return Game.IsKeyDown(Keycode);
}
}
}
}
}

20
src/Input/VirtualInput.bf Normal file
View File

@ -0,0 +1,20 @@
namespace Strawberry
{
public abstract class VirtualInput
{
public this()
{
Game.VirtualInputs.Add(this);
}
public ~this()
{
Game.VirtualInputs.Remove(this);
}
public virtual void Update()
{
}
}
}

58
src/Numerics/Point.bf Normal file
View File

@ -0,0 +1,58 @@
using System;
namespace Strawberry
{
public struct Point
{
static public readonly Point Right = Point(1, 0);
static public readonly Point Left = Point(-1, 0);
static public readonly Point Up = Point(0, -1);
static public readonly Point Down = Point(0, 1);
static public readonly Point Zero = Point(0, 0);
static public readonly Point One = Point(1, 1);
public int X;
public int Y;
public this()
{
this = default;
}
public this(int x, int y)
{
X = x;
Y = y;
}
static public explicit operator Point(Vector a)
{
return Point((int)a.X, (int)a.Y);
}
static public bool operator==(Point a, Point b)
{
return a.X == b.X && a.Y == b.Y;
}
static public Point operator+(Point a, Point b)
{
return Point(a.X + b.X, a.Y + b.Y);
}
static public Point operator-(Point a, Point b)
{
return Point(a.X - b.X, a.Y - b.Y);
}
static public Point operator*(Point a, int b)
{
return Point(a.X * b, a.Y * b);
}
static public Point operator/(Point a, int b)
{
return Point(a.X / b, a.Y / b);
}
}
}

129
src/Numerics/Rect.bf Normal file
View File

@ -0,0 +1,129 @@
using System;
namespace Strawberry
{
public struct Rect
{
public int X;
public int Y;
public int Width;
public int Height;
public this()
{
this = default;
}
public this(int x, int y, int width, int height)
{
X = x;
Y = y;
Width = width;
Height = height;
}
public int Left
{
[Inline]
get
{
return X;
}
[Inline]
set mut
{
X = value;
}
}
public int Right
{
[Inline]
get
{
return X + Width;
}
[Inline]
set mut
{
X = value - Width;
}
}
public int Top
{
[Inline]
get
{
return Y;
}
[Inline]
set mut
{
Y = value;
}
}
public int Bottom
{
[Inline]
get
{
return Y + Height;
}
[Inline]
set mut
{
Y = value - Height;
}
}
public Rect MirrorX(int axis = 0)
{
var rect = this;
rect.X = axis - X - Width;
return rect;
}
public Rect MirrorY(int axis = 0)
{
var rect = this;
rect.Y = axis - Y - Height;
return rect;
}
public Rect Inflate(int amount)
{
return Rect(X - amount, Y - amount, Width + amount * 2, Height + amount * 2);
}
public bool Intersects(Rect rect)
{
return (X + Width) > rect.X && (rect.X + rect.Width) > X && (Y + Height) > rect.Y && (rect.Y + rect.Height) > Y;
}
public bool Contains(Point point)
{
return point.X >= X && point.X < X + Width && point.Y >= Y && point.Y < Y + Height;
}
static public bool operator==(Rect a, Rect b)
{
return a.X == b.X && a.Y == b.Y && a.Width == b.Width && a.Height == b.Height;
}
static public Rect operator+(Rect a, Point b)
{
return Rect(a.X + b.X, a.Y + b.Y, a.Width, a.Height);
}
static public Rect operator-(Rect a, Point b)
{
return Rect(a.X - b.X, a.Y - b.Y, a.Width, a.Height);
}
}
}

82
src/Numerics/Vector.bf Normal file
View File

@ -0,0 +1,82 @@
using System;
namespace Strawberry
{
public struct Vector
{
static public readonly Vector Right = Vector(1, 0);
static public readonly Vector Left = Vector(-1, 0);
static public readonly Vector Up = Vector(0, -1);
static public readonly Vector Down = Vector(0, 1);
static public readonly Vector Zero = Vector(0, 0);
static public readonly Vector One = Vector(1, 1);
public float X;
public float Y;
public this()
{
this = default;
}
public this(float x, float y)
{
X = x;
Y = y;
}
public float Length
{
[Inline]
get
{
return Math.Sqrt(LengthSquared);
}
}
public float LengthSquared
{
[Inline]
get
{
return X * X + Y * Y;
}
}
[Inline]
public Point Round()
{
return Point((int)Math.Round(X), (int)Math.Round(Y));
}
static public operator Vector(Point a)
{
return Vector(a.X, a.Y);
}
static public bool operator==(Vector a, Vector b)
{
return a.X == b.X && a.Y == b.Y;
}
static public Vector operator+(Vector a, Vector b)
{
return Vector(a.X + b.X, a.Y + b.Y);
}
static public Vector operator-(Vector a, Vector b)
{
return Vector(a.X - b.X, a.Y - b.Y);
}
static public Vector operator*(Vector a, float b)
{
return Vector(a.X * b, a.Y * b);
}
static public Vector operator/(Vector a, float b)
{
return Vector(a.X / b, a.Y / b);
}
}
}

112
src/Physics/Actor.bf Normal file
View File

@ -0,0 +1,112 @@
using System;
namespace Strawberry
{
[Reflect]
public class Actor : Entity
{
private Vector remainder;
public this(int x, int y)
: base(x, y)
{
}
public bool GroundCheck(int distance = 1)
{
return Check<Solid>(.(0, distance));
}
public virtual bool IsRiding(Solid solid)
{
return Check(solid, .(0, 1));
}
public virtual void Squish()
{
}
public bool MoveX(float amount, Action onCollide = null)
{
remainder.X += amount;
let move = (int)Math.Round(remainder.X);
if (move != 0)
{
remainder.X -= move;
return MoveExactX(move, onCollide);
}
else
return false;
}
public bool MoveY(float amount, Action onCollide = null)
{
remainder.Y += amount;
let move = (int)Math.Round(remainder.Y);
if (move != 0)
{
remainder.Y -= move;
return MoveExactY(move, onCollide);
}
else
return false;
}
public bool MoveExactX(int amount, Action onCollide = null)
{
int move = amount;
int sign = Math.Sign(amount);
while (move != 0)
{
if (Check<Solid>(.(sign, 0)))
{
ZeroRemainderX();
onCollide?.Invoke();
return true;
}
X += sign;
move -= sign;
}
return false;
}
public bool MoveExactY(int amount, Action onCollide = null)
{
int move = amount;
int sign = Math.Sign(amount);
while (move != 0)
{
if (Check<Solid>(.(0, sign)))
{
ZeroRemainderY();
onCollide?.Invoke();
return true;
}
Y += sign;
move -= sign;
}
return false;
}
public void ZeroRemainderX()
{
remainder.X = 0;
}
public void ZeroRemainderY()
{
remainder.Y = 0;
}
public void ZeroRemainder()
{
remainder = Vector.Zero;
}
}
}

57
src/Physics/Platform.bf Normal file
View File

@ -0,0 +1,57 @@
using System;
using System.Collections;
namespace Strawberry
{
public abstract class Platform : Entity
{
private Vector remainder;
public this(int x, int y)
: base(x, y)
{
}
public void MoveX(float amount, Action onCollide = null)
{
remainder.X += amount;
let move = (int)Math.Round(remainder.X);
if (move != 0)
{
remainder.X -= move;
MoveExactX(move, onCollide);
}
}
public void MoveY(float amount, Action onCollide = null)
{
remainder.Y += amount;
let move = (int)Math.Round(remainder.Y);
if (move != 0)
{
remainder.Y -= move;
MoveExactY(move, onCollide);
}
}
public abstract void MoveExactX(int amount, Action onCollide = null);
public abstract void MoveExactY(int amount, Action onCollide = null);
public abstract List<Actor> GetRiders(List<Actor> into);
public void ZeroRemainderX()
{
remainder.X = 0;
}
public void ZeroRemainderY()
{
remainder.Y = 0;
}
public void ZeroRemainder()
{
remainder = Vector.Zero;
}
}
}

42
src/Physics/Solid.bf Normal file
View File

@ -0,0 +1,42 @@
using System.Collections;
namespace Strawberry
{
public class Solid : Platform
{
public this(int x, int y, Rect hitbox)
: base(x, y)
{
Hitbox = hitbox;
}
public override void Draw()
{
DrawHitbox(.(255, 255, 255, 255));
}
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, System.Action onCollide = null)
{
if (amount != 0)
{
}
}
public override void MoveExactY(int amount, System.Action onCollide = null)
{
if (amount != 0)
{
}
}
}
}

148
src/Scene.bf Normal file
View File

@ -0,0 +1,148 @@
using System.Collections;
using System;
namespace Strawberry
{
public class Scene
{
private List<Entity> entities;
private HashSet<Entity> toRemove;
private HashSet<Entity> toAdd;
public this()
{
entities = new List<Entity>();
toAdd = new HashSet<Entity>();
toRemove = new HashSet<Entity>();
}
public ~this()
{
for (var e in entities)
if (e.DeleteOnRemove)
delete e;
delete entities;
for (var e in toAdd)
if (e.DeleteOnRemove)
delete e;
delete toAdd;
delete toRemove;
}
public virtual void Started()
{
}
public virtual void Update()
{
UpdateLists();
for (var e in entities)
if (e.Active)
e.Update();
}
public virtual void Draw()
{
for (var e in entities)
if (e.Visible)
e.Draw();
}
public T Add<T>(T e) where T : Entity
{
if (e.Scene == null)
toAdd.Add(e);
return e;
}
public T Remove<T>(T e) where T : Entity
{
if (e.Scene == this)
toRemove.Add(e);
return e;
}
private void UpdateLists()
{
if (toRemove.Count > 0)
{
for (var e in toRemove)
{
entities.Remove(e);
e.Removed();
if (e.DeleteOnRemove)
delete e;
}
toRemove.Clear();
}
if (toAdd.Count > 0)
{
for (var e in toAdd)
{
entities.Add(e);
e.Added(this);
}
for (var e in toAdd)
e.Started();
toAdd.Clear();
}
}
// Finding Entities
public T First<T>() where T : Entity
{
for (var e in entities)
if (e is T)
return e as T;
return null;
}
public T First<T>(Point point) where T : Entity
{
for (var e in entities)
if (e is T && e.Check(point))
return e as T;
return null;
}
public T First<T>(Rect rect) where T : Entity
{
for (var e in entities)
if (e is T && e.Check(rect))
return e as T;
return null;
}
public List<T> All<T>(List<T> into) where T : Entity
{
for (var e in entities)
if (e is T)
into.Add(e as T);
return into;
}
public List<T> All<T>(Point point, List<T> into) where T : Entity
{
for (var e in entities)
if (e is T && e.Check(point))
into.Add(e as T);
return into;
}
public List<T> All<T>(Rect rect, List<T> into) where T : Entity
{
for (var e in entities)
if (e is T && e.Check(rect))
into.Add(e as T);
return into;
}
}
}