diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c1c5e29 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ + +SampleGame/build/* diff --git a/SampleGame/BeefProj.toml b/SampleGame/BeefProj.toml new file mode 100644 index 0000000..a4abdd4 --- /dev/null +++ b/SampleGame/BeefProj.toml @@ -0,0 +1,8 @@ +FileVersion = 1 +Dependencies = {corlib = "*", SDL2 = "*", Strawberry = "*"} + +[Project] +Name = "SampleGame" +TargetType = "BeefGUIApplication" +StartupObject = "Strawberry.Sample.Program" +DefaultNamespace = "Strawberry.Sample" diff --git a/SampleGame/BeefSpace.toml b/SampleGame/BeefSpace.toml new file mode 100644 index 0000000..aa4639d --- /dev/null +++ b/SampleGame/BeefSpace.toml @@ -0,0 +1,5 @@ +FileVersion = 1 +Projects = {SampleGame = {Path = "."}, Strawberry = {Path = ".."}, SDL2 = "*"} + +[Workspace] +StartupProject = "SampleGame" diff --git a/SampleGame/BeefSpace_User.toml b/SampleGame/BeefSpace_User.toml new file mode 100644 index 0000000..14fe3af --- /dev/null +++ b/SampleGame/BeefSpace_User.toml @@ -0,0 +1,218 @@ +FileVersion = 1 +LastConfig = "Debug" +LastPlatform = "Win64" +RecentFilesList = ["c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\src\\Static\\Ease.bf", "c:\\Program Files\\BeefLang\\BeefLibs\\corlib\\src\\Action.bf", "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\SampleGame\\src\\MovingJumpThru.bf", "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\SampleGame\\src\\Player.bf", "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\src\\Struct\\Color.bf", "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\SampleGame\\src\\Level.bf", "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\src\\Physics\\JumpThru.bf", "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\src\\Components\\Timer.bf", "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\src\\Physics\\Actor.bf", "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\src\\Physics\\Solid.bf"] + +[MainWindow] +X = 64 +Y = 64 +Width = 1200 +Height = 1024 +ShowKind = "Maximized" + +[MainDockingFrame] +Type = "DockingFrame" +SplitType = 2 + +[[MainDockingFrame.DockedWidgets]] +RequestedWidth = 500.0 +RequestedHeight = 350.0 +SizePriority = 350.0 +Type = "DockingFrame" +SplitType = 1 + +[[MainDockingFrame.DockedWidgets.DockedWidgets]] +RequestedWidth = 350.0 +RequestedHeight = 350.0 +Type = "TabbedView" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +Active = true +TabLabel = "Workspace" +TabWidth = 111.7143 +Type = "ProjectPanel" + +[[MainDockingFrame.DockedWidgets.DockedWidgets]] +IsFillWidget = true +Permanent = true +RequestedWidth = 150.0 +RequestedHeight = 150.0 +SizePriority = 150.0 +DefaultDocumentsTabbedView = true +Type = "TabbedView" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "Action.bf" +TabWidth = 89.14286 +Type = "SourceViewPanel" +FilePath = "c:\\Program Files\\BeefLang\\BeefLibs\\corlib\\src\\Action.bf" +ProjectName = "corlib" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +Active = true +TabLabel = "Ease.bf" +TabWidth = 78.85714 +Type = "SourceViewPanel" +FilePath = "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\src\\Static\\Ease.bf" +CursorPos = 206 +ProjectName = "Strawberry" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "MovingJumpThru.bf" +TabWidth = 151.4286 +Type = "SourceViewPanel" +FilePath = "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\SampleGame\\src\\MovingJumpThru.bf" +CursorPos = 406 +ProjectName = "SampleGame" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "Color.bf" +TabWidth = 83.42857 +Type = "SourceViewPanel" +FilePath = "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\src\\Struct\\Color.bf" +CursorPos = 588 +ProjectName = "Strawberry" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "Timer.bf" +TabWidth = 85.14286 +Type = "SourceViewPanel" +FilePath = "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\src\\Components\\Timer.bf" +CursorPos = 530 +VertPos = 130.0 +ProjectName = "Strawberry" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "Actor.bf" +TabWidth = 82.85714 +Type = "SourceViewPanel" +FilePath = "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\src\\Physics\\Actor.bf" +CursorPos = 2066 +VertPos = 2522.0 +ProjectName = "Strawberry" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "JumpThru.bf" +TabWidth = 109.1429 +Type = "SourceViewPanel" +FilePath = "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\src\\Physics\\JumpThru.bf" +CursorPos = 1409 +VertPos = 1430.0 +ProjectName = "Strawberry" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "Solid.bf" +TabWidth = 81.71429 +Type = "SourceViewPanel" +FilePath = "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\src\\Physics\\Solid.bf" +CursorPos = 174 +ProjectName = "Strawberry" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "Controls.bf" +TabWidth = 90.57143 +Type = "SourceViewPanel" +FilePath = "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\SampleGame\\src\\Controls.bf" +CursorPos = 433 +ProjectName = "SampleGame" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "Player.bf" +TabWidth = 76.85714 +Type = "SourceViewPanel" +FilePath = "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\SampleGame\\src\\Player.bf" +CursorPos = 2419 +VertPos = 2180.5 +ProjectName = "SampleGame" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "Level.bf" +TabWidth = 72.85714 +Type = "SourceViewPanel" +FilePath = "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\SampleGame\\src\\Level.bf" +CursorPos = 190 +ProjectName = "SampleGame" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "SampleGame.bf" +TabWidth = 118.0 +Type = "SourceViewPanel" +FilePath = "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\SampleGame\\src\\SampleGame.bf" +CursorPos = 169 +ProjectName = "SampleGame" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "Program.bf" +TabWidth = 92.28571 +Type = "SourceViewPanel" +FilePath = "c:\\Users\\Matt\\Documents\\Projects\\Strawberry\\SampleGame\\src\\Program.bf" +CursorPos = 166 +ProjectName = "SampleGame" + +[[MainDockingFrame.DockedWidgets]] +RequestedWidth = 437.0 +RequestedHeight = 327.0 +Type = "DockingFrame" +SplitType = 1 + +[[MainDockingFrame.DockedWidgets.DockedWidgets]] +RequestedWidth = 437.0 +RequestedHeight = 437.0 +SizePriority = 2558.0 +Type = "TabbedView" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +Active = true +TabLabel = "Memory" +TabWidth = 98.0 +Type = "MemoryPanel" +AutoResize = "Auto_Mul8" +RequestedWidth = 300.0 + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "Watch" +TabWidth = 84.28571 +Type = "WatchPanel" +Columns = [{Width = 200.0}, {Width = 200.0}, {Width = 200.0}] + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "Auto" +TabWidth = 76.28571 +Type = "AutoWatchPanel" +Columns = [{Width = 200.0}, {Width = 200.0}, {Width = 200.0}] + +[[MainDockingFrame.DockedWidgets.DockedWidgets]] +RequestedWidth = 437.0 +RequestedHeight = 437.0 +SizePriority = 2558.0 +Type = "TabbedView" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "Find Results" +TabWidth = 114.5714 +Type = "FindResultsPanel" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "Threads" +TabWidth = 94.0 +Type = "ThreadPanel" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "Call Stack" +TabWidth = 102.0 +Type = "CallStackPanel" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +TabLabel = "Immediate" +TabWidth = 109.4286 +Type = "ImmediatePanel" + +[[MainDockingFrame.DockedWidgets.DockedWidgets.Tabs]] +Active = true +TabLabel = "Output" +TabWidth = 88.85714 +Type = "OutputPanel" + +[DebuggerDisplayTypes.""] +IntDisplayType = "Default" +MmDisplayType = "Default" diff --git a/SampleGame/src/Controls.bf b/SampleGame/src/Controls.bf new file mode 100644 index 0000000..f4e704c --- /dev/null +++ b/SampleGame/src/Controls.bf @@ -0,0 +1,22 @@ +namespace Strawberry.Sample +{ + static public class Controls + { + static public VirtualAxis MoveX; + static public VirtualButton Jump; + + static public void Init() + { + Jump = new VirtualButton() + .AddKey(.Space) + .AddKey(.X) + .AddButton(0, .A) + .PressBuffer(0.1f); + + MoveX = new VirtualAxis() + .AddKeys(.Left, .Right, .TakeNewer) + .AddButtons(0, .DpadLeft, .DpadRight, .TakeNewer) + .AddAxis(0, .LeftX, 0.3f); + } + } +} diff --git a/SampleGame/src/Level.bf b/SampleGame/src/Level.bf new file mode 100644 index 0000000..69bb0ba --- /dev/null +++ b/SampleGame/src/Level.bf @@ -0,0 +1,13 @@ +namespace Strawberry.Sample +{ + public class Level : Scene + { + public this() + { + Add(new Player(.(50, 50))); + Add(new Solid(.(0, 168), .(0, 0, 320, 12))); + Add(new JumpThru(.(200, 132), 48)); + Add(new MovingJumpThru(.(136, 100), 32, .(124, 140), 2f)); + } + } +} diff --git a/SampleGame/src/MovingJumpThru.bf b/SampleGame/src/MovingJumpThru.bf new file mode 100644 index 0000000..0aa7517 --- /dev/null +++ b/SampleGame/src/MovingJumpThru.bf @@ -0,0 +1,50 @@ +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); + } + } +} diff --git a/SampleGame/src/Player.bf b/SampleGame/src/Player.bf new file mode 100644 index 0000000..da27f86 --- /dev/null +++ b/SampleGame/src/Player.bf @@ -0,0 +1,108 @@ +using System; + +namespace Strawberry.Sample +{ + public class Player : Actor + { + public Vector Speed; + + private Timer tJumpGrace; + private Timer tVarJump; + + public this(Point pos) + : base(pos) + { + Hitbox = Rect(-4, -8, 8, 8); + + Add(tJumpGrace = new Timer()); + Add(tVarJump = new Timer()); + } + + public override 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; + const float jumpXBoost = 30; // If left or right is held at the moment of a jump, this horizontal speed boost is applied + const float maxFall = 160; + const float gravity = 1000; + const float halfGravThreshold = 40; // Halves gravity at the peak of a jump, if the jump button is held + const float maxRun = 100; + const float runAccel = 800; + const float runAccelAirMult = 0.8f; // Gives you slightly less control of horizontal motion in the air + + let onGround = GroundCheck(); + if (onGround) + tJumpGrace.Value = coyoteTime; + + //Vertical Control + { + //Jumping + if (tJumpGrace && Controls.Jump.Pressed) + { + Controls.Jump.ClearPressBuffer(); + tJumpGrace.Clear(); + tVarJump.Value = varJumpTime; + Speed.Y = jumpSpeed; + Speed.X += jumpXBoost * Controls.MoveX.Valuei; + } + else + { + //Gravity + { + float mult; + if (Controls.Jump.Check && Math.Abs(Speed.Y) <= halfGravThreshold) + mult = 0.5f; + else + mult = 1; + + Speed.Y = Calc.Approach(Speed.Y, maxFall, gravity * mult * Time.Delta); + } + + //Variable Jumping + if (tVarJump) + { + if (Controls.Jump.Check) + Speed.Y = jumpSpeed; + else + tVarJump.Clear(); + } + } + } + + //Horizontal Control + { + float accel = runAccel; + if (!onGround) + accel *= runAccelAirMult; + + Speed.X = Calc.Approach(Speed.X, Controls.MoveX.Valuei * maxRun, accel * Time.Delta); + } + + //Resolve Speed + MoveX(Speed.X * Time.Delta, scope => OnCollideX); + MoveY(Speed.Y * Time.Delta, scope => OnCollideY); + } + + private void OnCollideX(Collision col) + { + Speed.X = 0; + ZeroRemainderX(); + } + + private void OnCollideY(Collision col) + { + Speed.Y = 0; + ZeroRemainderY(); + } + + public override void Draw() + { + base.Draw(); + + DrawHitbox(.Red); + } + } +} diff --git a/SampleGame/src/Program.bf b/SampleGame/src/Program.bf new file mode 100644 index 0000000..ee925e1 --- /dev/null +++ b/SampleGame/src/Program.bf @@ -0,0 +1,14 @@ +using System; + +namespace Strawberry.Sample +{ + static public class Program + { + static public int Main(String[] args) + { + let game = scope SampleGame(); + game.Run(); + return 0; + } + } +} diff --git a/SampleGame/src/SampleGame.bf b/SampleGame/src/SampleGame.bf new file mode 100644 index 0000000..b5ede44 --- /dev/null +++ b/SampleGame/src/SampleGame.bf @@ -0,0 +1,14 @@ +using System; + +namespace Strawberry.Sample +{ + public class SampleGame : Game + { + public this() + : base("Strawberry Sample Game!", 320, 180, 3) + { + Controls.Init(); + Scene = new Level(); + } + } +} diff --git a/src/Components/Timer.bf b/src/Components/Timer.bf index b3bb3bf..a52f25d 100644 --- a/src/Components/Timer.bf +++ b/src/Components/Timer.bf @@ -26,11 +26,13 @@ namespace Strawberry public float Value { + [Inline] get { return value; } + [Inline] set { this.value = Math.Max(0, value); @@ -38,6 +40,13 @@ namespace Strawberry } } + [Inline] + public void Clear() + { + value = 0; + Active = false; + } + public override void Update() { if (value > 0) @@ -54,5 +63,10 @@ namespace Strawberry } } } + + static public implicit operator bool(Timer timer) + { + return timer.value > 0; + } } } diff --git a/src/Physics/Actor.bf b/src/Physics/Actor.bf index 6c8b05b..0811d73 100644 --- a/src/Physics/Actor.bf +++ b/src/Physics/Actor.bf @@ -77,8 +77,6 @@ namespace Strawberry let hit = First(.(sign, 0)); if (hit != null) { - ZeroRemainderX(); - let c = Collision( Point.Right * sign, Math.Abs(amount), @@ -110,8 +108,6 @@ namespace Strawberry if (hit != null) { - ZeroRemainderY(); - let c = Collision( Point.Right * sign, Math.Abs(amount), diff --git a/src/Physics/Geometry.bf b/src/Physics/Geometry.bf index 9de8813..e4377b9 100644 --- a/src/Physics/Geometry.bf +++ b/src/Physics/Geometry.bf @@ -35,6 +35,32 @@ namespace Strawberry } } + [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 GetRiders(List into); diff --git a/src/Physics/JumpThru.bf b/src/Physics/JumpThru.bf index 0db1b1f..d508a06 100644 --- a/src/Physics/JumpThru.bf +++ b/src/Physics/JumpThru.bf @@ -6,14 +6,7 @@ namespace Strawberry public this(Point position, int width) : base(position) { - Hitbox = Rect(0, 0, width, 6); - } - - public override void Update() - { - base.Update(); - - MoveY(-10 * Time.Delta); + Hitbox = Rect(0, 0, width, 2); } public override void MoveExactX(int amount) @@ -80,7 +73,7 @@ namespace Strawberry public override void Draw() { - DrawHitbox(.(255, 255, 255, 255)); + DrawHitbox(.LightGray); } } } diff --git a/src/Physics/Solid.bf b/src/Physics/Solid.bf index 1ea1a4b..43fd2b7 100644 --- a/src/Physics/Solid.bf +++ b/src/Physics/Solid.bf @@ -10,13 +10,6 @@ namespace Strawberry Hitbox = hitbox; } - public override void Update() - { - base.Update(); - - MoveY(0.1f); - } - public override List GetRiders(List into) { for (var a in Scene.All(scope List)) diff --git a/src/Static/Ease.bf b/src/Static/Ease.bf new file mode 100644 index 0000000..53424bf --- /dev/null +++ b/src/Static/Ease.bf @@ -0,0 +1,36 @@ +using System; + +namespace Strawberry +{ + static public class Ease + { + public delegate float Easer(float t); + + static public float CubeIn(float t) + { + return t * t * t; + } + + static public float CubeOut(float t) + { + return Invert(t, scope => CubeIn); + } + + static public float CubeInOut(float t) + { + return Follow(t, scope => CubeIn, scope => CubeOut); + } + + [Inline] + static public float Invert(float t, Easer easer) + { + return 1 - easer(1 - t); + } + + [Inline] + static public float Follow(float t, Easer a, Easer b) + { + return (t <= 0.5f) ? a(t * 2) / 2 : b(t * 2 - 1) / 2 + 0.5f; + } + } +} diff --git a/src/Struct/Color.bf b/src/Struct/Color.bf index dd47059..97fd278 100644 --- a/src/Struct/Color.bf +++ b/src/Struct/Color.bf @@ -13,6 +13,9 @@ namespace Strawberry static public readonly Color Cyan = 0xFF00FFFF; static public readonly Color Magenta = 0xFFFF00FF; static public readonly Color Yellow = 0x00FFFFFF; + static public readonly Color DarkGray = 0x3F3F3FFF; + static public readonly Color Gray = 0x7F7F7FFF; + static public readonly Color LightGray = 0xBFBFBFFF; public uint8 R; public uint8 G; diff --git a/src/Struct/Vector.bf b/src/Struct/Vector.bf index 795945f..4033892 100644 --- a/src/Struct/Vector.bf +++ b/src/Struct/Vector.bf @@ -51,6 +51,16 @@ namespace Strawberry return Point((int)Math.Round(X), (int)Math.Round(Y)); } + static public Vector Lerp(Vector a, Vector b, float t) + { + if (t == 0) + return a; + else if (t == 1) + return b; + else + return a + (b - a) * t; + } + public override void ToString(String strBuffer) { strBuffer.Set("Vector [ ");