The sample game works again!

This commit is contained in:
Maddy Thorson 2021-12-23 17:09:38 -08:00
parent d3bf09f173
commit bae5798f07
17 changed files with 264 additions and 115 deletions

View File

@ -15,4 +15,3 @@ ReflectAlwaysInclude = "IncludeAll"
Type = "Folder" Type = "Folder"
Name = "Physics" Name = "Physics"
AutoInclude = true AutoInclude = true
Source = ["Physics.bf", "Solid.bf", "JumpThru.bf"]

View File

@ -0,0 +1,61 @@
namespace Strawberry.Sample
{
public class MovingJumpThru : Component, IUpdate
{
static public Entity Create(Point pos, int width, Point moveTo, float moveTime)
{
let e = new Entity(pos);
let hitbox = e.Add(new Hitbox(0, 0, width, 4));
let jumpThru = e.Add(new JumpThru(hitbox));
e.Add(new MovingJumpThru(jumpThru, moveTo, moveTime));
e.Add(new DrawHitbox(hitbox, .LightGray));
return e;
}
private JumpThru jumpThru;
private Point moveFrom;
private Point moveTo;
private float moveTime;
private float movingLerp = 0;
private bool movingPositive = true;
public this(JumpThru jumpThru, Point moveTo, float moveTime)
{
this.jumpThru = jumpThru;
this.moveTo = moveTo;
this.moveTime = moveTime;
}
protected override void Awake()
{
moveFrom = Entity.Position;
}
public void Update()
{
if (movingPositive)
{
movingLerp += Time.Delta / moveTime;
if (movingLerp >= 1)
{
movingLerp = 1;
movingPositive = false;
}
}
else
{
movingLerp -= Time.Delta / moveTime;
if (movingLerp <= 0)
{
movingLerp = 0;
movingPositive = true;
}
}
let target = Vector.Lerp(moveFrom, moveTo, Ease.CubeInOut(movingLerp));
jumpThru.MoveTo(target);
}
}
}

View File

@ -2,7 +2,7 @@ using System;
namespace Strawberry.Sample namespace Strawberry.Sample
{ {
public class Player : Component, IUpdate, IDraw public class Player : Component, IUpdate
{ {
static public Entity Create(Point pos) static public Entity Create(Point pos)
{ {
@ -10,18 +10,19 @@ namespace Strawberry.Sample
e.Add(new Player()); e.Add(new Player());
let hitbox = e.Add(new Hitbox(-4, -8, 16, 16)); let hitbox = e.Add(new Hitbox(-4, -8, 16, 16));
e.Add(new Physics(hitbox)); e.Add(new Actor(hitbox));
e.Add(new DrawHitbox(hitbox, .Red));
return e; return e;
} }
public Vector Speed; public Vector Speed;
private Physics physics; private Actor physics;
private Timer tJumpGrace; private Timer tJumpGrace;
private Timer tVarJump; private Timer tVarJump;
public override void Added() protected override void Added()
{ {
base.Added(); base.Added();
@ -29,9 +30,9 @@ namespace Strawberry.Sample
tVarJump = Entity.Add(new Timer()); tVarJump = Entity.Add(new Timer());
} }
public override void Awake() protected override void Awake()
{ {
physics = Entity.First<Physics>(); physics = Entity.First<Actor>();
} }
public void Update() public void Update()
@ -111,10 +112,5 @@ namespace Strawberry.Sample
Speed.Y = 0; Speed.Y = 0;
physics.ZeroRemainderY(); physics.ZeroRemainderY();
} }
public void Draw()
{
physics.Hitbox.DebugDraw();
}
} }
} }

View File

@ -0,0 +1,29 @@
using System;
namespace Strawberry.Sample
{
static public class StaticGeometry
{
static public Entity CreateSolid(Point pos, Rect bounds)
{
let e = new Entity(pos);
let hitbox = e.Add(new Hitbox(bounds));
e.Add(new Solid(hitbox));
e.Add(new DrawHitbox(hitbox, .White));
return e;
}
static public Entity CreateJumpThru(Point pos, int width)
{
let e = new Entity(pos);
let hitbox = e.Add(new Hitbox(0, 0, width, 4));
e.Add(new JumpThru(hitbox));
e.Add(new DrawHitbox(hitbox, .LightGray));
return e;
}
}
}

View File

@ -7,10 +7,9 @@ namespace Strawberry.Sample
public this() public this()
{ {
Add(Player.Create(.(50, 50))); Add(Player.Create(.(50, 50)));
Add(MovingJumpThru.Create(.(136, 100), 32, .(124, 140), 2f));
Add(new OldSolid(.(0, 168), .(0, 0, 320, 12))); Add(StaticGeometry.CreateSolid(.(0, 168), .(0, 0, 320, 12)));
Add(new OldJumpThru(.(200, 132), 48)); Add(StaticGeometry.CreateJumpThru(.(200, 132), 48));
Add(new MovingJumpThru(.(136, 100), 32, .(124, 140), 2f));
} }
} }
} }

View File

@ -1,50 +0,0 @@
namespace Strawberry.Sample
{
public class MovingJumpThru : JumpThru
{
private Point moveFrom;
private Point moveTo;
private float moveTime;
private float movingLerp;
private bool movingPositive;
public this(Point pos, int width, Point moveTo, float moveTime)
: base(pos, width)
{
moveFrom = Position;
this.moveTo = moveTo;
this.moveTime = moveTime;
movingLerp = 0;
movingPositive = true;
}
public override void Update()
{
base.Update();
if (movingPositive)
{
movingLerp += Time.Delta / moveTime;
if (movingLerp >= 1)
{
movingLerp = 1;
movingPositive = false;
}
}
else
{
movingLerp -= Time.Delta / moveTime;
if (movingLerp <= 0)
{
movingLerp = 0;
movingPositive = true;
}
}
let target = Vector.Lerp(moveFrom, moveTo, Ease.CubeInOut(movingLerp));
MoveTo(target);
}
}
}

View File

@ -1,20 +1,32 @@
using System; using System;
using System.Collections;
namespace Strawberry.Sample namespace Strawberry.Sample
{ {
public class Physics : Component, IHasHitbox, IUpdate public class Actor : Component, IHasHitbox, IUpdate
{ {
public Hitbox Hitbox { get; private set; } public Hitbox Hitbox { get; private set; }
public Vector Speed; public Vector Speed;
private Vector remainder; private Vector remainder;
public Level Level => Entity.SceneAs<Level>();
public Vector ExactPosition => Entity.Position + remainder;
public this(Hitbox hitbox) public this(Hitbox hitbox)
{ {
Hitbox = hitbox; Hitbox = hitbox;
} }
public Level Level => Entity.SceneAs<Level>(); public void Update()
{
MoveX(Speed.X * Time.Delta);
MoveY(Speed.Y * Time.Delta);
}
/*
Collision Helpers
*/
public bool Check(Level level) public bool Check(Level level)
{ {
@ -31,21 +43,19 @@ namespace Strawberry.Sample
return Hitbox.Check<Solid>(.(0, distance)) || Check(Level, .(0, distance)) || Hitbox.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) public bool IsRiding(Solid solid)
{ {
return Hitbox.Check(solid, .(0, 1)); return Hitbox.Check(solid, .(0, 1));
} }
public virtual bool IsRiding(JumpThru jumpThru) public bool IsRiding(JumpThru jumpThru)
{ {
return Hitbox.CheckOutside(jumpThru, .(0, 1)); return Hitbox.CheckOutside(jumpThru, .(0, 1));
} }
public void Update() /*
{ Movement
MoveX(Speed.X * Time.Delta); */
MoveY(Speed.Y * Time.Delta);
}
public bool MoveX(float amount, delegate void(Collision) onCollide = null) public bool MoveX(float amount, delegate void(Collision) onCollide = null)
{ {
@ -74,15 +84,15 @@ namespace Strawberry.Sample
} }
[Inline] [Inline]
public void MoveToX(float x) public void MoveToX(float x, delegate void(Collision) onCollide = null)
{ {
MoveX(x - (Entity.X + remainder.X), null); MoveX(x - (Entity.X + remainder.X), onCollide);
} }
[Inline] [Inline]
public void MoveToY(float y) public void MoveToY(float y, delegate void(Collision) onCollide = null)
{ {
MoveY(y - (Entity.Y + remainder.Y), null); MoveY(y - (Entity.Y + remainder.Y), onCollide);
} }
public bool MoveExactX(int amount, delegate void(Collision) onCollide = null) public bool MoveExactX(int amount, delegate void(Collision) onCollide = null)
@ -116,22 +126,45 @@ namespace Strawberry.Sample
int move = amount; int move = amount;
int sign = Math.Sign(amount); int sign = Math.Sign(amount);
while (move != 0) if (move > 0)
{ {
if (Check(Level, .(0, sign)) || Hitbox.Check<Solid>(.(0, sign)) || Hitbox.CheckOutside<JumpThru>(.(0, sign))) while (move != 0)
{ {
let c = Collision( if (Check(Level, .(0, sign)) || Hitbox.Check<Solid>(.(0, sign)) || Hitbox.CheckOutside<JumpThru>(.(0, sign)))
Cardinals.FromPoint(Point.Down * sign), {
Math.Abs(amount), let c = Collision(
Math.Abs(amount - move) Cardinals.FromPoint(Point.Down * sign),
); Math.Abs(amount),
Math.Abs(amount - move)
);
onCollide?.Invoke(c); onCollide?.Invoke(c);
return true; return true;
}
Entity.Y += sign;
move -= sign;
} }
}
else
{
while (move != 0)
{
if (Check(Level, .(0, sign)) || Hitbox.Check<Solid>(.(0, sign)))
{
let c = Collision(
Cardinals.FromPoint(Point.Down * sign),
Math.Abs(amount),
Math.Abs(amount - move)
);
Entity.Y += sign; onCollide?.Invoke(c);
move -= sign; return true;
}
Entity.Y += sign;
move -= sign;
}
} }
return false; return false;

View File

@ -1,4 +1,5 @@
using System.Collections; using System.Collections;
using System.Collections;
namespace Strawberry.Sample namespace Strawberry.Sample
{ {
@ -6,9 +7,54 @@ namespace Strawberry.Sample
{ {
public Hitbox Hitbox { get; private set; } public Hitbox Hitbox { get; private set; }
private Vector remainder;
public Vector ExactPosition => Entity.Position + remainder;
public this(Hitbox hitbox) public this(Hitbox hitbox)
{ {
Hitbox = hitbox; Hitbox = hitbox;
} }
public void FindRiders(List<Actor> into)
{
for (let a in Scene.All<Actor>(scope .()))
if (a.IsRiding(this))
into.Add(a);
}
public void Move(Vector amount)
{
remainder += amount;
Point move = remainder.Round();
MoveExact(move);
}
public void MoveTo(Vector pos)
{
Move(pos - ExactPosition);
}
public void MoveExact(Point amount)
{
if (amount != .Zero)
{
if (Hitbox.Collidable)
{
List<Actor> riders = FindRiders(..scope .());
Hitbox.Collidable = false;
for (let r in riders)
{
r.MoveExactX(amount.X);
r.MoveExactY(amount.Y);
}
Hitbox.Collidable = true;
}
Entity.Position += amount;
}
}
} }
} }

View File

@ -6,9 +6,15 @@ namespace Strawberry.Sample
{ {
public Hitbox Hitbox { get; private set; } public Hitbox Hitbox { get; private set; }
private Vector remainder;
public Vector ExactPosition => Entity.Position + remainder;
public this(Hitbox hitbox) public this(Hitbox hitbox)
{ {
Hitbox = hitbox; Hitbox = hitbox;
} }
} }
} }

View File

@ -335,19 +335,19 @@ namespace Strawberry
[Inline] [Inline]
public bool Check(Hitbox other) public bool Check(Hitbox other)
{ {
return other.Collidable && SceneHitbox.Intersects(other.SceneHitbox); return other.Collidable && other.Entity != Entity && SceneHitbox.Intersects(other.SceneHitbox);
} }
[Inline] [Inline]
public bool Check(Hitbox other, Point offset) public bool Check(Hitbox other, Point offset)
{ {
return other.Collidable && (SceneHitbox + offset).Intersects(other.SceneHitbox); return other.Collidable && other.Entity != Entity && (SceneHitbox + offset).Intersects(other.SceneHitbox);
} }
[Inline] [Inline]
public bool CheckOutside(Hitbox other, Point offset) public bool CheckOutside(Hitbox other, Point offset)
{ {
return other.Collidable && !SceneHitbox.Intersects(other.SceneHitbox) && (SceneHitbox + offset).Intersects(other.SceneHitbox); return other.Collidable && other.Entity != Entity && !SceneHitbox.Intersects(other.SceneHitbox) && (SceneHitbox + offset).Intersects(other.SceneHitbox);
} }
[Inline] [Inline]

View File

@ -24,7 +24,7 @@ namespace Strawberry
delete s; delete s;
} }
public override void Awake() protected override void Awake()
{ {
CallEnter(); CallEnter();
} }

View File

@ -0,0 +1,19 @@
using System;
namespace Strawberry
{
public class Updater : Component, IUpdate
{
private delegate void() update ~ delete _;
public this(delegate void() update)
{
this.update = update;
}
public void Update()
{
update?.Invoke();
}
}
}

View File

@ -7,9 +7,9 @@ namespace Strawberry
public Entity Entity { get; private set; } public Entity Entity { get; private set; }
public bool IsAwake { get; private set; } public bool IsAwake { get; private set; }
public virtual void Added() { } protected virtual void Added() { }
public virtual void Awake() { } protected virtual void Awake() { }
public virtual void End() { } protected virtual void End() { }
[Inline] [Inline]
public void Destroy() public void Destroy()

View File

@ -35,7 +35,7 @@ namespace Strawberry
{ {
for (var c in components) for (var c in components)
{ {
c.End(); c.[Friend]End();
c.[Friend]IsAwake = false; c.[Friend]IsAwake = false;
Scene.[Friend]UntrackComponent(c); Scene.[Friend]UntrackComponent(c);
} }
@ -49,7 +49,7 @@ namespace Strawberry
{ {
if (!c.[Friend]IsAwake) if (!c.[Friend]IsAwake)
{ {
c.Awake(); c.[Friend]Awake();
c.[Friend]IsAwake = true; c.[Friend]IsAwake = true;
} }
} }
@ -67,6 +67,11 @@ namespace Strawberry
Components Components
*/ */
public bool Has<T>() where T : Component
{
return First<T>() != null;
}
public T First<T>() where T : Component public T First<T>() where T : Component
{ {
for (let c in components) for (let c in components)
@ -75,7 +80,7 @@ namespace Strawberry
return null; return null;
} }
public ICollection<T> All<T>(ICollection<T> into) where T : Component public List<T> All<T>(List<T> into) where T : Component
{ {
for (let c in components) for (let c in components)
if (c is T) if (c is T)
@ -119,14 +124,14 @@ namespace Strawberry
components.Add(c); components.Add(c);
Scene.[Friend]TrackComponent(c); Scene.[Friend]TrackComponent(c);
c.[Friend]Entity = this; c.[Friend]Entity = this;
c.Added(); c.[Friend]Added();
} }
if (IsAwake) if (IsAwake)
{ {
for (var c in toAdd) for (var c in toAdd)
{ {
c.Awake(); c.[Friend]Awake();
c.[Friend]IsAwake = true; c.[Friend]IsAwake = true;
} }
} }

View File

@ -38,9 +38,16 @@ namespace Strawberry
public virtual void Update() public virtual void Update()
{ {
ForEach<IEarlyUpdate>(scope (u) => u.EarlyUpdate()); {
ForEach<IUpdate>(scope (u) => u.Update()); delegate void(IEarlyUpdate) early = scope (u) => u.EarlyUpdate();
ForEach<ILateUpdate>(scope (u) => u.LateUpdate()); delegate void(IUpdate) update = scope (u) => u.Update();
delegate void(ILateUpdate) late = scope (u) => u.LateUpdate();
ForEach<IEarlyUpdate>(early);
ForEach<IUpdate>(update);
ForEach<ILateUpdate>(late);
}
UpdateLists(); UpdateLists();
} }

View File

@ -11,7 +11,6 @@ namespace Strawberry
while (currentModule != null) while (currentModule != null)
{ {
let newModule = currentModule.[Friend]Run(); let newModule = currentModule.[Friend]Run();
delete currentModule;
currentModule = newModule; currentModule = newModule;
} }

View File

@ -4,14 +4,14 @@ namespace Strawberry
{ {
public struct Point : IHashable public struct Point : IHashable
{ {
static public readonly Point Right = .(1, 0); public const Point Right = .(1, 0);
static public readonly Point Left = .(-1, 0); public const Point Left = .(-1, 0);
static public readonly Point Up = .(0, -1); public const Point Up = .(0, -1);
static public readonly Point Down = .(0, 1); public const Point Down = .(0, 1);
static public readonly Point UnitX = .(1, 0); public const Point UnitX = .(1, 0);
static public readonly Point UnitY = .(0, 1); public const Point UnitY = .(0, 1);
static public readonly Point Zero = .(0, 0); public const Point Zero = .(0, 0);
static public readonly Point One = .(1, 1); public const Point One = .(1, 1);
public int X; public int X;
public int Y; public int Y;
@ -73,7 +73,7 @@ namespace Strawberry
return .((int32)a.X, (int32)a.Y); return .((int32)a.X, (int32)a.Y);
} }
[Inline] [Inline, Commutable]
static public bool operator==(Point a, Point b) static public bool operator==(Point a, Point b)
{ {
return a.X == b.X && a.Y == b.Y; return a.X == b.X && a.Y == b.Y;