diff --git a/IsoTest/IsoMapTest2.tscn b/IsoTest/IsoMapTest2.tscn index 9420d1e6..89e96067 100644 --- a/IsoTest/IsoMapTest2.tscn +++ b/IsoTest/IsoMapTest2.tscn @@ -1,7 +1,9 @@ -[gd_scene load_steps=55 format=3 uid="uid://ec4m3geediis"] +[gd_scene load_steps=57 format=3 uid="uid://ec4m3geediis"] [ext_resource type="Script" uid="uid://cvisn0b641od4" path="res://addons/cyclops_level_builder/nodes/cyclops_block.gd" id="1_18fbr"] [ext_resource type="Script" uid="uid://ba0tf7ihw4hpp" path="res://Scripts/Misc/CameraController3D.cs" id="1_g4gcm"] +[ext_resource type="Script" uid="uid://b8g8mflgsr5dc" path="res://Scripts/GameController.cs" id="1_joeuf"] +[ext_resource type="PackedScene" uid="uid://dkwi1hu1bixoe" path="res://Scenes/HUD/HUD.tscn" id="2_itd0i"] [ext_resource type="Script" uid="uid://djeq3sxhsep3c" path="res://addons/cyclops_level_builder/resources/data_vector_byte.gd" id="2_kler0"] [ext_resource type="Script" uid="uid://civ3w78ahacnu" path="res://addons/cyclops_level_builder/resources/data_vector_int.gd" id="3_k6bah"] [ext_resource type="Script" uid="uid://db41w3h28c2la" path="res://addons/cyclops_level_builder/resources/data_vector_float.gd" id="4_01bfr"] @@ -411,6 +413,11 @@ face_vertex_data = { [node name="IsoMapTest2" type="Node3D"] +[node name="GameController" type="Node" parent="."] +script = ExtResource("1_joeuf") + +[node name="HUD" parent="GameController" instance=ExtResource("2_itd0i")] + [node name="block0" type="Node3D" parent="."] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -3, 0, 0) script = ExtResource("1_18fbr") @@ -467,6 +474,7 @@ CameraOffset = Vector3(8, 12, 8) TargetPath = NodePath("../IsoPlayerFsm") [node name="CanvasLayer" type="CanvasLayer" parent="."] +visible = false [node name="FPS" type="Label" parent="CanvasLayer"] z_index = 20 diff --git a/Scenes/Actors/IsoPlayer_FSM.tscn b/Scenes/Actors/IsoPlayer_FSM.tscn index 077d3aaf..19bc91b7 100644 --- a/Scenes/Actors/IsoPlayer_FSM.tscn +++ b/Scenes/Actors/IsoPlayer_FSM.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=15 format=3 uid="uid://rimplblbptcd"] +[gd_scene load_steps=19 format=3 uid="uid://rimplblbptcd"] [ext_resource type="Script" uid="uid://88smibkin17p" path="res://Scripts/Components/FSM/3DPlayer/IsoPlayerFSMProxy.cs" id="1_cc7e7"] [ext_resource type="Texture2D" uid="uid://ddwhrlrgj6i00" path="res://Sprites/Actors/Cirno.png" id="1_vex34"] @@ -10,6 +10,9 @@ [ext_resource type="Script" uid="uid://dq338w2lw5phl" path="res://Scripts/Components/Actors/KeyboardInputProvider.cs" id="7_4cdxq"] [ext_resource type="Script" uid="uid://c8ar11sg0su2h" path="res://Scripts/Components/FSM/3DPlayer/ShadowModule.cs" id="9_fg04g"] [ext_resource type="Script" uid="uid://bm73kgly8gv2i" path="res://Scripts/Components/FSM/3DPlayer/IsoInteractionController.cs" id="10_habpy"] +[ext_resource type="Script" uid="uid://d1ixvdcii6uy7" path="res://Scripts/Components/FSM/3DPlayer/SelectorController.cs" id="11_4cdxq"] +[ext_resource type="Script" uid="uid://vne180ohyucn" path="res://Scripts/Components/FSM/3DPlayer/IsoActivationProvider.cs" id="11_4exx2"] +[ext_resource type="AudioStream" uid="uid://myr6n2c1u503" path="res://SFX/581602__samsterbirdies__beep-error.mp3" id="13_2ffwi"] [sub_resource type="CapsuleShape3D" id="CapsuleShape3D_fg04g"] radius = 0.349554 @@ -27,6 +30,10 @@ material = SubResource("StandardMaterial3D_cc7e7") [sub_resource type="CylinderShape3D" id="CylinderShape3D_habpy"] height = 0.679688 +[sub_resource type="CylinderShape3D" id="CylinderShape3D_6d8x8"] +height = 1.0415 +radius = 1.5708 + [node name="IsoPlayerFsm" type="CharacterBody3D" node_paths=PackedStringArray("PlayerFSM")] collision_layer = 2 script = ExtResource("1_cc7e7") @@ -40,7 +47,7 @@ script = ExtResource("2_3oyrx") [node name="Active" type="Node" parent="StateMachine" node_paths=PackedStringArray("_moduleNodes")] script = ExtResource("3_cc7e7") -_moduleNodes = [NodePath("../../InputProvider"), NodePath("../../MovementModule"), NodePath("../../ShadowModule"), NodePath("../../InteractionController")] +_moduleNodes = [NodePath("../../InputProvider"), NodePath("../../MovementModule"), NodePath("../../ShadowModule"), NodePath("../../InteractionController"), NodePath("../../ActivationProvider")] [node name="Sprite" type="Sprite3D" parent="."] transform = Transform3D(0.707107, -0.5, 0.5, 0, 0.707107, 0.707107, -0.707107, -0.5, 0.5, 0, 0, 0) @@ -91,3 +98,22 @@ script = ExtResource("10_habpy") [node name="CollisionShape3D" type="CollisionShape3D" parent="InteractionController"] transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.0410156, 0) shape = SubResource("CylinderShape3D_habpy") + +[node name="ActivationProvider" type="Area3D" parent="." node_paths=PackedStringArray("_inputProvider", "_selectorController", "_errorSound")] +collision_layer = 0 +collision_mask = 32 +script = ExtResource("11_4exx2") +_inputProvider = NodePath("../InputProvider") +_selectorController = NodePath("SelectorController") +_errorSound = NodePath("AudioStreamPlayer") + +[node name="CollisionShape3D" type="CollisionShape3D" parent="ActivationProvider"] +transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0.224854, 0) +shape = SubResource("CylinderShape3D_6d8x8") + +[node name="SelectorController" type="Node" parent="ActivationProvider"] +script = ExtResource("11_4cdxq") + +[node name="AudioStreamPlayer" type="AudioStreamPlayer" parent="ActivationProvider"] +stream = ExtResource("13_2ffwi") +bus = &"Effects" diff --git a/Scripts/Components/Actors/ActivationProvider.cs b/Scripts/Components/Actors/ActivationProvider.cs index 3ba087e0..a9dc723f 100644 --- a/Scripts/Components/Actors/ActivationProvider.cs +++ b/Scripts/Components/Actors/ActivationProvider.cs @@ -13,8 +13,7 @@ public partial class ActivationProvider : Area2D [Export] public PackedScene SelectorScene { get; set; } - [Export] - private InputProvider _inputProvider; + [Export] private InputProvider _inputProvider; [Export] private AudioStreamPlayer2D _errorSound; diff --git a/Scripts/Components/Actors/EnemyPossessionMovement.cs b/Scripts/Components/Actors/EnemyPossessionMovement.cs index 084d0848..bab1e7e9 100644 --- a/Scripts/Components/Actors/EnemyPossessionMovement.cs +++ b/Scripts/Components/Actors/EnemyPossessionMovement.cs @@ -1,3 +1,4 @@ +using Cirno.Scripts; using Cirno.Scripts.Components.Actors; using Godot; diff --git a/Scripts/Components/FSM/3DPlayer/IsoActivationProvider.cs b/Scripts/Components/FSM/3DPlayer/IsoActivationProvider.cs new file mode 100644 index 00000000..8c2003cf --- /dev/null +++ b/Scripts/Components/FSM/3DPlayer/IsoActivationProvider.cs @@ -0,0 +1,143 @@ +using Cirno.Scripts.Components.Actors; +using Cirno.Scripts.Interactables; +using Godot; + +namespace Cirno.Scripts.Components.FSM._3DPlayer; + +public partial class IsoActivationProvider: Area3D, IModule +{ + + private bool _enabled = false; + + public bool Enabled + { + get => _enabled; + set + { + if (_enabled == value) return; + _enabled = value; + } + } + + [Export] private InputProvider _inputProvider; + [Export] private SelectorController _selectorController; + + [Export] private AudioStreamPlayer _errorSound; + + [Export] public PackedScene SelectorScene { get; set; } + + + public IStateMachine StateMachine { get; private set; } + + public void EnterState(PlayerState state) + { + Enabled = true; + AreaEntered += _on_interaction_controller_area_entered; + AreaExited += _on_interaction_controller_area_exited; + } + + public void ExitState(PlayerState state) + { + Enabled = false; + AreaEntered -= _on_interaction_controller_area_entered; + AreaExited -= _on_interaction_controller_area_exited; + } + + public void Init(IStateMachine machine) + { + StateMachine = machine; + + _selectorController.Hide(); + + // TODO: Create selector UI element and link the signals + + // if (SelectorScene is not null && _selector is null) + // { + // _selector = actor.CreateSibling(SelectorScene, this.GlobalPosition); + // _selector.Visible = false; + // } + } + + public void Process(double delta) + { + + } + + public void PhysicsProcess(double delta) + { + + } + + public void HandleInteraction() + { + if (_inputProvider.GetUseJustPressed()) + { + if (!TrySelect()) + { + _selectorController.SelectNext(); + } + + return; + } + + if (_inputProvider.GetScanJustPressed()) + { + _selectorController.SelectNext(); + } + } + + private bool TrySelect() + { + var selected = _selectorController.SelectedInteractable; + if (selected is null) + { + _errorSound?.Play(); + return false; + }; + if (!selected.CanActivate()) + { + _errorSound?.Play(); + return true; + }; + bool success = selected.Activate(ActivationType.Use); + + if (success) + { + // Deselect and scan for next + _selectorController.SelectNext(); + //_selector.RemoveInteractable(selected); + } + else + { + _errorSound?.Play(); + } + + return true; + //var spaceState = GetWorld2D().DirectSpaceState; + + //var query = PhysicsRayQueryParameters2D.Create(Vector2.Zero, ) + } + + private void _on_interaction_controller_area_entered(Area3D area) + { + if (!Enabled) return; + if (area.IsInGroup("Interactable") && area is IInteractable interactable && interactable.CanActivate()) + { + + //if (_selector == null) return; + + _selectorController.AddInteractable(interactable); + } + } + + private void _on_interaction_controller_area_exited(Area3D area) + { + //if (!Enabled) return; + if (area.IsInGroup("Interactable") && area is IInteractable interactable) + { + + //if (_selector == null) return; + _selectorController.RemoveInteractable(interactable); + } + } +} \ No newline at end of file diff --git a/Scripts/Components/FSM/3DPlayer/IsoActivationProvider.cs.uid b/Scripts/Components/FSM/3DPlayer/IsoActivationProvider.cs.uid new file mode 100644 index 00000000..3f138ce1 --- /dev/null +++ b/Scripts/Components/FSM/3DPlayer/IsoActivationProvider.cs.uid @@ -0,0 +1 @@ +uid://vne180ohyucn diff --git a/Scripts/Components/FSM/3DPlayer/SelectorController.cs b/Scripts/Components/FSM/3DPlayer/SelectorController.cs new file mode 100644 index 00000000..e44d1956 --- /dev/null +++ b/Scripts/Components/FSM/3DPlayer/SelectorController.cs @@ -0,0 +1,139 @@ +using System.Collections.Generic; +using Cirno.Scripts.Interactables; +using Godot; + +namespace Cirno.Scripts.Components.FSM._3DPlayer; + +public partial class SelectorController : Node +{ + [Signal] public delegate void ShowSelectorEventHandler(); + [Signal] public delegate void HideSelectorEventHandler(); + [Signal] public delegate void ChangePositionEventHandler(Vector2 position); + + private Interactable _lastInteractable; + + private List _interactables = []; + + private int _selectedInteractable; + + private int SelectedInteractableIndex + { + get => _selectedInteractable; + set + { + if (value >= _interactables.Count) + { + _selectedInteractable = 0; + } + + if (value < 0) + { + _selectedInteractable = _interactables.Count - 1; + } + } + } + + public IInteractable SelectedInteractable + { + get => + _interactables.Count > 0 + ? SelectedInteractableIndex >= _interactables.Count + ? _interactables[^1] + : _interactables[SelectedInteractableIndex] + : null; + set + { + // Passing null deselects the interactable + if (value == null) + { + _selectedInteractable = -1; + NotifyChanged(null); + return; + } + + // If it's already in the list, set the current one to it, otherwise add it + if (!_interactables.Contains(value)) + { + AddInteractable(value); + } + + SelectedInteractableIndex = _interactables.IndexOf(value); + NotifyChanged(value); + } + } + + public void SelectNext() + { + SelectedInteractableIndex += 1; + // _selectedInteractable += 1; + // if (_selectedInteractable >= _interactables.Count) + // { + // _selectedInteractable = 0; + // } + + if (_interactables.Count > 0) + { + SelectedInteractable = _interactables[_selectedInteractable]; + } + else + { + _selectedInteractable = -1; + } + + UpdatePosition(); + } + + public void AddInteractable(IInteractable interactable) + { + if (!_interactables.Contains(interactable)) + { + _interactables.Add(interactable); + + if (_interactables.Count == 1) + { + _selectedInteractable = 0; + } + } + + UpdatePosition(); + } + + public void RemoveInteractable(IInteractable interactable) + { + if (_interactables.Contains(interactable)) + { + _interactables.Remove(interactable); + } + + UpdatePosition(); + } + + public void Deselect() + { + _selectedInteractable = -1; + EmitSignalHideSelector(); + } + + public void UpdatePosition() + { + if (SelectedInteractable != null) + { + EmitSignalChangePosition(SelectedInteractable.GetGlobalPosition()); + EmitSignalShowSelector(); + } + else + { + EmitSignalHideSelector(); + } + } + + private void NotifyChanged(IInteractable interactable) + { + //EmitSignal(nameof(SelectedItemInteractableChanged), interactable); + } + + public void Hide() + { + EmitSignalHideSelector(); + } +} \ No newline at end of file diff --git a/Scripts/Components/FSM/3DPlayer/SelectorController.cs.uid b/Scripts/Components/FSM/3DPlayer/SelectorController.cs.uid new file mode 100644 index 00000000..da87161f --- /dev/null +++ b/Scripts/Components/FSM/3DPlayer/SelectorController.cs.uid @@ -0,0 +1 @@ +uid://d1ixvdcii6uy7 diff --git a/Scripts/GameController.cs b/Scripts/GameController.cs new file mode 100644 index 00000000..455678bc --- /dev/null +++ b/Scripts/GameController.cs @@ -0,0 +1,168 @@ +using Cirno.Scripts.Enums; +using Cirno.Scripts.Misc; +using Cirno.Scripts.Resources; +using Godot; + +namespace Cirno.Scripts; + +public partial class GameController : Node +{ + public static GameController Instance { get; private set; } + + private Hud _hud; + + public GameState GameState { get; private set; } + + [Signal] public delegate void GameStateChangeEventHandler(GameState state); + + [Signal] public delegate void ManagerReadyEventHandler(); + + [Export] public StringName PauseActionName { get; private set; } = "pause"; + + public override void _Ready() + { + Instance = this; + RenderingServer.SetDefaultClearColor(Colors.Black); + if (GlobalState.Instance.SessionSettings.GameMode is GameMode.Roguelite) + { + if (GlobalState.Instance.SessionSettings.LevelNumber < 0) + { + // TODO: Change based on which level we're going to + GlobalState.Instance.SessionSettings.LevelNumber = 0; + } + } + else + { + //GlobalState.Session.LevelNumber = MapResource.LevelId; + } + + + GlobalState.Instance.ChangeCursor(false); + + if (GlobalState.Instance.SessionSettings.AllowSaving) + { + GlobalState.Instance.SaveGame(); + } + + //_audioManager = new AudioManager(); + // this.AddChild(_audioManager); + + _hud = GetNodeOrNull("HUD"); + if (_hud == null) GD.Print("No HUD in scene."); + + //_cameraTarget = GetNodeOrNull("CameraTarget"); + //if (_cameraTarget == null) GD.Print("No camera target in scene."); + + // _inventoryManager = GetNodeOrNull("InventoryManager"); + //if (_inventoryManager == null) GD.Print("No inventory manager in scene."); + + + //SpawnBulletsContainer(); + + if (_hud != null) + { + this.GameStateChange += _hud.OnGameStateChanged; + } + + // if (_inventoryManager != null && _hud != null) + // { + // + // _inventoryManager.WeaponUpdate += key => _hud.EquipWeapon(key); + // } + + //PlayerRespawned += OnPlayerRespawned; + + GameState = GameState.Playing; + + + + //CallDeferred(MethodName.DelayPlayerSpawn); + + CallDeferred(MethodName.OnFinished); + } + + private void OnFinished() + { + EmitSignalManagerReady(); + } + + public override void _Process(double delta) + { + if (GameState is GameState.Paused && Input.IsActionJustPressed(PauseActionName)) + { + Unpause(); + } + } + + public void Pause() + { + if (GameState == GameState.Playing) + { + ChangeState(GameState.Paused); + } + } + + public void Unpause() + { + if (GameState == GameState.Paused) + { + CallDeferred(MethodName.ChangeState, (int)GameState.Playing); + //ChangeState(GameState.Playing); + } + } + + public GameState ToggleControlMode() + { + if (GameState is GameState.Playing) + { + ChangeState(GameState.Controlling); + } + else if (GameState is GameState.Controlling) + { + ChangeState(GameState.Playing); + } + + return GameState; + } + + public void ChangeState(GameState state) + { + if (state == GameState) return; + GameState = state; + EmitSignal(SignalName.GameStateChange, (int)state); + GD.Print($"Game state changed to {state}"); + + switch (state) + { + case GameState.Paused: + case GameState.Dialogue: + case GameState.Shop: + case GameState.Inventory: + GlobalState.Instance.ChangeCursor(true); + + GetTree().SetPause(true); + //Input.MouseMode = Input.MouseModeEnum.Visible; + break; + case GameState.Playing: + case GameState.Controlling: + //Input.MouseMode = Input.MouseModeEnum.Confined; + GlobalState.Instance.ChangeCursor(false); + DelayedUnpause(); + //CallDeferred(MethodName.DelayedUnpause); + //GetTree().SetPause(false); + break; + case GameState.Menu: + GlobalState.Instance.ChangeCursor(true); + //Input.MouseMode = Input.MouseModeEnum.Visible; + DelayedUnpause(); + //CallDeferred(MethodName.DelayedUnpause); + //GetTree().SetPause(false); + break; + } + } + + private void DelayedUnpause() + { + GetTree().SetPause(false); + } +} \ No newline at end of file diff --git a/Scripts/GameController.cs.uid b/Scripts/GameController.cs.uid new file mode 100644 index 00000000..1261afbe --- /dev/null +++ b/Scripts/GameController.cs.uid @@ -0,0 +1 @@ +uid://b8g8mflgsr5dc diff --git a/Scripts/GameManager.cs b/Scripts/GameManager.cs index 48c8705c..3dabfd6f 100644 --- a/Scripts/GameManager.cs +++ b/Scripts/GameManager.cs @@ -415,15 +415,4 @@ public partial class GameManager : Node2D GD.Print("Rebaking tilemap"); //NavigationRegion.BakeNavigationPolygon(true); } -} - -public enum GameState -{ - Menu, - Paused, - Playing, - Dialogue, - Controlling, - Inventory, - Shop } \ No newline at end of file diff --git a/Scripts/GameState.cs b/Scripts/GameState.cs new file mode 100644 index 00000000..b2a055ba --- /dev/null +++ b/Scripts/GameState.cs @@ -0,0 +1,12 @@ +namespace Cirno.Scripts; + +public enum GameState +{ + Menu, + Paused, + Playing, + Dialogue, + Controlling, + Inventory, + Shop +} \ No newline at end of file diff --git a/Scripts/GameState.cs.uid b/Scripts/GameState.cs.uid new file mode 100644 index 00000000..850e695a --- /dev/null +++ b/Scripts/GameState.cs.uid @@ -0,0 +1 @@ +uid://web5o6tevx28 diff --git a/Scripts/Hud.cs b/Scripts/Hud.cs index 161b76b1..dc7e9d75 100644 --- a/Scripts/Hud.cs +++ b/Scripts/Hud.cs @@ -79,7 +79,10 @@ public partial class Hud : CanvasLayer //_healthLabel = GetNode