mirror of
https://github.com/MaddyThorson/StrawberryBF.git
synced 2024-11-25 16:18:56 +08:00
Initial commit
This commit is contained in:
commit
4a44eb0f26
2
.gitattributes
vendored
Normal file
2
.gitattributes
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
# Auto detect text files and perform LF normalization
|
||||
* text=auto
|
8
BeefProj.toml
Normal file
8
BeefProj.toml
Normal 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
16
src/Draw.bf
Normal 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
347
src/Entity.bf
Normal 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
105
src/Game.bf
Normal 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
194
src/Input/VirtualAxis.bf
Normal 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
137
src/Input/VirtualButton.bf
Normal 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
20
src/Input/VirtualInput.bf
Normal 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
58
src/Numerics/Point.bf
Normal 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
129
src/Numerics/Rect.bf
Normal 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
82
src/Numerics/Vector.bf
Normal 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
112
src/Physics/Actor.bf
Normal 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
57
src/Physics/Platform.bf
Normal 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
42
src/Physics/Solid.bf
Normal 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
148
src/Scene.bf
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user