diff --git a/src/app/App.cs b/src/app/App.cs index 5c19821a..cc421c37 100644 --- a/src/app/App.cs +++ b/src/app/App.cs @@ -2,7 +2,7 @@ using Chickensoft.GodotNodeInterfaces; using Chickensoft.Introspection; using Godot; -using System.Linq; +using System.Threading; namespace GameJamDungeon { @@ -25,28 +25,54 @@ namespace GameJamDungeon public IAppLogic AppLogic { get; set; } = default!; public AppLogic.IBinding AppBinding { get; set; } = default!; + [Node] public IMenu Menu { get; set; } = default!; + [Node] public ISubViewport GameWindow { get; set; } = default!; + [Node] public IAnimationPlayer AnimationPlayer { get; set; } = default!; + public void Initialize() { Instantiator = new Instantiator(GetTree()); AppRepo = new AppRepo(); AppLogic = new AppLogic(); AppLogic.Set(AppRepo); - + Menu.NewGame += OnNewGame; + Menu.Quit += OnQuit; + AnimationPlayer.AnimationFinished += AnimationPlayer_AnimationFinished; this.Provide(); } public void OnReady() { - Game = Instantiator.LoadAndInstantiate(GAME_SCENE_PATH); - GameWindow.AddChildEx(Game); AppBinding = AppLogic.Bind(); - AppLogic.Start(); - Instantiator.SceneTree.Paused = false; + AppBinding + .Handle((in AppLogic.Output.ShowLoadingScreen _) => + { + Menu.Hide(); + AnimationPlayer.Play("load"); + }) + .Handle((in AppLogic.Output.SetupGameScene _) => + { + Instantiator.SceneTree.Paused = true; + Game = Instantiator.LoadAndInstantiate(GAME_SCENE_PATH); + GameWindow.AddChildEx(Game); + }) + .Handle((in AppLogic.Output.ShowGame _) => + { + Instantiator.SceneTree.Paused = false; + Game.Show(); + }); + + + AppLogic.Start(); } + private void AnimationPlayer_AnimationFinished(StringName animName) + { + AppLogic.Input(new AppLogic.Input.LoadGameFinished()); + } public void OnNewGame() => AppLogic.Input(new AppLogic.Input.NewGame()); diff --git a/src/app/App.tscn b/src/app/App.tscn index 9aa409be..7d1fe637 100644 --- a/src/app/App.tscn +++ b/src/app/App.tscn @@ -1,6 +1,68 @@ -[gd_scene load_steps=2 format=3 uid="uid://cagfc5ridmteu"] +[gd_scene load_steps=6 format=3 uid="uid://cagfc5ridmteu"] [ext_resource type="Script" path="res://src/app/App.cs" id="1_rt73h"] +[ext_resource type="PackedScene" uid="uid://rfvnddfqufho" path="res://src/menu/Menu.tscn" id="2_kvwo1"] + +[sub_resource type="Animation" id="Animation_fa8xf"] +resource_name = "load" +length = 5.0 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("LoadScreen:modulate") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0, 0.466667, 4.03333, 5), +"transitions": PackedFloat32Array(1, 1, 1, 1), +"update": 0, +"values": [Color(0, 0, 0, 0), Color(0, 0, 0, 1), Color(0, 0, 0, 1), Color(0, 0, 0, 0)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("SubViewportContainer:visible") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0, 4.03333), +"transitions": PackedFloat32Array(1, 1), +"update": 1, +"values": [false, true] +} + +[sub_resource type="Animation" id="Animation_mbxap"] +length = 0.001 +tracks/0/type = "value" +tracks/0/imported = false +tracks/0/enabled = true +tracks/0/path = NodePath("LoadScreen:modulate") +tracks/0/interp = 1 +tracks/0/loop_wrap = true +tracks/0/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 0, +"values": [Color(1, 1, 1, 0)] +} +tracks/1/type = "value" +tracks/1/imported = false +tracks/1/enabled = true +tracks/1/path = NodePath("SubViewportContainer:visible") +tracks/1/interp = 1 +tracks/1/loop_wrap = true +tracks/1/keys = { +"times": PackedFloat32Array(0), +"transitions": PackedFloat32Array(1), +"update": 1, +"values": [true] +} + +[sub_resource type="AnimationLibrary" id="AnimationLibrary_vkd35"] +_data = { +"RESET": SubResource("Animation_mbxap"), +"load": SubResource("Animation_fa8xf") +} [node name="App" type="CanvasLayer"] process_mode = 3 @@ -21,3 +83,21 @@ handle_input_locally = false audio_listener_enable_3d = true size = Vector2i(1920, 1080) render_target_update_mode = 4 + +[node name="Menu" parent="." instance=ExtResource("2_kvwo1")] +unique_name_in_owner = true + +[node name="LoadScreen" type="ColorRect" parent="."] +modulate = Color(1, 1, 1, 0) +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +color = Color(0.235294, 0.235294, 0.784314, 1) + +[node name="AnimationPlayer" type="AnimationPlayer" parent="."] +unique_name_in_owner = true +libraries = { +"": SubResource("AnimationLibrary_vkd35") +} diff --git a/src/app/state/AppLogic.Input.cs b/src/app/state/AppLogic.Input.cs index 5d9227a5..711408cb 100644 --- a/src/app/state/AppLogic.Input.cs +++ b/src/app/state/AppLogic.Input.cs @@ -6,13 +6,15 @@ { public readonly record struct NewGame; - public readonly record struct FadeInFinished; + public readonly record struct LoadGameFinished; public readonly record struct FadeOutFinished; public readonly record struct QuitGame; public readonly record struct GameOver; + + public readonly record struct ShowLoadingScreen; } } } diff --git a/src/app/state/AppLogic.Output.cs b/src/app/state/AppLogic.Output.cs index 67652042..25d53986 100644 --- a/src/app/state/AppLogic.Output.cs +++ b/src/app/state/AppLogic.Output.cs @@ -18,7 +18,9 @@ public readonly record struct HideGame; - public readonly record struct SetupGameScene(); + public readonly record struct SetupGameScene; + + public readonly record struct ShowLoadingScreen; public readonly record struct ShowMainMenu; diff --git a/src/app/state/AppLogic.cs b/src/app/state/AppLogic.cs index bf9fbaee..94ebbd94 100644 --- a/src/app/state/AppLogic.cs +++ b/src/app/state/AppLogic.cs @@ -9,6 +9,6 @@ namespace GameJamDungeon [LogicBlock(typeof(State), Diagram = true)] public partial class AppLogic : LogicBlock, IAppLogic { - public override Transition GetInitialState() => To(); + public override Transition GetInitialState() => To(); } } diff --git a/src/app/state/states/LeavingMenu.cs b/src/app/state/states/LeavingMenu.cs deleted file mode 100644 index e27562a1..00000000 --- a/src/app/state/states/LeavingMenu.cs +++ /dev/null @@ -1,22 +0,0 @@ -using Chickensoft.Introspection; -using Chickensoft.LogicBlocks; - -namespace GameJamDungeon -{ - public partial class AppLogic - { - public partial record State - { - [Meta] - public partial record LeavingMenu : State, IGet - { - public LeavingMenu() - { - this.OnEnter(() => Output(new Output.FadeToBlack())); - } - - public Transition On(in Input.FadeOutFinished input) => To(); - } - } - } -} diff --git a/src/app/state/states/LoadingScreen.cs b/src/app/state/states/LoadingScreen.cs new file mode 100644 index 00000000..cd781b10 --- /dev/null +++ b/src/app/state/states/LoadingScreen.cs @@ -0,0 +1,24 @@ +using Chickensoft.Introspection; +using Chickensoft.LogicBlocks; + +namespace GameJamDungeon; + +public partial class AppLogic +{ + public partial record State + { + [Meta] + public partial record LoadingScreen : State, IGet + { + public LoadingScreen() + { + this.OnEnter(() => + { + Output(new Output.ShowLoadingScreen()); + }); + } + + public Transition On(in Input.LoadGameFinished input) => To(); + } + } +} \ No newline at end of file diff --git a/src/app/state/states/MainMenu.cs b/src/app/state/states/MainMenu.cs index fc9e9bc5..9bdd7c64 100644 --- a/src/app/state/states/MainMenu.cs +++ b/src/app/state/states/MainMenu.cs @@ -14,19 +14,19 @@ namespace GameJamDungeon { this.OnEnter(() => { - Output(new Output.SetupGameScene()); - Get().OnMainMenuEntered(); - Output(new Output.ShowMainMenu()); }); } - public Transition On(in Input.NewGame input) => To(); + public Transition On(in Input.NewGame input) + { + Output(new Output.SetupGameScene()); + return To(); + } public Transition On(in Input.QuitGame input) { Output(new Output.ExitGame()); - return ToSelf(); } } diff --git a/src/app/state/states/SplashScreen.cs b/src/app/state/states/SplashScreen.cs deleted file mode 100644 index e00b4f8c..00000000 --- a/src/app/state/states/SplashScreen.cs +++ /dev/null @@ -1,33 +0,0 @@ -using Chickensoft.Introspection; -using Chickensoft.LogicBlocks; - -namespace GameJamDungeon -{ - public partial class AppLogic - { - public partial record State - { - [Meta] - public partial record SplashScreen : State, IGet - { - public SplashScreen() - { - this.OnEnter(() => Output(new Output.ShowSplashScreen())); - - OnAttach( - () => Get().SplashScreenSkipped += OnSplashScreenSkipped - ); - - OnDetach( - () => Get().SplashScreenSkipped -= OnSplashScreenSkipped - ); - } - - public Transition On(in Input.FadeOutFinished input) => To(); - - public void OnSplashScreenSkipped() => - Output(new Output.HideSplashScreen()); - } - } - } -} diff --git a/src/game/Game.cs b/src/game/Game.cs index a07f6cac..5aae8a55 100644 --- a/src/game/Game.cs +++ b/src/game/Game.cs @@ -41,7 +41,7 @@ public partial class Game : Node3D, IGame { GameBinding = GameLogic.Bind(); GameBinding - .Handle((in GameLogic.Output.StartGame _) => { GameRepo.Resume(); }) + .Handle((in GameLogic.Output.StartGame _) => { }) .Handle((in GameLogic.Output.SetPauseMode output) => { CallDeferred(nameof(SetPauseMode), output.IsPaused); }) .Handle((in GameLogic.Output.SetInventoryMode _) => { InventoryMenu.PopulateItems(_.Inventory); InventoryMenu.Show(); }) .Handle((in GameLogic.Output.HideInventory _) => { InventoryMenu.Hide(); InventoryMenu.ClearItems(); }) diff --git a/src/game/IGameRepo.cs b/src/game/IGameRepo.cs index 968579ea..36a905fa 100644 --- a/src/game/IGameRepo.cs +++ b/src/game/IGameRepo.cs @@ -60,7 +60,7 @@ public class GameRepo : IGameRepo { _inventoryItems = new AutoProp>([]); _isInventoryScreenOpened = new AutoProp(false); - _isPaused = new AutoProp(false); + _isPaused = new AutoProp(true); _playerGlobalPosition = new AutoProp(Vector3.Zero); _equippedWeapon = new Weapon(); HPBarValue = new AutoProp(0); diff --git a/src/game/state/states/Playing.cs b/src/game/state/states/Playing.cs index 741e0481..fcc5659d 100644 --- a/src/game/state/states/Playing.cs +++ b/src/game/state/states/Playing.cs @@ -12,7 +12,7 @@ namespace GameJamDungeon { public Playing() { - this.OnEnter(() => { Output(new Output.StartGame()); Get().Resume(); }); + this.OnEnter(() => { Output(new Output.StartGame()); }); OnAttach(() => Get().Ended += OnEnded); OnDetach(() => Get().Ended -= OnEnded); diff --git a/src/menu/Menu.cs b/src/menu/Menu.cs index 6a8ccc83..4b50c49f 100644 --- a/src/menu/Menu.cs +++ b/src/menu/Menu.cs @@ -3,7 +3,6 @@ using Chickensoft.GodotNodeInterfaces; using Chickensoft.Introspection; using GameJamDungeon; using Godot; -using System; public interface IMenu : IControl { diff --git a/src/menu/Menu.tscn b/src/menu/Menu.tscn new file mode 100644 index 00000000..548bdfdb --- /dev/null +++ b/src/menu/Menu.tscn @@ -0,0 +1,40 @@ +[gd_scene load_steps=2 format=3 uid="uid://rfvnddfqufho"] + +[ext_resource type="Script" path="res://src/menu/Menu.cs" id="1_vehpg"] + +[node name="Menu" type="Control"] +layout_mode = 3 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +script = ExtResource("1_vehpg") + +[node name="MarginContainer" type="MarginContainer" parent="."] +layout_mode = 1 +anchors_preset = 15 +anchor_right = 1.0 +anchor_bottom = 1.0 +grow_horizontal = 2 +grow_vertical = 2 +theme_override_constants/margin_left = 100 +theme_override_constants/margin_top = 100 +theme_override_constants/margin_right = 100 +theme_override_constants/margin_bottom = 100 + +[node name="VBoxContainer" type="VBoxContainer" parent="MarginContainer"] +layout_mode = 2 +size_flags_horizontal = 0 +size_flags_vertical = 0 + +[node name="NewGameButton" type="Button" parent="MarginContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "New Game" + +[node name="QuitButton" type="Button" parent="MarginContainer/VBoxContainer"] +unique_name_in_owner = true +layout_mode = 2 +text = "Quit +" diff --git a/src/player/Player.tscn b/src/player/Player.tscn index 5a45589c..59b647cd 100644 --- a/src/player/Player.tscn +++ b/src/player/Player.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=17 format=3 uid="uid://cfecvvav8kkp6"] +[gd_scene load_steps=19 format=3 uid="uid://cfecvvav8kkp6"] [ext_resource type="Script" path="res://src/player/Player.cs" id="1_xcol5"] [ext_resource type="Texture2D" uid="uid://bokx3h8kfdo5i" path="res://src/player/slash_0000_Classic_30.png" id="2_la11l"] @@ -109,6 +109,12 @@ animations = [{ "speed": 12.0 }] +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_kxbln"] +bg_color = Color(0, 0.411765, 0, 1) + +[sub_resource type="StyleBoxFlat" id="StyleBoxFlat_onron"] +bg_color = Color(0, 0.411765, 0, 1) + [node name="Player" type="CharacterBody3D"] collision_layer = 38 collision_mask = 7 @@ -159,6 +165,7 @@ animation = &"attack" [node name="HealthTimer" type="Timer" parent="."] unique_name_in_owner = true +process_mode = 1 wait_time = 3.0 autostart = true @@ -188,6 +195,7 @@ text = "HP: inf/inf" unique_name_in_owner = true custom_minimum_size = Vector2(0, 25) layout_mode = 2 +theme_override_styles/background = SubResource("StyleBoxFlat_kxbln") show_percentage = false [node name="VTNumber" type="Label" parent="MarginContainer/VBoxContainer"] @@ -199,4 +207,5 @@ text = "VT: inf/inf" unique_name_in_owner = true custom_minimum_size = Vector2(0, 25) layout_mode = 2 +theme_override_styles/background = SubResource("StyleBoxFlat_onron") show_percentage = false