diff --git a/Autoloads/ConsoleManager.cs b/Autoloads/ConsoleManager.cs index 55b78a2..4e39ebf 100644 --- a/Autoloads/ConsoleManager.cs +++ b/Autoloads/ConsoleManager.cs @@ -16,6 +16,7 @@ public partial class ConsoleManager : Node { _gameManager = GetNode("/root/GameManager"); _achievementManager = GetNode("/root/AchievementManager"); + _skillManager = GetNode("/root/SkillManager"); RegisterConsoleCommands(); } @@ -96,13 +97,12 @@ public partial class ConsoleManager : Node private bool GetSkillManagement() { var player = _gameManager.Player; - if (player == null) + if (player == null || !IsInstanceValid(player)) { - LimboConsole.Warn("Player node not found."); + LimboConsole.Warn("Player node not found or is invalid."); return false; } - _skillManager ??= player.GetNode("SkillManager"); _skillUnlockerComponent ??= player.GetNode("SkillUnlockerComponent"); if (_skillManager != null && _skillUnlockerComponent != null) return true; diff --git a/Autoloads/GameManager.cs b/Autoloads/GameManager.cs index 7f355d5..09aeeb3 100644 --- a/Autoloads/GameManager.cs +++ b/Autoloads/GameManager.cs @@ -58,6 +58,10 @@ public partial class GameManager : Node private void OnNodeRemoved(Node node) { _sceneNodes.Remove(node); + if (node == _player) + { + _player = null; + } } public void AddCoins(int amount) @@ -231,7 +235,9 @@ public partial class GameManager : Node public PlayerController GetPlayer() { - if (_player != null) return _player; + if (_player != null && IsInstanceValid(_player)) return _player; + + _player = null; foreach (var node in _sceneNodes) { diff --git a/scripts/SkillManager.cs b/Autoloads/SkillManager.cs similarity index 62% rename from scripts/SkillManager.cs rename to Autoloads/SkillManager.cs index a108a99..3637ee5 100644 --- a/scripts/SkillManager.cs +++ b/Autoloads/SkillManager.cs @@ -1,15 +1,18 @@ +using System.Collections.Generic; +using System.Linq; using Godot; using Godot.Collections; -using Mr.BrickAdventures.Autoloads; using Mr.BrickAdventures.scripts.components; using Mr.BrickAdventures.scripts.interfaces; using Mr.BrickAdventures.scripts.Resources; -namespace Mr.BrickAdventures.scripts; +namespace Mr.BrickAdventures.Autoloads; public partial class SkillManager : Node { private GameManager _gameManager; + private PlayerController _player; + [Export] public Array AvailableSkills { get; set; } = []; public Dictionary ActiveComponents { get; private set; } = new(); @@ -20,11 +23,52 @@ public partial class SkillManager : Node public override void _Ready() { _gameManager = GetNode("/root/GameManager"); - ApplyUnlockedSkills(); + } + + /// + /// Called by the PlayerController from its _Ready method to register itself with the manager. + /// + public void RegisterPlayer(PlayerController player) + { + if (_player == player) return; + + // If a player is already registered (e.g., from a previous scene), unregister it first. + if (_player != null && IsInstanceValid(_player)) + { + UnregisterPlayer(); + } + + _player = player; + if (_player != null) + { + // Automatically unregister when the player node is removed from the scene. + _player.TreeExiting += UnregisterPlayer; + ApplyUnlockedSkills(); + } } + /// + /// Cleans up skills and references related to the current player. + /// + private void UnregisterPlayer() + { + if (_player != null && IsInstanceValid(_player)) + { + _player.TreeExiting -= UnregisterPlayer; + RemoveAllActiveSkills(); + } + _player = null; + } + public void AddSkill(SkillData skillData) { + // Ensure a valid player is registered before adding a skill. + if (_player == null || !IsInstanceValid(_player)) + { + GD.Print("SkillManager: Player not available to add skill."); + return; + } + if (ActiveComponents.ContainsKey(skillData.Name)) return; @@ -42,6 +86,7 @@ public partial class SkillManager : Node break; } } + // Remove other throw skills if a new one is added if (data is { Type: SkillType.Throw }) RemoveSkill(data.Name); } @@ -50,7 +95,8 @@ public partial class SkillManager : Node var instance = skillData.Node.Instantiate(); if (instance is ISkill skill) { - skill.Initialize(Owner, skillData); + // Initialize the skill with the registered player instance. + skill.Initialize(_player, skillData); skill.Activate(); } else @@ -60,12 +106,13 @@ public partial class SkillManager : Node return; } - Owner.AddChild(instance); + // Add the skill node as a child of the player. + _player.AddChild(instance); ActiveComponents[skillData.Name] = instance; if (instance is BrickThrowComponent btc) { - EmitSignalActiveThrowSkillChanged(btc); + EmitSignalActiveThrowSkillChanged(btc); } } @@ -89,7 +136,7 @@ public partial class SkillManager : Node inst.QueueFree(); var skills = _gameManager.GetUnlockedSkills(); - foreach (SkillData s in skills) + foreach (var s in skills) { if (s.Name == skillName) { @@ -99,9 +146,23 @@ public partial class SkillManager : Node } ActiveComponents.Remove(skillName); } + + private void RemoveAllActiveSkills() + { + // Create a copy of keys to avoid modification during iteration + var keys = ActiveComponents.Keys.ToArray(); + var skillNames = keys.Select(key => key.ToString()).ToList(); + + foreach (var skillName in skillNames) + { + RemoveSkill(skillName); + } + } public void ApplyUnlockedSkills() { + if (_player == null || !IsInstanceValid(_player)) return; + foreach (var sd in AvailableSkills) { if (_gameManager.IsSkillUnlocked(sd)) diff --git a/Autoloads/SkillManager.cs.uid b/Autoloads/SkillManager.cs.uid new file mode 100644 index 0000000..f84267a --- /dev/null +++ b/Autoloads/SkillManager.cs.uid @@ -0,0 +1 @@ +uid://dru77vj07e18s diff --git a/objects/entities/brick_player.tscn b/objects/entities/brick_player.tscn index abe19d3..bb7d46f 100644 --- a/objects/entities/brick_player.tscn +++ b/objects/entities/brick_player.tscn @@ -1,4 +1,4 @@ -[gd_scene load_steps=60 format=3 uid="uid://bqi5s710xb1ju"] +[gd_scene load_steps=53 format=3 uid="uid://bqi5s710xb1ju"] [ext_resource type="Script" uid="uid://csel4s0e4g5uf" path="res://scripts/components/PlayerController.cs" id="1_yysbb"] [ext_resource type="Shader" uid="uid://bs4xvm4qkurpr" path="res://shaders/hit_flash.tres" id="2_lgb3u"] @@ -27,16 +27,9 @@ [ext_resource type="Script" uid="uid://dtg6115je7b5s" path="res://scripts/components/StompDamageComponent.cs" id="17_bl1gx"] [ext_resource type="AudioStream" uid="uid://duj2q0rqytaxg" path="res://sfx/jump.wav" id="18_pysae"] [ext_resource type="AudioStream" uid="uid://bmfn6p88gy575" path="res://sfx/player_hurt.wav" id="19_7anly"] -[ext_resource type="Script" uid="uid://d4crrfmbgxnqf" path="res://scripts/Resources/SkillData.cs" id="19_yysbb"] [ext_resource type="AudioStream" uid="uid://ycgtf6wj7mto" path="res://sfx/heal.wav" id="20_bptj5"] -[ext_resource type="Resource" uid="uid://dw5ee2lpeypnb" path="res://resources/skills/brick_throw.tres" id="20_o1ihh"] -[ext_resource type="Resource" uid="uid://cdp8sex36vdq2" path="res://resources/skills/explosive_brick.tres" id="21_ur2y5"] -[ext_resource type="Resource" uid="uid://cr5lo4h8wm0jc" path="res://resources/skills/fire_brick.tres" id="22_7til7"] -[ext_resource type="Resource" uid="uid://ceakv6oqob6m7" path="res://resources/skills/ice_brick.tres" id="23_e5pae"] -[ext_resource type="Resource" uid="uid://d3bjre2etov1n" path="res://resources/skills/magnetic.tres" id="24_xuhvf"] [ext_resource type="Script" uid="uid://dlh5xcv2sy82s" path="res://scripts/components/SkillUnlockerComponent.cs" id="25_yysbb"] [ext_resource type="Script" uid="uid://bo506l4x0808e" path="res://scripts/components/HitComponent.cs" id="26_6n1ss"] -[ext_resource type="Script" uid="uid://di572axt0c3s8" path="res://scripts/SkillManager.cs" id="26_uno3u"] [ext_resource type="Script" uid="uid://cjcc7fia15wu3" path="res://scripts/components/CanBeLaunchedComponent.cs" id="27_oefns"] [ext_resource type="PackedScene" uid="uid://bg76mtpcmfm2j" path="res://objects/ui/charging_bar_layer.tscn" id="28_3f5nm"] [ext_resource type="Script" uid="uid://cqau0810tjk4d" path="res://scripts/components/TriggerLeverComponent.cs" id="28_bnap0"] @@ -223,13 +216,8 @@ Damage = 4.0 Area = NodePath("../StompDamageArea") Root = NodePath("..") -[node name="SkillManager" type="Node" parent="."] -script = ExtResource("26_uno3u") -AvailableSkills = Array[ExtResource("19_yysbb")]([ExtResource("20_o1ihh"), ExtResource("21_ur2y5"), ExtResource("22_7til7"), ExtResource("23_e5pae"), ExtResource("24_xuhvf")]) - -[node name="SkillUnlockerComponent" type="Node" parent="." node_paths=PackedStringArray("SkillManager")] +[node name="SkillUnlockerComponent" type="Node" parent="."] script = ExtResource("25_yysbb") -SkillManager = NodePath("../SkillManager") [node name="HitComponent" type="Node" parent="." node_paths=PackedStringArray("Sprite", "Health", "HitFx")] script = ExtResource("26_6n1ss") @@ -267,12 +255,11 @@ bus = &"sfx" stream = ExtResource("32_x2b7c") bus = &"sfx" -[node name="ChargingBarLayer" parent="." node_paths=PackedStringArray("_skillManager") instance=ExtResource("28_3f5nm")] +[node name="ChargingBarLayer" parent="." instance=ExtResource("28_3f5nm")] offset_left = -17.0 offset_top = -30.0 offset_right = 23.0 offset_bottom = -20.0 -_skillManager = NodePath("../SkillManager") [node name="HitParticles" parent="." instance=ExtResource("28_jh5m0")] process_material = SubResource("ParticleProcessMaterial_lgb3u") diff --git a/objects/skill_manager.tscn b/objects/skill_manager.tscn new file mode 100644 index 0000000..8cb1e10 --- /dev/null +++ b/objects/skill_manager.tscn @@ -0,0 +1,13 @@ +[gd_scene load_steps=8 format=3 uid="uid://bi6v7u17vg1ww"] + +[ext_resource type="Script" uid="uid://dru77vj07e18s" path="res://Autoloads/SkillManager.cs" id="1_31033"] +[ext_resource type="Script" uid="uid://d4crrfmbgxnqf" path="res://scripts/Resources/SkillData.cs" id="2_87da4"] +[ext_resource type="Resource" uid="uid://dw5ee2lpeypnb" path="res://resources/skills/brick_throw.tres" id="3_shjvi"] +[ext_resource type="Resource" uid="uid://cdp8sex36vdq2" path="res://resources/skills/explosive_brick.tres" id="4_53vnv"] +[ext_resource type="Resource" uid="uid://cr5lo4h8wm0jc" path="res://resources/skills/fire_brick.tres" id="5_77gav"] +[ext_resource type="Resource" uid="uid://ceakv6oqob6m7" path="res://resources/skills/ice_brick.tres" id="6_gib8v"] +[ext_resource type="Resource" uid="uid://d3bjre2etov1n" path="res://resources/skills/magnetic.tres" id="7_6wy8o"] + +[node name="SkillManager" type="Node"] +script = ExtResource("1_31033") +AvailableSkills = Array[ExtResource("2_87da4")]([ExtResource("3_shjvi"), ExtResource("4_53vnv"), ExtResource("5_77gav"), ExtResource("6_gib8v"), ExtResource("7_6wy8o")]) diff --git a/project.godot b/project.godot index 2043fbf..096ff93 100644 --- a/project.godot +++ b/project.godot @@ -41,6 +41,7 @@ DialogueManager="*res://addons/dialogue_manager/dialogue_manager.gd" SteamManager="*res://Autoloads/SteamManager.cs" AchievementManager="*res://objects/achievement_manager.tscn" DamageNumberManager="*res://objects/damage_number_manager.tscn" +SkillManager="*res://objects/skill_manager.tscn" [debug] diff --git a/scripts/SkillManager.cs.uid b/scripts/SkillManager.cs.uid deleted file mode 100644 index dc14de7..0000000 --- a/scripts/SkillManager.cs.uid +++ /dev/null @@ -1 +0,0 @@ -uid://di572axt0c3s8 diff --git a/scripts/UI/ChargeProgressBar.cs b/scripts/UI/ChargeProgressBar.cs index aab9776..91654ef 100644 --- a/scripts/UI/ChargeProgressBar.cs +++ b/scripts/UI/ChargeProgressBar.cs @@ -8,8 +8,8 @@ namespace Mr.BrickAdventures.scripts.UI; public partial class ChargeProgressBar : ProgressBar { [Export] public ProgressBar ProgressBar { get; set; } - [Export] private SkillManager _skillManager; + private SkillManager _skillManager; private BrickThrowComponent _throwComponent; private ChargeThrowInputResource _throwInput; @@ -17,8 +17,10 @@ public partial class ChargeProgressBar : ProgressBar { ProgressBar.Hide(); + _skillManager = GetNodeOrNull("/root/SkillManager"); if (_skillManager == null) { + GD.PrintErr("ChargeProgressBar: SkillManager autoload not found."); return; } @@ -26,12 +28,21 @@ public partial class ChargeProgressBar : ProgressBar SetupDependencies(); } - + + public override void _ExitTree() + { + if (_skillManager != null && IsInstanceValid(_skillManager)) + { + _skillManager.ActiveThrowSkillChanged -= OnActiveThrowSkillChanged; + } + OnOwnerExiting(); + } + private void OnActiveThrowSkillChanged(BrickThrowComponent throwComponent) { OnOwnerExiting(); - if (throwComponent == null) return; + if (throwComponent == null || !IsInstanceValid(throwComponent)) return; _throwComponent = throwComponent; _throwComponent.TreeExiting += OnOwnerExiting; diff --git a/scripts/components/PlayerController.cs b/scripts/components/PlayerController.cs index d2e5b89..27695af 100644 --- a/scripts/components/PlayerController.cs +++ b/scripts/components/PlayerController.cs @@ -2,6 +2,7 @@ using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using Godot; +using Mr.BrickAdventures.Autoloads; namespace Mr.BrickAdventures.scripts.components; @@ -31,6 +32,9 @@ public partial class PlayerController : CharacterBody2D public override void _Ready() { + var skillManager = GetNodeOrNull("/root/SkillManager"); + skillManager?.RegisterPlayer(this); + _inputHandler = GetNode("PlayerInputHandler"); foreach (var child in MovementAbilitiesContainer.GetChildren()) { diff --git a/scripts/components/SkillUnlockerComponent.cs b/scripts/components/SkillUnlockerComponent.cs index 4bf6a2f..a2029ac 100644 --- a/scripts/components/SkillUnlockerComponent.cs +++ b/scripts/components/SkillUnlockerComponent.cs @@ -8,7 +8,7 @@ namespace Mr.BrickAdventures.scripts.components; public partial class SkillUnlockerComponent : Node { - [Export] public SkillManager SkillManager { get; set; } + public SkillManager SkillManager { get; private set; } [Signal] public delegate void SkillUnlockedEventHandler(SkillData skill); @@ -18,6 +18,7 @@ public partial class SkillUnlockerComponent : Node public override void _Ready() { _gameManager = GetNode("/root/GameManager"); + SkillManager = GetNode("/root/SkillManager"); } private bool HasEnoughCoins(int amount)