From c0badd01d4a34c08194c88320339d1eafad385f4 Mon Sep 17 00:00:00 2001 From: Joanna May Date: Sat, 16 Mar 2024 15:39:23 -0500 Subject: [PATCH] wip: upgrade to logic blocks v5 syntax --- GameDemo.csproj | 8 +++- src/app/App.cs | 16 +++---- src/app/state/AppLogic.State.cs | 8 ++-- src/app/state/AppLogic.cs | 4 +- src/app/state/states/InGame.cs | 14 ++++--- src/app/state/states/LeavingGame.cs | 6 +-- src/app/state/states/LeavingMenu.cs | 9 ++-- src/app/state/states/MainMenu.cs | 12 +++--- src/app/state/states/SplashScreen.cs | 10 ++--- src/coin/Coin.cs | 11 ++--- src/coin/state/CoinLogic.State.cs | 6 ++- src/coin/state/CoinLogic.cs | 2 +- .../states/CoinLogic.State.Collecting.cs | 18 ++++---- src/coin/state/states/CoinLogic.State.Idle.cs | 4 +- src/game/Game.cs | 40 +++++++++--------- src/game/state/GameLogic.State.cs | 10 +++-- src/game/state/GameLogic.cs | 2 +- src/game/state/states/Lost.cs | 9 ++-- src/game/state/states/MenuBackdrop.cs | 13 +++--- src/game/state/states/Paused.Saving.cs | 18 ++++---- src/game/state/states/Paused.cs | 23 +++++----- src/game/state/states/Playing.cs | 17 ++++---- src/game/state/states/Quit.cs | 6 ++- src/game/state/states/RestartingGame.cs | 6 ++- src/game/state/states/Resuming.cs | 10 ++--- src/game/state/states/Won.cs | 8 ++-- src/in_game_audio/InGameAudio.cs | 26 +++++------- .../state/InGameAudioLogic.State.cs | 28 +++++++------ src/in_game_audio/state/InGameAudioLogic.cs | 2 +- src/in_game_ui/InGameUI.cs | 11 ++--- src/in_game_ui/state/InGameUILogic.State.cs | 14 ++++--- src/in_game_ui/state/InGameUILogic.cs | 2 +- src/jumpshroom/Jumpshroom.cs | 10 +++-- src/jumpshroom/state/JumpshroomLogic.State.cs | 4 +- src/jumpshroom/state/JumpshroomLogic.cs | 2 +- .../states/JumpshroomLogic.State.Cooldown.cs | 6 +-- .../states/JumpshroomLogic.State.Idle.cs | 2 +- .../states/JumpshroomLogic.State.Launching.cs | 6 +-- .../states/JumpshroomLogic.State.Loading.cs | 7 ++-- src/menu/splash/Splash.cs | 2 +- src/player/Player.cs | 14 +++---- src/player/PlayerModel.cs | 22 +++++----- src/player/state/PlayerLogic.State.cs | 6 ++- src/player/state/PlayerLogic.cs | 2 +- ...layerLogic.State.Alive.Airborne.Falling.cs | 6 +-- ...layerLogic.State.Alive.Airborne.Jumping.cs | 16 +++---- ...layerLogic.State.Alive.Airborne.Liftoff.cs | 6 +-- .../PlayerLogic.State.Alive.Airborne.cs | 4 +- .../PlayerLogic.State.Alive.Grounded.Idle.cs | 9 ++-- ...PlayerLogic.State.Alive.Grounded.Moving.cs | 8 ++-- .../PlayerLogic.State.Alive.Grounded.cs | 10 ++--- .../state/states/PlayerLogic.State.Alive.cs | 42 +++++++++---------- .../states/PlayerLogic.State.Disabled.cs | 12 +++--- src/player_camera/PlayerCamera.cs | 24 ++++++----- .../State/PlayerCameraLogic.State.cs | 39 ++++++++--------- src/player_camera/State/PlayerCameraLogic.cs | 2 +- .../PlayerCameraLogic.State.InputDisabled.cs | 2 +- .../PlayerCameraLogic.State.InputEnabled.cs | 8 ++-- test/src/coin/CoinTest.cs | 4 +- test/src/jumpshroom/JumpshroomTest.cs | 6 ++- test/src/player/PlayerTest.cs | 16 ++++--- test/src/player_camera/PlayerCameraTest.cs | 6 ++- 62 files changed, 360 insertions(+), 316 deletions(-) diff --git a/GameDemo.csproj b/GameDemo.csproj index b1743ab..1880b7c 100644 --- a/GameDemo.csproj +++ b/GameDemo.csproj @@ -40,8 +40,12 @@ - - + + + + + diff --git a/src/app/App.cs b/src/app/App.cs index 7c1ee02..c5d7294 100644 --- a/src/app/App.cs +++ b/src/app/App.cs @@ -68,27 +68,27 @@ public void OnReady() { AppBinding = AppLogic.Bind(); AppBinding - .Handle(_ => { + .Handle((in AppLogic.Output.ShowSplashScreen _) => { HideMenus(); BlankScreen.Hide(); Splash.Show(); }) - .Handle(_ => { + .Handle((in AppLogic.Output.HideSplashScreen _) => { BlankScreen.Show(); FadeToBlack(); }) - .Handle(_ => { + .Handle((in AppLogic.Output.RemoveExistingGame _) => { GamePreview.RemoveChildEx(Game); Game.QueueFree(); Game = default!; }) - .Handle(_ => { + .Handle((in AppLogic.Output.LoadGame _) => { Game = Instantiator.LoadAndInstantiate(GAME_SCENE_PATH); GamePreview.AddChildEx(Game); Instantiator.SceneTree.Paused = false; }) - .Handle(_ => { + .Handle((in AppLogic.Output.ShowMainMenu _) => { // Load everything while we're showing a black screen, then fade in. HideMenus(); Menu.Show(); @@ -96,12 +96,12 @@ public void OnReady() { FadeInFromBlack(); }) - .Handle(_ => FadeToBlack()) - .Handle(_ => { + .Handle((in AppLogic.Output.FadeToBlack _) => FadeToBlack()) + .Handle((in AppLogic.Output.ShowGame _) => { HideMenus(); FadeInFromBlack(); }) - .Handle(_ => FadeToBlack()); + .Handle((in AppLogic.Output.HideGame _) => FadeToBlack()); // Enter the first state to kick off the binding side effects. AppLogic.Start(); diff --git a/src/app/state/AppLogic.State.cs b/src/app/state/AppLogic.State.cs index 17cc5ad..2151057 100644 --- a/src/app/state/AppLogic.State.cs +++ b/src/app/state/AppLogic.State.cs @@ -1,9 +1,9 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class AppLogic { - public interface IState : IStateLogic { - } + public interface IState : IStateLogic; - public abstract partial record State : StateLogic, IState { - } + public abstract partial record State : StateLogic, IState; } diff --git a/src/app/state/AppLogic.cs b/src/app/state/AppLogic.cs index 03c2d5c..5bc2fa0 100644 --- a/src/app/state/AppLogic.cs +++ b/src/app/state/AppLogic.cs @@ -3,9 +3,9 @@ namespace GameDemo; using Chickensoft.LogicBlocks; using Chickensoft.LogicBlocks.Generator; -public interface IAppLogic : ILogicBlock { } +public interface IAppLogic : ILogicBlock; -[StateMachine] +[StateDiagram(typeof(State))] public partial class AppLogic : LogicBlock, IAppLogic { public override IState GetInitialState() => new State.SplashScreen(); diff --git a/src/app/state/states/InGame.cs b/src/app/state/states/InGame.cs index fae245e..cfcf3c8 100644 --- a/src/app/state/states/InGame.cs +++ b/src/app/state/states/InGame.cs @@ -1,26 +1,28 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class AppLogic { public partial record State { public record InGame : State, IGet { public InGame() { - OnEnter(_ => { + this.OnEnter(() => { Get().OnEnterGame(); - Context.Output(new Output.ShowGame()); + Output(new Output.ShowGame()); }); - OnExit(_ => Context.Output(new Output.HideGame())); + this.OnExit(() => Output(new Output.HideGame())); OnAttach(() => Get().GameExited += OnGameExited); OnDetach(() => Get().GameExited -= OnGameExited); } public void OnRestartGameRequested() => - Context.Input(new Input.EndGame(PostGameAction.RestartGame)); + Input(new Input.EndGame(PostGameAction.RestartGame)); public void OnGameExited(PostGameAction reason) => - Context.Input(new Input.EndGame(reason)); + Input(new Input.EndGame(reason)); - public IState On(Input.EndGame input) => + public IState On(in Input.EndGame input) => new LeavingGame(input.PostGameAction); } } diff --git a/src/app/state/states/LeavingGame.cs b/src/app/state/states/LeavingGame.cs index 13a50e7..d6f56d4 100644 --- a/src/app/state/states/LeavingGame.cs +++ b/src/app/state/states/LeavingGame.cs @@ -9,17 +9,17 @@ public LeavingGame(PostGameAction postGameAction) { PostGameAction = postGameAction; } - public IState On(Input.FadeOutFinished input) { + public IState On(in Input.FadeOutFinished input) { // We are either supposed to restart the game or go back to the main // menu. More complex games might have more post-game destinations, // but it's pretty simple for us. - Context.Output(new Output.RemoveExistingGame()); + Output(new Output.RemoveExistingGame()); if (PostGameAction is not PostGameAction.RestartGame) { return new MainMenu(); } - Context.Output(new Output.LoadGame()); + Output(new Output.LoadGame()); return new InGame(); } } diff --git a/src/app/state/states/LeavingMenu.cs b/src/app/state/states/LeavingMenu.cs index 55e14f2..49c3581 100644 --- a/src/app/state/states/LeavingMenu.cs +++ b/src/app/state/states/LeavingMenu.cs @@ -1,16 +1,15 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class AppLogic { public partial record State { public record LeavingMenu : State, IGet { public LeavingMenu() { - OnEnter( - previous => Context.Output(new Output.FadeToBlack()) - ); + this.OnEnter(() => Output(new Output.FadeToBlack())); } - public IState On(Input.FadeOutFinished input) => - new InGame(); + public IState On(in Input.FadeOutFinished input) => new InGame(); } } } diff --git a/src/app/state/states/MainMenu.cs b/src/app/state/states/MainMenu.cs index 382e3a3..b1291f6 100644 --- a/src/app/state/states/MainMenu.cs +++ b/src/app/state/states/MainMenu.cs @@ -1,19 +1,21 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class AppLogic { public partial record State { public record MainMenu : State, IGet { public MainMenu() { - OnEnter( - previous => { - Context.Output(new Output.LoadGame()); + this.OnEnter( + () => { + Output(new Output.LoadGame()); Get().OnMainMenuEntered(); - Context.Output(new Output.ShowMainMenu()); + Output(new Output.ShowMainMenu()); } ); } - public IState On(Input.StartGame input) => new LeavingMenu(); + public IState On(in Input.StartGame input) => new LeavingMenu(); } } } diff --git a/src/app/state/states/SplashScreen.cs b/src/app/state/states/SplashScreen.cs index 1146a40..b66b304 100644 --- a/src/app/state/states/SplashScreen.cs +++ b/src/app/state/states/SplashScreen.cs @@ -1,12 +1,12 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class AppLogic { public partial record State { public record SplashScreen : State, IGet { public SplashScreen() { - OnEnter( - (previous) => Context.Output(new Output.ShowSplashScreen()) - ); + this.OnEnter(() => Output(new Output.ShowSplashScreen())); OnAttach( () => Get().SplashScreenSkipped += OnSplashScreenSkipped @@ -17,10 +17,10 @@ public SplashScreen() { ); } - public IState On(Input.FadeOutFinished input) => new MainMenu(); + public IState On(in Input.FadeOutFinished input) => new MainMenu(); public void OnSplashScreenSkipped() => - Context.Output(new Output.HideSplashScreen()); + Output(new Output.HideSplashScreen()); } } } diff --git a/src/coin/Coin.cs b/src/coin/Coin.cs index 2d11717..39ca008 100644 --- a/src/coin/Coin.cs +++ b/src/coin/Coin.cs @@ -70,7 +70,7 @@ public void OnResolved() { CoinBinding = CoinLogic.Bind(); CoinBinding - .When().Call(state => { + .When(state => { // We want to start receiving physics ticks so we can orient ourselves // toward the entity that's collecting us. SetPhysicsProcess(true); @@ -80,13 +80,14 @@ public void OnResolved() { }); CoinBinding - .Handle( - output => GlobalPosition = output.GlobalPosition + .Handle( + (in CoinLogic.Output.Move output) => + GlobalPosition = output.GlobalPosition ) - .Handle( + .Handle( // We're done being collected, so we can remove ourselves from the // scene tree. - output => QueueFree() + (in CoinLogic.Output.SelfDestruct output) => QueueFree() ); } diff --git a/src/coin/state/CoinLogic.State.cs b/src/coin/state/CoinLogic.State.cs index 1b6414e..629db88 100644 --- a/src/coin/state/CoinLogic.State.cs +++ b/src/coin/state/CoinLogic.State.cs @@ -1,7 +1,9 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class CoinLogic { - public interface IState : IStateLogic { } + public interface IState : IStateLogic; - public abstract partial record State : StateLogic, IState; + public abstract partial record State : StateLogic, IState; } diff --git a/src/coin/state/CoinLogic.cs b/src/coin/state/CoinLogic.cs index 356419c..29e3b2d 100644 --- a/src/coin/state/CoinLogic.cs +++ b/src/coin/state/CoinLogic.cs @@ -6,7 +6,7 @@ namespace GameDemo; public interface ICoinLogic : ILogicBlock { } -[StateMachine] +[StateDiagram(typeof(State))] public partial class CoinLogic : LogicBlock, ICoinLogic { public override IState GetInitialState() => new State.Idle(); diff --git a/src/coin/state/states/CoinLogic.State.Collecting.cs b/src/coin/state/states/CoinLogic.State.Collecting.cs index c72c005..d5e9a7d 100644 --- a/src/coin/state/states/CoinLogic.State.Collecting.cs +++ b/src/coin/state/states/CoinLogic.State.Collecting.cs @@ -1,5 +1,7 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class CoinLogic { public partial record State { public interface ICollecting : IState { @@ -12,22 +14,20 @@ public record Collecting : State, ICollecting, IGet { public Collecting(ICoinCollector target) { Target = target; - OnEnter( - previous => Get().StartCoinCollection(Get()) - ); + this.OnEnter(() => Get().StartCoinCollection(Get())); } - public IState On(Input.PhysicsProcess input) { - var settings = Context.Get(); + public IState On(in Input.PhysicsProcess input) { + var settings = Get(); var collectionTime = settings.CollectionTimeInSeconds; _elapsedTime += (float)input.Delta; if (_elapsedTime >= collectionTime) { - Context.Output(new Output.SelfDestruct()); + Output(new Output.SelfDestruct()); - var coin = Context.Get(); - var gameRepo = Context.Get(); + var coin = Get(); + var gameRepo = Get(); gameRepo.OnFinishCoinCollection(coin); } @@ -36,7 +36,7 @@ public IState On(Input.PhysicsProcess input) { Target.CenterOfMass, (float)(_elapsedTime / collectionTime) ); - Context.Output(new Output.Move(nextPosition)); + Output(new Output.Move(nextPosition)); return this; } } diff --git a/src/coin/state/states/CoinLogic.State.Idle.cs b/src/coin/state/states/CoinLogic.State.Idle.cs index c4a3229..b254c09 100644 --- a/src/coin/state/states/CoinLogic.State.Idle.cs +++ b/src/coin/state/states/CoinLogic.State.Idle.cs @@ -2,10 +2,10 @@ namespace GameDemo; public partial class CoinLogic { public partial record State { - public interface IIdle : IState { } + public interface IIdle : IState; public record Idle : State, IIdle, IGet { - public IState On(Input.StartCollection input) => new Collecting( + public IState On(in Input.StartCollection input) => new Collecting( input.Target ); } diff --git a/src/game/Game.cs b/src/game/Game.cs index f770d39..158ed54 100644 --- a/src/game/Game.cs +++ b/src/game/Game.cs @@ -73,41 +73,43 @@ public void Setup() { public void OnResolved() { GameBinding = GameLogic.Bind(); GameBinding - .Handle( - _ => { + .Handle( + (in GameLogic.Output.StartGame _) => { PlayerCamera.UsePlayerCamera(); InGameUi.Show(); }) - .Handle( - output => GetTree().Paused = output.IsPaused + .Handle( + (in GameLogic.Output.SetPauseMode output) => + GetTree().Paused = output.IsPaused ) - .Handle( - output => Input.MouseMode = output.IsMouseCaptured - ? Input.MouseModeEnum.Captured - : Input.MouseModeEnum.Visible + .Handle( + (in GameLogic.Output.CaptureMouse output) => + Input.MouseMode = output.IsMouseCaptured + ? Input.MouseModeEnum.Captured + : Input.MouseModeEnum.Visible ) - .Handle(_ => { + .Handle((in GameLogic.Output.ShowLostScreen _) => { DeathMenu.Show(); DeathMenu.FadeIn(); DeathMenu.Animate(); }) - .Handle(_ => DeathMenu.FadeOut()) - .Handle(_ => { + .Handle((in GameLogic.Output.ExitLostScreen _) => DeathMenu.FadeOut()) + .Handle((in GameLogic.Output.ShowPauseMenu _) => { PauseMenu.Show(); PauseMenu.FadeIn(); }) - .Handle(_ => { + .Handle((in GameLogic.Output.ShowWonScreen _) => { WinMenu.Show(); WinMenu.FadeIn(); }) - .Handle(_ => WinMenu.FadeOut()) - .Handle(_ => PauseMenu.FadeOut()) - .Handle(_ => PauseMenu.Hide()) - .Handle( - _ => PauseMenu.OnSaveStarted() + .Handle((in GameLogic.Output.ExitWonScreen _) => WinMenu.FadeOut()) + .Handle((in GameLogic.Output.ExitPauseMenu _) => PauseMenu.FadeOut()) + .Handle((in GameLogic.Output.HidePauseMenu _) => PauseMenu.Hide()) + .Handle((in GameLogic.Output.ShowPauseSaveOverlay _) => + PauseMenu.OnSaveStarted() ) - .Handle( - _ => PauseMenu.OnSaveFinished() + .Handle((in GameLogic.Output.HidePauseSaveOverlay _) => + PauseMenu.OnSaveFinished() ); // Trigger the first state's OnEnter callbacks so our bindings run. diff --git a/src/game/state/GameLogic.State.cs b/src/game/state/GameLogic.State.cs index 507b581..f20e64f 100644 --- a/src/game/state/GameLogic.State.cs +++ b/src/game/state/GameLogic.State.cs @@ -1,10 +1,12 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class GameLogic { - public interface IState : IStateLogic { + public interface IState : IStateLogic { } - public abstract partial record State : StateLogic, IState { + public abstract partial record State : StateLogic, IState { protected State() { OnAttach(() => { var gameRepo = Get(); @@ -19,9 +21,9 @@ protected State() { } public void OnIsMouseCaptured(bool isMouseCaptured) => - Context.Output(new Output.CaptureMouse(isMouseCaptured)); + Output(new Output.CaptureMouse(isMouseCaptured)); public void OnIsPaused(bool isPaused) => - Context.Output(new Output.SetPauseMode(isPaused)); + Output(new Output.SetPauseMode(isPaused)); } } diff --git a/src/game/state/GameLogic.cs b/src/game/state/GameLogic.cs index 3ae43e1..9e944c6 100644 --- a/src/game/state/GameLogic.cs +++ b/src/game/state/GameLogic.cs @@ -6,7 +6,7 @@ namespace GameDemo; public interface IGameLogic : ILogicBlock { } -[StateMachine] +[StateDiagram(typeof(State))] public partial class GameLogic : LogicBlock, IGameLogic { public override IState GetInitialState() => new State.MenuBackdrop(); diff --git a/src/game/state/states/Lost.cs b/src/game/state/states/Lost.cs index 0b3172e..5cf2003 100644 --- a/src/game/state/states/Lost.cs +++ b/src/game/state/states/Lost.cs @@ -1,15 +1,16 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class GameLogic { public partial record State { public record Lost : State, IGet, IGet { public Lost() { - OnEnter( - _ => Context.Output(new Output.ShowLostScreen())); + this.OnEnter(() => Output(new Output.ShowLostScreen())); } - public IState On(Input.Start input) => new RestartingGame(); - public IState On(Input.GoToMainMenu input) => new Quit(); + public IState On(in Input.Start input) => new RestartingGame(); + public IState On(in Input.GoToMainMenu input) => new Quit(); } } } diff --git a/src/game/state/states/MenuBackdrop.cs b/src/game/state/states/MenuBackdrop.cs index 5834a85..fc5d09e 100644 --- a/src/game/state/states/MenuBackdrop.cs +++ b/src/game/state/states/MenuBackdrop.cs @@ -1,20 +1,23 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class GameLogic { public partial record State { - public record MenuBackdrop : State, IGet, IGet { + public record MenuBackdrop : State, + IGet, IGet { public MenuBackdrop() { - OnEnter(_ => Get().SetIsMouseCaptured(false)); + this.OnEnter(() => Get().SetIsMouseCaptured(false)); OnAttach(() => Get().GameEntered += OnGameEntered); OnDetach(() => Get().GameEntered -= OnGameEntered); } - public void OnGameEntered() => Context.Input(new Input.Start()); + public void OnGameEntered() => Input(new Input.Start()); - public IState On(Input.Start input) => new Playing(); + public IState On(in Input.Start input) => new Playing(); - public IState On(Input.Initialize input) { + public IState On(in Input.Initialize input) { Get().SetNumCoinsAtStart(input.NumCoinsInWorld); return this; } diff --git a/src/game/state/states/Paused.Saving.cs b/src/game/state/states/Paused.Saving.cs index 862854f..83d6969 100644 --- a/src/game/state/states/Paused.Saving.cs +++ b/src/game/state/states/Paused.Saving.cs @@ -1,5 +1,7 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class GameLogic { public partial record State { public record Saving : Paused, IGet { @@ -7,26 +9,24 @@ public Saving() { OnAttach(() => Get().SaveCompleted += OnSaveCompleted); OnDetach(() => Get().SaveCompleted -= OnSaveCompleted); - OnEnter( - previous => { - Context.Output(new Output.ShowPauseSaveOverlay()); + this.OnEnter( + () => { + Output(new Output.ShowPauseSaveOverlay()); Get().Save(); } ); - OnExit( - next => Context.Output(new Output.HidePauseSaveOverlay()) - ); + this.OnExit(() => Output(new Output.HidePauseSaveOverlay())); } public void OnSaveCompleted() => - Context.Input(new Input.SaveCompleted()); + Input(new Input.SaveCompleted()); - public IState On(Input.SaveCompleted input) + public IState On(in Input.SaveCompleted input) => new Paused(); // Make it impossible to leave the pause menu while saving - public override IState On(Input.PauseButtonPressed input) => this; + public override IState On(in Input.PauseButtonPressed input) => this; } } } diff --git a/src/game/state/states/Paused.cs b/src/game/state/states/Paused.cs index 674f47a..aabb151 100644 --- a/src/game/state/states/Paused.cs +++ b/src/game/state/states/Paused.cs @@ -1,29 +1,32 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class GameLogic { public partial record State { public record Paused : State, - IGet, IGet, IGet { + IGet, + IGet, + IGet { public Paused() { - OnEnter( - _ => { + this.OnEnter( + () => { Get().Pause(); - Context.Output(new Output.ShowPauseMenu()); + Output(new Output.ShowPauseMenu()); } ); + // We don't resume on exit because we can leave this state for // a menu and we want to remain paused. - OnExit( - _ => Context.Output(new Output.ExitPauseMenu()) - ); + this.OnExit(() => Output(new Output.ExitPauseMenu())); } - public virtual IState On(Input.PauseButtonPressed input) + public virtual IState On(in Input.PauseButtonPressed input) => new Resuming(); - public IState On(Input.SaveRequested input) => new Saving(); + public IState On(in Input.SaveRequested input) => new Saving(); - public IState On(Input.GoToMainMenu input) => new Quit(); + public IState On(in Input.GoToMainMenu input) => new Quit(); } } } diff --git a/src/game/state/states/Playing.cs b/src/game/state/states/Playing.cs index 92579a8..fd4b044 100644 --- a/src/game/state/states/Playing.cs +++ b/src/game/state/states/Playing.cs @@ -1,12 +1,15 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class GameLogic { public partial record State { - public record Playing : State, IGet, IGet { + public record Playing : State, + IGet, IGet { public Playing() { - OnEnter( - _ => { - Context.Output(new Output.StartGame()); + this.OnEnter( + () => { + Output(new Output.StartGame()); Get().SetIsMouseCaptured(true); } ); @@ -16,9 +19,9 @@ public Playing() { } public void OnEnded(GameOverReason reason) - => Context.Input(new Input.EndGame(reason)); + => Input(new Input.EndGame(reason)); - public IState On(Input.EndGame input) { + public IState On(in Input.EndGame input) { Get().Pause(); return input.Reason switch { @@ -28,7 +31,7 @@ public IState On(Input.EndGame input) { }; } - public IState On(Input.PauseButtonPressed input) => new Paused(); + public IState On(in Input.PauseButtonPressed input) => new Paused(); } } } diff --git a/src/game/state/states/Quit.cs b/src/game/state/states/Quit.cs index bd094d6..263b57c 100644 --- a/src/game/state/states/Quit.cs +++ b/src/game/state/states/Quit.cs @@ -1,11 +1,13 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class GameLogic { public partial record State { public record Quit : State { public Quit() { - OnEnter( - _ => Get().OnExitGame(PostGameAction.GoToMainMenu) + this.OnEnter( + () => Get().OnExitGame(PostGameAction.GoToMainMenu) ); } } diff --git a/src/game/state/states/RestartingGame.cs b/src/game/state/states/RestartingGame.cs index 8d20639..a7a510b 100644 --- a/src/game/state/states/RestartingGame.cs +++ b/src/game/state/states/RestartingGame.cs @@ -1,11 +1,13 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class GameLogic { public partial record State { public record RestartingGame : State { public RestartingGame() { - OnEnter( - _ => Get().OnExitGame(PostGameAction.RestartGame)); + this.OnEnter( + () => Get().OnExitGame(PostGameAction.RestartGame)); } } } diff --git a/src/game/state/states/Resuming.cs b/src/game/state/states/Resuming.cs index 57498b5..45acedd 100644 --- a/src/game/state/states/Resuming.cs +++ b/src/game/state/states/Resuming.cs @@ -1,16 +1,16 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class GameLogic { public partial record State { public record Resuming : State, IGet { public Resuming() { - OnEnter(previous => Get().Resume()); - OnExit( - next => Context.Output(new Output.HidePauseMenu()) - ); + this.OnEnter(() => Get().Resume()); + this.OnExit(() => Output(new Output.HidePauseMenu())); } - public IState On(Input.PauseMenuTransitioned input) => + public IState On(in Input.PauseMenuTransitioned input) => new Playing(); } } diff --git a/src/game/state/states/Won.cs b/src/game/state/states/Won.cs index eea43d8..6fe3187 100644 --- a/src/game/state/states/Won.cs +++ b/src/game/state/states/Won.cs @@ -1,15 +1,15 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class GameLogic { public partial record State { public record Won : State, IGet { public Won() { - OnEnter( - previous => Context.Output(new Output.ShowWonScreen()) - ); + this.OnEnter(() => Output(new Output.ShowWonScreen())); } - public IState On(Input.GoToMainMenu input) { + public IState On(in Input.GoToMainMenu input) { Get().OnExitGame(PostGameAction.GoToMainMenu); return this; } diff --git a/src/in_game_audio/InGameAudio.cs b/src/in_game_audio/InGameAudio.cs index 0b6bad3..06e7c27 100644 --- a/src/in_game_audio/InGameAudio.cs +++ b/src/in_game_audio/InGameAudio.cs @@ -43,26 +43,22 @@ public void OnResolved() { InGameAudioBinding = InGameAudioLogic.Bind(); InGameAudioBinding - .Handle( - _ => CoinCollected.Play() + .Handle((in InGameAudioLogic.Output.PlayCoinCollected _) => + CoinCollected.Play() ) - .Handle( - _ => Bounce.Play() + .Handle((in InGameAudioLogic.Output.PlayBounce _) => Bounce.Play() ) - .Handle( - _ => PlayerDied.Play() + .Handle((in InGameAudioLogic.Output.PlayPlayerDied _) => PlayerDied.Play() ) - .Handle( - _ => PlayerJumped.Play() + .Handle((in InGameAudioLogic.Output.PlayJump _) => + PlayerJumped.Play() ) - .Handle( - _ => StartMainMenuMusic() + .Handle((in InGameAudioLogic.Output.PlayMainMenuMusic _) => + StartMainMenuMusic() ) - .Handle( - _ => StartGameMusic() - ) - .Handle( - _ => GameMusic.FadeOut() + .Handle((in InGameAudioLogic.Output.PlayGameMusic _) => StartGameMusic()) + .Handle((in InGameAudioLogic.Output.StopGameMusic _) => + GameMusic.FadeOut() ); InGameAudioLogic.Start(); diff --git a/src/in_game_audio/state/InGameAudioLogic.State.cs b/src/in_game_audio/state/InGameAudioLogic.State.cs index 2d52674..2d96aec 100644 --- a/src/in_game_audio/state/InGameAudioLogic.State.cs +++ b/src/in_game_audio/state/InGameAudioLogic.State.cs @@ -4,14 +4,14 @@ namespace GameDemo; public partial class InGameAudioLogic : LogicBlock, IInGameAudioLogic { - public interface IState : IStateLogic { + public interface IState : IStateLogic { } - public record State : StateLogic, IState { + public record State : StateLogic, IState { public State() { OnAttach(() => { - var appRepo = Context.Get(); - var gameRepo = Context.Get(); + var appRepo = Get(); + var gameRepo = Get(); gameRepo.CoinCollected += OnCoinCollected; gameRepo.JumpshroomUsed += OnJumpshroomUsed; gameRepo.Ended += OnGameEnded; @@ -21,8 +21,8 @@ public State() { }); OnDetach(() => { - var appRepo = Context.Get(); - var gameRepo = Context.Get(); + var appRepo = Get(); + var gameRepo = Get(); gameRepo.CoinCollected -= OnCoinCollected; gameRepo.JumpshroomUsed -= OnJumpshroomUsed; gameRepo.Ended -= OnGameEnded; @@ -32,26 +32,28 @@ public State() { }); } - public void OnCoinCollected() => Context.Output(new Output.PlayCoinCollected()); + public void OnCoinCollected() => + Output(new Output.PlayCoinCollected()); - public void OnJumpshroomUsed() => Context.Output(new Output.PlayBounce()); + public void OnJumpshroomUsed() => Output(new Output.PlayBounce()); public void OnGameEnded(GameOverReason reason) { - Context.Output(new Output.StopGameMusic()); + Output(new Output.StopGameMusic()); if (reason is not GameOverReason.Lost) { return; } - Context.Output(new Output.PlayPlayerDied()); + Output(new Output.PlayPlayerDied()); } - public void OnJumped() => Context.Output(new Output.PlayJump()); + public void OnJumped() => Output(new Output.PlayJump()); // TODO: Use a different sound system for menu sounds. - public void OnMainMenuEntered() => Context.Output(new Output.PlayMainMenuMusic()); + public void OnMainMenuEntered() => + Output(new Output.PlayMainMenuMusic()); - public void OnGameEntered() => Context.Output(new Output.PlayGameMusic()); + public void OnGameEntered() => Output(new Output.PlayGameMusic()); } } diff --git a/src/in_game_audio/state/InGameAudioLogic.cs b/src/in_game_audio/state/InGameAudioLogic.cs index 0b7cd86..0e20bd8 100644 --- a/src/in_game_audio/state/InGameAudioLogic.cs +++ b/src/in_game_audio/state/InGameAudioLogic.cs @@ -5,7 +5,7 @@ namespace GameDemo; public interface IInGameAudioLogic : ILogicBlock; -[StateMachine] +[StateDiagram(typeof(State))] public partial class InGameAudioLogic : LogicBlock, IInGameAudioLogic { public override IState GetInitialState() => new State(); diff --git a/src/in_game_ui/InGameUI.cs b/src/in_game_ui/InGameUI.cs index 34c89ea..e356d56 100644 --- a/src/in_game_ui/InGameUI.cs +++ b/src/in_game_ui/InGameUI.cs @@ -44,13 +44,13 @@ public void OnResolved() { // TODO: Move the access to the game repo to the state machine. InGameUIBinding - .Handle( - output => SetCoinsLabel( + .Handle((in InGameUILogic.Output.NumCoinsCollectedChanged output) => + SetCoinsLabel( output.NumCoinsCollected, GameRepo.NumCoinsAtStart.Value ) ) - .Handle( - output => SetCoinsLabel( + .Handle((in InGameUILogic.Output.NumCoinsAtStartChanged output) => + SetCoinsLabel( GameRepo.NumCoinsCollected.Value, output.NumCoinsAtStart ) ); @@ -58,7 +58,8 @@ public void OnResolved() { InGameUILogic.Start(); } - public void SetCoinsLabel(int coins, int totalCoins) => CoinsLabel.Text = $"{coins}/{totalCoins}"; + public void SetCoinsLabel(int coins, int totalCoins) => + CoinsLabel.Text = $"{coins}/{totalCoins}"; public void OnExitTree() { InGameUILogic.Stop(); diff --git a/src/in_game_ui/state/InGameUILogic.State.cs b/src/in_game_ui/state/InGameUILogic.State.cs index 22fb686..5f0453b 100644 --- a/src/in_game_ui/state/InGameUILogic.State.cs +++ b/src/in_game_ui/state/InGameUILogic.State.cs @@ -1,28 +1,30 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class InGameUILogic { - public interface IState : IStateLogic { + public interface IState : IStateLogic { } - public record State : StateLogic, IState { + public record State : StateLogic, IState { public State() { OnAttach(() => { - var gameRepo = Context.Get(); + var gameRepo = Get(); gameRepo.NumCoinsCollected.Sync += OnNumCoinsCollected; gameRepo.NumCoinsAtStart.Sync += OnNumCoinsAtStart; }); OnDetach(() => { - var gameRepo = Context.Get(); + var gameRepo = Get(); gameRepo.NumCoinsCollected.Sync -= OnNumCoinsCollected; gameRepo.NumCoinsAtStart.Sync -= OnNumCoinsAtStart; }); } public void OnNumCoinsCollected(int numCoinsCollected) => - Context.Output(new Output.NumCoinsCollectedChanged(numCoinsCollected)); + Output(new Output.NumCoinsCollectedChanged(numCoinsCollected)); public void OnNumCoinsAtStart(int numCoinsAtStart) => - Context.Output(new Output.NumCoinsAtStartChanged(numCoinsAtStart)); + Output(new Output.NumCoinsAtStartChanged(numCoinsAtStart)); } } diff --git a/src/in_game_ui/state/InGameUILogic.cs b/src/in_game_ui/state/InGameUILogic.cs index f705b67..eaa19d3 100644 --- a/src/in_game_ui/state/InGameUILogic.cs +++ b/src/in_game_ui/state/InGameUILogic.cs @@ -9,7 +9,7 @@ public interface IInGameUILogic : ILogicBlock { // This state machine is nothing more than glue to the app repository. // If the UI were more sophisticated, it'd be easy to expand on this. -[StateMachine] +[StateDiagram(typeof(State))] public partial class InGameUILogic : LogicBlock, IInGameUILogic { public override IState GetInitialState() => new State(); diff --git a/src/jumpshroom/Jumpshroom.cs b/src/jumpshroom/Jumpshroom.cs index 7b1d33c..41b8e45 100644 --- a/src/jumpshroom/Jumpshroom.cs +++ b/src/jumpshroom/Jumpshroom.cs @@ -64,11 +64,13 @@ public void OnResolved() { CooldownTimer.Timeout += OnCooldownTimeout; JumpshroomBinding - .Handle( - output => AnimationPlayer.Play("bounce") + .Handle( + (in JumpshroomLogic.Output.Animate output) => + AnimationPlayer.Play("bounce") ) - .Handle( - output => CooldownTimer.Start() + .Handle( + (in JumpshroomLogic.Output.StartCooldownTimer output) => + CooldownTimer.Start() ); } diff --git a/src/jumpshroom/state/JumpshroomLogic.State.cs b/src/jumpshroom/state/JumpshroomLogic.State.cs index 3f08c14..02d151e 100644 --- a/src/jumpshroom/state/JumpshroomLogic.State.cs +++ b/src/jumpshroom/state/JumpshroomLogic.State.cs @@ -3,7 +3,7 @@ namespace GameDemo; using Chickensoft.LogicBlocks; public partial class JumpshroomLogic : LogicBlock { - public interface IState : IStateLogic { } + public interface IState : IStateLogic; - public abstract partial record State : StateLogic, IState; + public abstract partial record State : StateLogic, IState; } diff --git a/src/jumpshroom/state/JumpshroomLogic.cs b/src/jumpshroom/state/JumpshroomLogic.cs index 82941bc..50a0ddc 100644 --- a/src/jumpshroom/state/JumpshroomLogic.cs +++ b/src/jumpshroom/state/JumpshroomLogic.cs @@ -6,7 +6,7 @@ namespace GameDemo; public interface IJumpshroomLogic : ILogicBlock { } -[StateMachine] +[StateDiagram(typeof(State))] public partial class JumpshroomLogic : LogicBlock, IJumpshroomLogic { public override State GetInitialState() => new State.Idle(); diff --git a/src/jumpshroom/state/states/JumpshroomLogic.State.Cooldown.cs b/src/jumpshroom/state/states/JumpshroomLogic.State.Cooldown.cs index 0c74c55..56a4e1e 100644 --- a/src/jumpshroom/state/states/JumpshroomLogic.State.Cooldown.cs +++ b/src/jumpshroom/state/states/JumpshroomLogic.State.Cooldown.cs @@ -6,12 +6,10 @@ public partial class JumpshroomLogic : LogicBlock { public partial record State { public record Cooldown : State, IGet { public Cooldown() { - OnEnter( - (previous) => Context.Output(new Output.StartCooldownTimer()) - ); + this.OnEnter(() => Output(new Output.StartCooldownTimer())); } - public IState On(Input.CooldownCompleted input) => new Idle(); + public IState On(in Input.CooldownCompleted input) => new Idle(); } } } diff --git a/src/jumpshroom/state/states/JumpshroomLogic.State.Idle.cs b/src/jumpshroom/state/states/JumpshroomLogic.State.Idle.cs index b98d642..b1ea7d0 100644 --- a/src/jumpshroom/state/states/JumpshroomLogic.State.Idle.cs +++ b/src/jumpshroom/state/states/JumpshroomLogic.State.Idle.cs @@ -5,7 +5,7 @@ namespace GameDemo; public partial class JumpshroomLogic : LogicBlock { public partial record State { public record Idle : State, IGet { - public IState On(Input.Hit input) { + public IState On(in Input.Hit input) { return new Loading(input.Target); } } diff --git a/src/jumpshroom/state/states/JumpshroomLogic.State.Launching.cs b/src/jumpshroom/state/states/JumpshroomLogic.State.Launching.cs index 12cf32e..3d2e696 100644 --- a/src/jumpshroom/state/states/JumpshroomLogic.State.Launching.cs +++ b/src/jumpshroom/state/states/JumpshroomLogic.State.Launching.cs @@ -12,12 +12,12 @@ public Launching(IPushEnabled target) { // We are colliding with something we can push at the moment of // launch, so push it. - OnEnter( - (previous) => Target.Push(Vector3.Up * Get().ImpulseStrength) + this.OnEnter( + () => Target.Push(Vector3.Up * Get().ImpulseStrength) ); } - public IState On(Input.LaunchCompleted input) => new Cooldown(); + public IState On(in Input.LaunchCompleted input) => new Cooldown(); } } } diff --git a/src/jumpshroom/state/states/JumpshroomLogic.State.Loading.cs b/src/jumpshroom/state/states/JumpshroomLogic.State.Loading.cs index 3f81c15..81d5476 100644 --- a/src/jumpshroom/state/states/JumpshroomLogic.State.Loading.cs +++ b/src/jumpshroom/state/states/JumpshroomLogic.State.Loading.cs @@ -10,15 +10,14 @@ public record Loading : State, IGet { public Loading(IPushEnabled target) { Target = target; - OnEnter(previous => { + this.OnEnter(() => { Get().OnJumpshroomUsed(); - Context.Output(new Output.Animate()); + Output(new Output.Animate()); }); } // Springy top is fully compressed, so it is ready to launch. - public IState On(Input.Launch input) => - new Launching(Target); + public IState On(in Input.Launch input) => new Launching(Target); } } } diff --git a/src/menu/splash/Splash.cs b/src/menu/splash/Splash.cs index b782990..831e651 100644 --- a/src/menu/splash/Splash.cs +++ b/src/menu/splash/Splash.cs @@ -6,7 +6,7 @@ namespace GameDemo; using Godot; using SuperNodes.Types; -public interface ISplash : IControl { } +public interface ISplash : IControl; [SuperNode(typeof(AutoNode), typeof(Dependent))] public partial class Splash : Control, ISplash { diff --git a/src/player/Player.cs b/src/player/Player.cs index f9fac66..e203d18 100644 --- a/src/player/Player.cs +++ b/src/player/Player.cs @@ -131,14 +131,12 @@ public void OnResolved() { GameRepo.SetPlayerGlobalPosition(GlobalPosition); PlayerBinding - .Handle( - output => { - Transform = Transform with { Basis = output.Rotation }; - Velocity = output.Velocity; - } - ) - .Handle( - output => Velocity = output.Velocity + .Handle((in PlayerLogic.Output.MovementComputed output) => { + Transform = Transform with { Basis = output.Rotation }; + Velocity = output.Velocity; + }) + .Handle((in PlayerLogic.Output.VelocityChanged output) => + Velocity = output.Velocity ); PlayerLogic.Start(); diff --git a/src/player/PlayerModel.cs b/src/player/PlayerModel.cs index cd07a49..526a1fe 100644 --- a/src/player/PlayerModel.cs +++ b/src/player/PlayerModel.cs @@ -6,7 +6,7 @@ namespace GameDemo; using Godot; using SuperNodes.Types; -public interface IPlayerModel { } +public interface IPlayerModel; [SuperNode(typeof(Dependent), typeof(AutoNode))] public partial class PlayerModel : Node3D { @@ -39,20 +39,20 @@ public void OnResolved() { PlayerBinding = PlayerLogic.Bind(); PlayerBinding - .Handle( - (output) => AnimationStateMachine.Travel("idle") + .Handle((in PlayerLogic.Output.Animations.Idle output) => + AnimationStateMachine.Travel("idle") ) - .Handle( - (output) => AnimationStateMachine.Travel("move") + .Handle((in PlayerLogic.Output.Animations.Move output) => + AnimationStateMachine.Travel("move") ) - .Handle( - (output) => AnimationStateMachine.Travel("jump") + .Handle((in PlayerLogic.Output.Animations.Jump output) => + AnimationStateMachine.Travel("jump") ) - .Handle( - (output) => AnimationStateMachine.Travel("fall") + .Handle((in PlayerLogic.Output.Animations.Fall output) => + AnimationStateMachine.Travel("fall") ) - .Handle( - (output) => AnimationTree.Set( + .Handle((in PlayerLogic.Output.MoveSpeedChanged output) => + AnimationTree.Set( "parameters/main_animations/move/blend_position", output.Speed ) ); diff --git a/src/player/state/PlayerLogic.State.cs b/src/player/state/PlayerLogic.State.cs index 1d00706..986d342 100644 --- a/src/player/state/PlayerLogic.State.cs +++ b/src/player/state/PlayerLogic.State.cs @@ -1,7 +1,9 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class PlayerLogic { - public interface IState : IStateLogic { } + public interface IState : IStateLogic; - public abstract partial record State : StateLogic, IState { } + public abstract partial record State : StateLogic, IState; } diff --git a/src/player/state/PlayerLogic.cs b/src/player/state/PlayerLogic.cs index 67be215..650b54d 100644 --- a/src/player/state/PlayerLogic.cs +++ b/src/player/state/PlayerLogic.cs @@ -5,7 +5,7 @@ namespace GameDemo; public interface IPlayerLogic : ILogicBlock { } -[StateMachine] +[StateDiagram(typeof(State))] public partial class PlayerLogic : LogicBlock, IPlayerLogic { public override IState GetInitialState() => new State.Disabled(); diff --git a/src/player/state/states/PlayerLogic.State.Alive.Airborne.Falling.cs b/src/player/state/states/PlayerLogic.State.Alive.Airborne.Falling.cs index 25b2143..1cc13e0 100644 --- a/src/player/state/states/PlayerLogic.State.Alive.Airborne.Falling.cs +++ b/src/player/state/states/PlayerLogic.State.Alive.Airborne.Falling.cs @@ -1,12 +1,12 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class PlayerLogic { public partial record State { public record Falling : Airborne { public Falling() { - OnEnter( - previous => Context.Output(new Output.Animations.Fall()) - ); + this.OnEnter(() => Output(new Output.Animations.Fall())); } } } diff --git a/src/player/state/states/PlayerLogic.State.Alive.Airborne.Jumping.cs b/src/player/state/states/PlayerLogic.State.Alive.Airborne.Jumping.cs index 5c94fd3..3a57c66 100644 --- a/src/player/state/states/PlayerLogic.State.Alive.Airborne.Jumping.cs +++ b/src/player/state/states/PlayerLogic.State.Alive.Airborne.Jumping.cs @@ -1,12 +1,14 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class PlayerLogic { public abstract partial record State { public record Jumping : Airborne, IGet { public Jumping() { - OnEnter( - previous => { - Context.Output(new Output.Animations.Jump()); + this.OnEnter( + () => { + Output(new Output.Animations.Jump()); Get().OnJump(); } ); @@ -14,15 +16,15 @@ public Jumping() { // Override jump when in the air to allow for bigger jumps if the player // keeps holding down the jump button. - public IState On(Input.Jump input) { - var player = Context.Get(); - var settings = Context.Get(); + public IState On(in Input.Jump input) { + var player = Get(); + var settings = Get(); var velocity = player.Velocity; // Continue the jump in-air. Very forgiving player physics. velocity.Y += settings.JumpForce * (float)input.Delta; - Context.Output(new Output.VelocityChanged(velocity)); + Output(new Output.VelocityChanged(velocity)); return this; } diff --git a/src/player/state/states/PlayerLogic.State.Alive.Airborne.Liftoff.cs b/src/player/state/states/PlayerLogic.State.Alive.Airborne.Liftoff.cs index fcb807c..51e0fbc 100644 --- a/src/player/state/states/PlayerLogic.State.Alive.Airborne.Liftoff.cs +++ b/src/player/state/states/PlayerLogic.State.Alive.Airborne.Liftoff.cs @@ -1,5 +1,7 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class PlayerLogic { public abstract partial record State { /// @@ -10,9 +12,7 @@ public abstract partial record State { /// public record Liftoff : Airborne { public Liftoff() { - OnEnter( - (previous) => Context.Output(new Output.Animations.Jump()) - ); + this.OnEnter(() => Output(new Output.Animations.Jump())); } } } diff --git a/src/player/state/states/PlayerLogic.State.Alive.Airborne.cs b/src/player/state/states/PlayerLogic.State.Alive.Airborne.cs index 8b55dc4..abcbe81 100644 --- a/src/player/state/states/PlayerLogic.State.Alive.Airborne.cs +++ b/src/player/state/states/PlayerLogic.State.Alive.Airborne.cs @@ -4,7 +4,7 @@ public partial class PlayerLogic { public partial record State { public record Airborne : Alive, IGet, IGet { - public IState On(Input.HitFloor input) { + public IState On(in Input.HitFloor input) { if (input.IsMovingHorizontally) { return new Moving(); } @@ -12,7 +12,7 @@ public IState On(Input.HitFloor input) { return new Idle(); } - public IState On(Input.StartedFalling input) => new Falling(); + public IState On(in Input.StartedFalling input) => new Falling(); } } } diff --git a/src/player/state/states/PlayerLogic.State.Alive.Grounded.Idle.cs b/src/player/state/states/PlayerLogic.State.Alive.Grounded.Idle.cs index 60d949b..6c914a5 100644 --- a/src/player/state/states/PlayerLogic.State.Alive.Grounded.Idle.cs +++ b/src/player/state/states/PlayerLogic.State.Alive.Grounded.Idle.cs @@ -1,15 +1,16 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class PlayerLogic { public abstract partial record State { public record Idle : Grounded, IGet { public Idle() { - OnEnter( - (previous) => Context.Output(new Output.Animations.Idle()) - ); + this.OnEnter(() => Output(new Output.Animations.Idle())); } - public IState On(Input.StartedMovingHorizontally input) => new Moving(); + public IState On(in Input.StartedMovingHorizontally input) => + new Moving(); } } } diff --git a/src/player/state/states/PlayerLogic.State.Alive.Grounded.Moving.cs b/src/player/state/states/PlayerLogic.State.Alive.Grounded.Moving.cs index d82a2bc..4246e14 100644 --- a/src/player/state/states/PlayerLogic.State.Alive.Grounded.Moving.cs +++ b/src/player/state/states/PlayerLogic.State.Alive.Grounded.Moving.cs @@ -1,15 +1,15 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class PlayerLogic { public abstract partial record State { public record Moving : Grounded, IGet { public Moving() { - OnEnter( - (previous) => Context.Output(new Output.Animations.Move()) - ); + this.OnEnter(() => Output(new Output.Animations.Move())); } - public IState On(Input.StoppedMovingHorizontally input) => new Idle(); + public IState On(in Input.StoppedMovingHorizontally input) => new Idle(); } } } diff --git a/src/player/state/states/PlayerLogic.State.Alive.Grounded.cs b/src/player/state/states/PlayerLogic.State.Alive.Grounded.cs index 5f5d127..ae898df 100644 --- a/src/player/state/states/PlayerLogic.State.Alive.Grounded.cs +++ b/src/player/state/states/PlayerLogic.State.Alive.Grounded.cs @@ -3,22 +3,22 @@ namespace GameDemo; public partial class PlayerLogic { public abstract partial record State { public record Grounded : Alive, IGet, IGet { - public virtual IState On(Input.Jump input) { + public virtual IState On(in Input.Jump input) { // We can jump from any grounded state if the jump button was just // pressed. - var player = Context.Get(); - var settings = Context.Get(); + var player = Get(); + var settings = Get(); var velocity = player.Velocity; // Start the jump. velocity.Y += settings.JumpImpulseForce; - Context.Output(new Output.VelocityChanged(velocity)); + Output(new Output.VelocityChanged(velocity)); return new Jumping(); } - public IState On(Input.LeftFloor input) { + public IState On(in Input.LeftFloor input) { if (input.IsFalling) { return new Falling(); } diff --git a/src/player/state/states/PlayerLogic.State.Alive.cs b/src/player/state/states/PlayerLogic.State.Alive.cs index 3b8a49b..e901a24 100644 --- a/src/player/state/states/PlayerLogic.State.Alive.cs +++ b/src/player/state/states/PlayerLogic.State.Alive.cs @@ -3,7 +3,7 @@ namespace GameDemo; using Godot; public partial class PlayerLogic { - public partial record State : StateLogic, IState { + public partial record State { public record Alive : State, IGet, IGet, @@ -16,18 +16,18 @@ public record Alive : State, // a MoveEnabled substate and extend it for states where movement is // allowed. - public virtual IState On(Input.Killed input) { + public virtual IState On(in Input.Killed input) { Get().OnGameEnded(GameOverReason.Lost); return new Dead(); } - public virtual IState On(Input.PhysicsTick input) { + public virtual IState On(in Input.PhysicsTick input) { var delta = input.Delta; - var player = Context.Get(); - var settings = Context.Get(); - var gameRepo = Context.Get(); - var data = Context.Get(); + var player = Get(); + var settings = Get(); + var gameRepo = Get(); + var data = Get(); var moveDirection = player.GetGlobalInputVector(gameRepo.CameraBasis.Value); @@ -60,18 +60,18 @@ public virtual IState On(Input.PhysicsTick input) { // Add gravity. velocity.Y += settings.Gravity * (float)delta; - Context.Output( + Output( new Output.MovementComputed(nextRotationBasis, velocity) ); return this; } - public virtual IState On(Input.Moved input) { - var player = Context.Get(); - var settings = Context.Get(); - var gameRepo = Context.Get(); - var data = Context.Get(); + public virtual IState On(in Input.Moved input) { + var player = Get(); + var settings = Get(); + var gameRepo = Get(); + var data = Get(); // Tell the game the player has moved. // Anything that subscribes to our position (like the camera) will @@ -116,39 +116,39 @@ public virtual IState On(Input.Moved input) { data.LastVelocity = player.Velocity; if (justHitFloor) { - Context.Input( + Input( new Input.HitFloor(IsMovingHorizontally: isMovingHorizontally) ); } else if (justLeftFloor) { - Context.Input( + Input( new Input.LeftFloor(IsFalling: hasNegativeYVelocity) ); } else if (justStartedFalling) { - Context.Input(new Input.StartedFalling()); + Input(new Input.StartedFalling()); } // Grounded status hasn't changed. Check for changes in horizontal // movement. if (justStartedMovingHorizontally) { - Context.Input(new Input.StartedMovingHorizontally()); + Input(new Input.StartedMovingHorizontally()); } else if (justStoppedMovingHorizontally) { - Context.Input(new Input.StoppedMovingHorizontally()); + Input(new Input.StoppedMovingHorizontally()); } return this; } - public IState On(Input.Pushed input) { - var player = Context.Get(); + public IState On(in Input.Pushed input) { + var player = Get(); var velocity = player.Velocity; // Apply force velocity += input.GlobalForceImpulseVector; - Context.Output(new Output.VelocityChanged(velocity)); + Output(new Output.VelocityChanged(velocity)); // Remain in current state. Next physics tick will end up applying the // force which will make us re-evaluate our state in On(Input.Moved) diff --git a/src/player/state/states/PlayerLogic.State.Disabled.cs b/src/player/state/states/PlayerLogic.State.Disabled.cs index 9ff118d..410b9fe 100644 --- a/src/player/state/states/PlayerLogic.State.Disabled.cs +++ b/src/player/state/states/PlayerLogic.State.Disabled.cs @@ -1,20 +1,20 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; + public partial class PlayerLogic { - public abstract partial record State : StateLogic, IState { + public abstract partial record State { public record Disabled : State, IGet { public Disabled() { - OnEnter( - previous => Context.Output(new Output.Animations.Idle()) - ); + this.OnEnter(() => Output(new Output.Animations.Idle())); OnAttach(() => Get().GameEntered += OnGameEntered); OnDetach(() => Get().GameEntered -= OnGameEntered); } - public IState On(Input.Enable input) => new Idle(); + public IState On(in Input.Enable input) => new Idle(); } - public void OnGameEntered() => Context.Input(new Input.Enable()); + public void OnGameEntered() => Input(new Input.Enable()); } } diff --git a/src/player_camera/PlayerCamera.cs b/src/player_camera/PlayerCamera.cs index f70c6a6..fa59d6f 100644 --- a/src/player_camera/PlayerCamera.cs +++ b/src/player_camera/PlayerCamera.cs @@ -119,17 +119,19 @@ public void Setup() { public void OnResolved() { CameraBinding = CameraLogic.Bind(); CameraBinding - .Handle( - output => { - GimbalHorizontalNode.Rotation = output.GimbalRotationHorizontal; - GimbalVerticalNode.Rotation = output.GimbalRotationVertical; - } - ).Handle( - output => GlobalTransform = output.GlobalTransform - ).Handle( - output => CameraNode.Position = output.CameraLocalPosition - ).Handle( - output => OffsetNode.Position = output.Offset + .Handle((in PlayerCameraLogic.Output.GimbalRotationChanged output) => { + GimbalHorizontalNode.Rotation = output.GimbalRotationHorizontal; + GimbalVerticalNode.Rotation = output.GimbalRotationVertical; + }) + .Handle((in PlayerCameraLogic.Output.GlobalTransformChanged output) => + GlobalTransform = output.GlobalTransform + ) + .Handle( + (in PlayerCameraLogic.Output.CameraLocalPositionChanged output) => + CameraNode.Position = output.CameraLocalPosition + ) + .Handle((in PlayerCameraLogic.Output.CameraOffsetChanged output) => + OffsetNode.Position = output.Offset ); CameraLogic.Start(); diff --git a/src/player_camera/State/PlayerCameraLogic.State.cs b/src/player_camera/State/PlayerCameraLogic.State.cs index bcf58ec..94e933f 100644 --- a/src/player_camera/State/PlayerCameraLogic.State.cs +++ b/src/player_camera/State/PlayerCameraLogic.State.cs @@ -1,9 +1,10 @@ namespace GameDemo; +using Chickensoft.LogicBlocks; using Godot; public partial class PlayerCameraLogic { - public interface IState : IStateLogic { + public interface IState : IStateLogic { } /// @@ -11,7 +12,7 @@ public interface IState : IStateLogic { /// be able to instantiate it by itself for easier testing. /// public partial record State - : StateLogic, IState, + : StateLogic, IState, IGet, IGet, IGet { @@ -35,24 +36,24 @@ public State() { internal void OnMouseCaptured(bool isMouseCaptured) { if (isMouseCaptured) { - Context.Input(new Input.EnableInput()); + Input(new Input.EnableInput()); return; } - Context.Input(new Input.DisableInput()); + Input(new Input.DisableInput()); } internal void OnPlayerGlobalPositionChanged(Vector3 position) => - Context.Input(new Input.TargetPositionChanged(position)); + Input(new Input.TargetPositionChanged(position)); internal void OnCameraTargetOffsetChanged(Vector3 targetOffset) => - Context.Input(new Input.TargetOffsetChanged(targetOffset)); + Input(new Input.TargetOffsetChanged(targetOffset)); - public IState On(Input.PhysicsTicked input) { - var camera = Context.Get(); - var gameRepo = Context.Get(); - var settings = Context.Get(); - var data = Context.Get(); + public IState On(in Input.PhysicsTicked input) { + var camera = Get(); + var gameRepo = Get(); + var settings = Get(); + var data = Get(); // Lerp to the desired horizontal angle. var rotationHorizontal = camera.GimbalRotationHorizontal; @@ -75,7 +76,7 @@ public IState On(Input.PhysicsTicked input) { // This triggers the camera to update its gimbal nodes. // This keeps us from having to know about the camera's implementation // details. - Context.Output(new Output.GimbalRotationChanged( + Output(new Output.GimbalRotationChanged( rotationHorizontal, rotationVertical )); @@ -89,7 +90,7 @@ public IState On(Input.PhysicsTicked input) { transform, (float)input.Delta * settings.FollowSpeed ).Orthonormalized(); - Context.Output(new Output.GlobalTransformChanged(globalTransform)); + Output(new Output.GlobalTransformChanged(globalTransform)); // Lerp camera inside system to spring arm target position var springArmTargetPosition = camera.SpringArmTargetPosition; @@ -98,7 +99,7 @@ public IState On(Input.PhysicsTicked input) { springArmTargetPosition, (float)input.Delta * settings.SpringArmAdjSpeed ); - Context.Output( + Output( new Output.CameraLocalPositionChanged(springArmTargetPositionLerp) ); @@ -107,19 +108,19 @@ public IState On(Input.PhysicsTicked input) { data.TargetOffset, (float)input.Delta * settings.OffsetAdjSpeed ); - Context.Output(new Output.CameraOffsetChanged(offset)); + Output(new Output.CameraOffsetChanged(offset)); return this; } - public IState On(Input.TargetPositionChanged input) { - var data = Context.Get(); + public IState On(in Input.TargetPositionChanged input) { + var data = Get(); data.TargetPosition = input.TargetPosition; return this; } - public IState On(Input.TargetOffsetChanged input) { - var data = Context.Get(); + public IState On(in Input.TargetOffsetChanged input) { + var data = Get(); data.TargetOffset = input.TargetOffset; return this; } diff --git a/src/player_camera/State/PlayerCameraLogic.cs b/src/player_camera/State/PlayerCameraLogic.cs index c4db6d3..1fbc67a 100644 --- a/src/player_camera/State/PlayerCameraLogic.cs +++ b/src/player_camera/State/PlayerCameraLogic.cs @@ -6,7 +6,7 @@ namespace GameDemo; public interface IPlayerCameraLogic : ILogicBlock; -[StateMachine] +[StateDiagram(typeof(State))] public partial class PlayerCameraLogic : LogicBlock, IPlayerCameraLogic { public override IState GetInitialState() => new State.InputDisabled(); diff --git a/src/player_camera/State/states/PlayerCameraLogic.State.InputDisabled.cs b/src/player_camera/State/states/PlayerCameraLogic.State.InputDisabled.cs index 4e31f42..f0e44db 100644 --- a/src/player_camera/State/states/PlayerCameraLogic.State.InputDisabled.cs +++ b/src/player_camera/State/states/PlayerCameraLogic.State.InputDisabled.cs @@ -3,7 +3,7 @@ namespace GameDemo; public partial class PlayerCameraLogic { public partial record State { public record InputDisabled : State, IGet { - public IState On(Input.EnableInput input) => new InputEnabled(); + public IState On(in Input.EnableInput input) => new InputEnabled(); } } } diff --git a/src/player_camera/State/states/PlayerCameraLogic.State.InputEnabled.cs b/src/player_camera/State/states/PlayerCameraLogic.State.InputEnabled.cs index f20b9ed..e1356ab 100644 --- a/src/player_camera/State/states/PlayerCameraLogic.State.InputEnabled.cs +++ b/src/player_camera/State/states/PlayerCameraLogic.State.InputEnabled.cs @@ -7,11 +7,11 @@ public partial record State { /// The state of the player camera. public record InputEnabled : State, IGet, IGet { - public IState On(Input.DisableInput input) => new InputDisabled(); + public IState On(in Input.DisableInput input) => new InputDisabled(); - public IState On(Input.MouseInputOccurred input) { - var settings = Context.Get(); - var data = Context.Get(); + public IState On(in Input.MouseInputOccurred input) { + var settings = Get(); + var data = Get(); var targetAngleHorizontal = data.TargetAngleHorizontal + (-input.Motion.Relative.X * settings.MouseSensitivity); diff --git a/test/src/coin/CoinTest.cs b/test/src/coin/CoinTest.cs index 492e428..1dab9f4 100644 --- a/test/src/coin/CoinTest.cs +++ b/test/src/coin/CoinTest.cs @@ -64,7 +64,7 @@ public void Initializes() { public void OnPhysicsProcess() { _logic.Reset(); _logic.Setup( - logic => logic.Input(It.IsAny()) + logic => logic.Input(in It.Ref.IsAny) ); _coin.OnPhysicsProcess(1f); @@ -76,7 +76,7 @@ public void OnPhysicsProcess() { public void OnCollectorDetectorBodyEntered() { _logic.Reset(); _logic.Setup( - logic => logic.Input(It.IsAny()) + logic => logic.Input(in It.Ref.IsAny) ); var collector = new FakeCoinCollector(); diff --git a/test/src/jumpshroom/JumpshroomTest.cs b/test/src/jumpshroom/JumpshroomTest.cs index 191b333..65e2345 100644 --- a/test/src/jumpshroom/JumpshroomTest.cs +++ b/test/src/jumpshroom/JumpshroomTest.cs @@ -105,7 +105,7 @@ public void OnAreaBodyEnteredHitsIfPushEnabled() { _logic.Reset(); var target = new FakePushEnabled(); _logic.Setup( - logic => logic.Input(It.IsAny()) + logic => logic.Input(in It.Ref.IsAny) ); _shroom.OnAreaBodyEntered(target); @@ -116,7 +116,9 @@ public void OnAreaBodyEnteredHitsIfPushEnabled() { public void OnCooldownTimeoutCompletesCooldown() { _logic.Reset(); _logic.Setup( - logic => logic.Input(It.IsAny()) + logic => logic.Input( + in It.Ref.IsAny + ) ); _shroom.OnCooldownTimeout(); _logic.VerifyAll(); diff --git a/test/src/player/PlayerTest.cs b/test/src/player/PlayerTest.cs index df15b3f..29858a8 100644 --- a/test/src/player/PlayerTest.cs +++ b/test/src/player/PlayerTest.cs @@ -86,17 +86,19 @@ public void OnPhysicsProcessJumpsOnInput() { _player.OnPhysicsProcess(1d); - _logic.Verify(logic => logic.Input(It.IsAny())); + _logic.Verify( + logic => logic.Input(in It.Ref.IsAny) + ); } [Test] public void OnPhysicsProcess() { _logic.Reset(); _logic.Setup( - logic => logic.Input(It.IsAny()) + logic => logic.Input(in It.Ref.IsAny) ); _logic.Setup( - logic => logic.Input(It.IsAny()) + logic => logic.Input(in It.Ref.IsAny) ); _player.OnPhysicsProcess(1d); @@ -136,7 +138,9 @@ public void IsMovingChecks() { [Test] public void Pushed() { _logic.Reset(); - _logic.Setup(logic => logic.Input(It.IsAny())); + _logic.Setup( + logic => logic.Input(in It.Ref.IsAny) + ); _player.Push(Vector3.Forward); _logic.VerifyAll(); @@ -148,7 +152,9 @@ public void Pushed() { [Test] public void Dies() { _logic.Reset(); - _logic.Setup(logic => logic.Input(It.IsAny())); + _logic.Setup( + logic => logic.Input(in It.Ref.IsAny) + ); _player.Kill(); _logic.VerifyAll(); } diff --git a/test/src/player_camera/PlayerCameraTest.cs b/test/src/player_camera/PlayerCameraTest.cs index 4c5df70..63486c2 100644 --- a/test/src/player_camera/PlayerCameraTest.cs +++ b/test/src/player_camera/PlayerCameraTest.cs @@ -67,7 +67,9 @@ public void OnPhysicsProcess() { _logic.Reset(); _logic.Setup( - logic => logic.Input(It.IsAny()) + logic => logic.Input( + in It.Ref.IsAny + ) ); _playerCam.OnPhysicsProcess(1d); @@ -81,7 +83,7 @@ public void InputsMouseMotion() { var motion = new InputEventMouseMotion(); _logic.Setup( logic => logic.Input( - It.IsAny() + in It.Ref.IsAny ) );