From 288f0b1916dc0b255cbbbab8d4fa9f93536938f0 Mon Sep 17 00:00:00 2001 From: Gabriel Kaszewski Date: Sat, 31 Jan 2026 17:35:27 +0100 Subject: [PATCH] refactor: Consolidate skill component logic into SkillComponentBase and update manager access to singletons. --- Autoloads/ConsoleManager.cs | 4 +- Autoloads/FloatingTextManager.cs | 12 +++++ Autoloads/GameManager.cs | 10 ++-- Autoloads/GameStateStore.cs | 14 ++++++ Autoloads/SaveSystem.cs | 12 +++++ Autoloads/SkillManager.cs | 16 ++++-- scripts/Events/SkillCollectHandler.cs | 3 +- scripts/Resources/SkillData.cs | 3 +- scripts/UI/DeathScreen.cs | 2 +- scripts/UI/GameOverScreen.cs | 2 +- scripts/UI/Hud.cs | 2 +- scripts/UI/MainMenu.cs | 4 +- scripts/UI/Marketplace.cs | 33 +++++-------- scripts/UI/MarketplaceButton.cs | 4 +- scripts/UI/PauseMenu.cs | 2 +- .../components/BrickArmorSkillComponent.cs | 25 +++++----- .../components/BrickShieldSkillComponent.cs | 30 +++++------- scripts/components/BrickThrowComponent.cs | 40 ++++++--------- .../components/DoubleJumpSkillComponent.cs | 29 +++-------- scripts/components/ExitDoorComponent.cs | 2 +- .../components/GroundPoundSkillComponent.cs | 39 +++++++-------- scripts/components/MagneticSkillComponent.cs | 49 +++++++++---------- scripts/components/PlayerDeathComponent.cs | 2 +- scripts/components/SkillComponentBase.cs | 29 +++++++++++ scripts/components/SkillComponentBase.cs.uid | 1 + scripts/components/SkillUnlockerComponent.cs | 5 +- .../components/XRayVisionSkillComponent.cs | 17 ++++--- 27 files changed, 212 insertions(+), 179 deletions(-) create mode 100644 scripts/components/SkillComponentBase.cs create mode 100644 scripts/components/SkillComponentBase.cs.uid diff --git a/Autoloads/ConsoleManager.cs b/Autoloads/ConsoleManager.cs index a55b84e..af11c8e 100644 --- a/Autoloads/ConsoleManager.cs +++ b/Autoloads/ConsoleManager.cs @@ -13,9 +13,9 @@ public partial class ConsoleManager : Node public override void _Ready() { - _gameManager = GetNode(Constants.GameManagerPath); + _gameManager = GameManager.Instance; _achievementManager = GetNode(Constants.AchievementManagerPath); - _skillManager = GetNode(Constants.SkillManagerPath); + _skillManager = SkillManager.Instance; } private void AddCoinsCommand(int amount) diff --git a/Autoloads/FloatingTextManager.cs b/Autoloads/FloatingTextManager.cs index 125d766..3f475cd 100644 --- a/Autoloads/FloatingTextManager.cs +++ b/Autoloads/FloatingTextManager.cs @@ -14,6 +14,18 @@ public partial class FloatingTextManager : Node [Export] public Color CoinColor { get; set; } = new Color("#ebd320"); // Gold [Export] public Color MessageColor { get; set; } = new Color("#ffffff"); // White + public static FloatingTextManager Instance { get; private set; } + + public override void _Ready() + { + Instance = this; + } + + public override void _ExitTree() + { + if (Instance == this) Instance = null; + } + public void ShowDamage(float amount, Vector2 position) { var text = Mathf.Round(amount * 100f).ToString(CultureInfo.InvariantCulture); diff --git a/Autoloads/GameManager.cs b/Autoloads/GameManager.cs index 55f891e..73ceb8d 100644 --- a/Autoloads/GameManager.cs +++ b/Autoloads/GameManager.cs @@ -30,6 +30,8 @@ public partial class GameManager : Node /// private GameStateStore Store => GameStateStore.Instance; + public static GameManager Instance { get; private set; } + public override void _EnterTree() { GetTree().NodeAdded += OnNodeAdded; @@ -38,6 +40,7 @@ public partial class GameManager : Node public override void _ExitTree() { + if (Instance == this) Instance = null; GetTree().NodeAdded -= OnNodeAdded; GetTree().NodeRemoved -= OnNodeRemoved; _sceneNodes.Clear(); @@ -45,6 +48,7 @@ public partial class GameManager : Node public override void _Ready() { + Instance = this; _speedRunManager = GetNode(Constants.SpeedRunManagerPath); } @@ -140,11 +144,9 @@ public partial class GameManager : Node { if (Store == null) return new Array(); + var skills = Store.GetAllUnlockedSkills(); var result = new Array(); - foreach (var s in Store.Player.UnlockedSkills) - result.Add(s); - foreach (var s in Store.Session.SkillsUnlocked) - if (!result.Contains(s)) result.Add(s); + foreach (var s in skills) result.Add(s); return result; } diff --git a/Autoloads/GameStateStore.cs b/Autoloads/GameStateStore.cs index 46acff8..6279a95 100644 --- a/Autoloads/GameStateStore.cs +++ b/Autoloads/GameStateStore.cs @@ -1,4 +1,5 @@ using Godot; +using System.Collections.Generic; using Mr.BrickAdventures.scripts.Resources; using Mr.BrickAdventures.scripts.State; @@ -163,6 +164,19 @@ public partial class GameStateStore : Node Session.SkillsUnlocked.Clear(); } + /// + /// Gets all unlocked skills from player persistence and current session. + /// + public List GetAllUnlockedSkills() + { + var result = new List(Player.UnlockedSkills); + foreach (var skill in Session.SkillsUnlocked) + { + if (!result.Contains(skill)) result.Add(skill); + } + return result; + } + #endregion #region Reset Operations diff --git a/Autoloads/SaveSystem.cs b/Autoloads/SaveSystem.cs index e48c031..f0d36a4 100644 --- a/Autoloads/SaveSystem.cs +++ b/Autoloads/SaveSystem.cs @@ -14,12 +14,24 @@ public partial class SaveSystem : Node [Export] public string SavePath { get; set; } = "user://savegame.json"; [Export] public int Version { get; set; } = 2; + public static SaveSystem Instance { get; private set; } + private static readonly JsonSerializerOptions JsonOptions = new() { WriteIndented = true, PropertyNamingPolicy = JsonNamingPolicy.CamelCase }; + public override void _Ready() + { + Instance = this; + } + + public override void _ExitTree() + { + if (Instance == this) Instance = null; + } + public void SaveGame() { var store = GameStateStore.Instance; diff --git a/Autoloads/SkillManager.cs b/Autoloads/SkillManager.cs index ae525f4..abaf4be 100644 --- a/Autoloads/SkillManager.cs +++ b/Autoloads/SkillManager.cs @@ -18,6 +18,8 @@ public partial class SkillManager : Node public Dictionary ActiveComponents { get; private set; } = new(); + public static SkillManager Instance { get; private set; } + [Signal] public delegate void ActiveThrowSkillChangedEventHandler(BrickThrowComponent throwComponent); [Signal] @@ -25,9 +27,15 @@ public partial class SkillManager : Node public override void _Ready() { + Instance = this; _gameManager = GetNode(Constants.GameManagerPath); } + public override void _ExitTree() + { + if (Instance == this) Instance = null; + } + /// /// Called by the PlayerController from its _Ready method to register itself with the manager. /// @@ -143,7 +151,6 @@ public partial class SkillManager : Node { if (s.Name == skillName) { - s.IsActive = false; break; } } @@ -188,12 +195,16 @@ public partial class SkillManager : Node return null; } + public bool IsSkillActive(SkillData skill) + { + return skill != null && ActiveComponents.ContainsKey(skill.Name); + } + public void ActivateSkill(SkillData skill) { if (!ActiveComponents.ContainsKey(skill.Name)) { AddSkill(skill); - skill.IsActive = true; } } @@ -202,7 +213,6 @@ public partial class SkillManager : Node if (ActiveComponents.ContainsKey(skill.Name)) { RemoveSkill(skill.Name); - skill.IsActive = false; } } diff --git a/scripts/Events/SkillCollectHandler.cs b/scripts/Events/SkillCollectHandler.cs index e2dd3b3..3c60911 100644 --- a/scripts/Events/SkillCollectHandler.cs +++ b/scripts/Events/SkillCollectHandler.cs @@ -14,7 +14,7 @@ public partial class SkillCollectHandler : Node public override void _Ready() { - _skillManager = GetNode(Constants.SkillManagerPath); + _skillManager = SkillManager.Instance; EventBus.Instance.SkillCollected += OnSkillCollected; } @@ -34,7 +34,6 @@ public partial class SkillCollectHandler : Node GameStateStore.Instance?.UnlockSkillInSession(skill); // Immediately activate the skill for the player - skill.IsActive = true; skill.Level = 1; _skillManager?.AddSkill(skill); diff --git a/scripts/Resources/SkillData.cs b/scripts/Resources/SkillData.cs index 0f06e13..660aba0 100644 --- a/scripts/Resources/SkillData.cs +++ b/scripts/Resources/SkillData.cs @@ -10,11 +10,10 @@ public partial class SkillData : Resource [Export] public string Name { get; set; } = "New Skill"; [Export] public string Description { get; set; } = "New Skill"; [Export] public Texture2D Icon { get; set; } - [Export] public bool IsActive { get; set; } = false; [Export] public int Level { get; set; } = 1; [Export] public SkillType Type { get; set; } = SkillType.Throw; [Export] public PackedScene Node { get; set; } [Export] public Array Upgrades { get; set; } = []; - + public int MaxLevel => Upgrades.Count; } \ No newline at end of file diff --git a/scripts/UI/DeathScreen.cs b/scripts/UI/DeathScreen.cs index e8dfd05..80b56ca 100644 --- a/scripts/UI/DeathScreen.cs +++ b/scripts/UI/DeathScreen.cs @@ -20,7 +20,7 @@ public partial class DeathScreen : Control public override void _Ready() { - _gameManager = GetNode(Constants.GameManagerPath); + _gameManager = GameManager.Instance; // Subscribe to lives changed event for reactive updates EventBus.Instance.LivesChanged += OnLivesChanged; diff --git a/scripts/UI/GameOverScreen.cs b/scripts/UI/GameOverScreen.cs index 514c728..c9e4eed 100644 --- a/scripts/UI/GameOverScreen.cs +++ b/scripts/UI/GameOverScreen.cs @@ -15,7 +15,7 @@ public partial class GameOverScreen : Control public override void _Ready() { - _gameManager = GetNode(Constants.GameManagerPath); + _gameManager = GameManager.Instance; RestartButton.Pressed += OnRestartClicked; MainMenuButton.Pressed += OnMainMenuClicked; } diff --git a/scripts/UI/Hud.cs b/scripts/UI/Hud.cs index cc021a5..1aaf331 100644 --- a/scripts/UI/Hud.cs +++ b/scripts/UI/Hud.cs @@ -16,7 +16,7 @@ public partial class Hud : Control public override void _Ready() { - _gameManager = GetNode(Constants.GameManagerPath); + _gameManager = GameManager.Instance; } public override void _Process(double delta) diff --git a/scripts/UI/MainMenu.cs b/scripts/UI/MainMenu.cs index bf6810f..4b9c161 100644 --- a/scripts/UI/MainMenu.cs +++ b/scripts/UI/MainMenu.cs @@ -22,8 +22,8 @@ public partial class MainMenu : Control public override void _Ready() { - _saveSystem = GetNode(Constants.SaveSystemPath); - _gameManager = GetNode(Constants.GameManagerPath); + _saveSystem = SaveSystem.Instance; + _gameManager = GameManager.Instance; _uiManager = GetNode(Constants.UIManagerPath); NewGameButton.Pressed += OnNewGamePressed; diff --git a/scripts/UI/Marketplace.cs b/scripts/UI/Marketplace.cs index 7cefe6f..1e91681 100644 --- a/scripts/UI/Marketplace.cs +++ b/scripts/UI/Marketplace.cs @@ -26,9 +26,8 @@ public partial class Marketplace : Control public override void _Ready() { - _gameManager = GetNode(Constants.GameManagerPath); - _skillManager = GetNode(Constants.SkillManagerPath); - _skillManager.SkillRemoved += OnSkillRemoved; + _gameManager = GameManager.Instance; + _skillManager = SkillManager.Instance; Skills = _skillManager.AvailableSkills; @@ -42,11 +41,16 @@ public partial class Marketplace : Control foreach (var skill in unlockedSkills) CreateSkillButton(skill); SkillUnlockerComponent.SkillUnlocked += OnSkillUnlocked; + EventBus.Instance.SkillCollected += OnGlobalSkillCollected; } public override void _ExitTree() { SkillUnlockerComponent.SkillUnlocked -= OnSkillUnlocked; + if (EventBus.Instance != null) + { + EventBus.Instance.SkillCollected -= OnGlobalSkillCollected; + } } public override void _Input(InputEvent @event) @@ -81,7 +85,7 @@ public partial class Marketplace : Control foreach (var btn in _skillButtons) { - if (btn.Data.IsActive) btn.Activate(); + if (_skillManager.IsSkillActive(btn.Data)) btn.Activate(); else btn.Deactivate(); } } @@ -118,7 +122,7 @@ public partial class Marketplace : Control if (skill.Level < skill.MaxLevel) { SkillUnlockerComponent.TryUpgradeSkill(skill); - if (!skill.IsActive) SkillUnlockerComponent.SkillManager.ToggleSkillActivation(skill); + if (!SkillUnlockerComponent.SkillManager.IsSkillActive(skill)) SkillUnlockerComponent.SkillManager.ToggleSkillActivation(skill); } else { @@ -137,28 +141,15 @@ public partial class Marketplace : Control foreach (var btn in _skillButtons) { - if (btn.Data.IsActive) + if (SkillUnlockerComponent.SkillManager.IsSkillActive(btn.Data)) btn.Activate(); else btn.Deactivate(); } } - private void OnSkillRemoved(SkillData skill) + private void OnGlobalSkillCollected(SkillData skill, Vector2 position) { - SkillButton buttonToRemove = null; - foreach (var button in _skillButtons) - { - if (button.Data == skill) - { - buttonToRemove = button; - break; - } - } - if (buttonToRemove != null) - { - _skillButtons.Remove(buttonToRemove); - buttonToRemove.QueueFree(); - } + OnSkillUnlocked(skill); } } \ No newline at end of file diff --git a/scripts/UI/MarketplaceButton.cs b/scripts/UI/MarketplaceButton.cs index 1e37e9a..dcd7fe8 100644 --- a/scripts/UI/MarketplaceButton.cs +++ b/scripts/UI/MarketplaceButton.cs @@ -19,7 +19,7 @@ public partial class MarketplaceButton : Button public override void _Ready() { - _gameManager = GetNode(Constants.GameManagerPath); + _gameManager = GameManager.Instance; var player = _gameManager.Player; if (player == null) return; @@ -29,7 +29,7 @@ public partial class MarketplaceButton : Button _skillUnlockerComponent.SkillUnlocked += OnSkillStateChanged; } - _skillManager = GetNode(Constants.SkillManagerPath); + _skillManager = SkillManager.Instance; _skillManager.SkillRemoved += OnSkillStateChanged; UpdateButtonState(); diff --git a/scripts/UI/PauseMenu.cs b/scripts/UI/PauseMenu.cs index efdd60c..746c7ea 100644 --- a/scripts/UI/PauseMenu.cs +++ b/scripts/UI/PauseMenu.cs @@ -19,7 +19,7 @@ public partial class PauseMenu : Control public override void _Ready() { - _gameManager = GetNode(Constants.GameManagerPath); + _gameManager = GameManager.Instance; _uiManager = GetNode(Constants.UIManagerPath); ResumeButton.Pressed += OnResumePressed; diff --git a/scripts/components/BrickArmorSkillComponent.cs b/scripts/components/BrickArmorSkillComponent.cs index 9c1f446..62318c5 100644 --- a/scripts/components/BrickArmorSkillComponent.cs +++ b/scripts/components/BrickArmorSkillComponent.cs @@ -5,26 +5,27 @@ using Mr.BrickAdventures.scripts.Resources; namespace Mr.BrickAdventures.scripts.components; [GlobalClass] -public partial class BrickArmorSkillComponent : Node, ISkill +public partial class BrickArmorSkillComponent : SkillComponentBase { private HealthComponent _healthComponent; - private SkillData _skillData; private float _armorBonus = 0; - - public void Initialize(Node owner, SkillData data) + + public override void Initialize(Node owner, SkillData data) { - if (owner is not PlayerController player) return; - _healthComponent = player.GetNode("HealthComponent"); - _skillData = data; + base.Initialize(owner, data); + if (Player != null) + { + _healthComponent = Player.GetNode("HealthComponent"); + } } - public void Activate() + public override void Activate() { - if (_healthComponent == null || _skillData == null) return; - ApplyUpgrade(_skillData.Upgrades[_skillData.Level - 1]); + if (_healthComponent == null || Data == null) return; + ApplyUpgrade(Data.Upgrades[Data.Level - 1]); } - public void Deactivate() + public override void Deactivate() { if (_healthComponent == null) return; _healthComponent.MaxHealth -= _armorBonus; @@ -35,7 +36,7 @@ public partial class BrickArmorSkillComponent : Node, ISkill _armorBonus = 0; } - public void ApplyUpgrade(SkillUpgrade upgrade) + public override void ApplyUpgrade(SkillUpgrade upgrade) { if (_healthComponent == null || upgrade == null) return; diff --git a/scripts/components/BrickShieldSkillComponent.cs b/scripts/components/BrickShieldSkillComponent.cs index 60cd581..4dec163 100644 --- a/scripts/components/BrickShieldSkillComponent.cs +++ b/scripts/components/BrickShieldSkillComponent.cs @@ -7,41 +7,33 @@ using Mr.BrickAdventures.scripts.Resources; namespace Mr.BrickAdventures.scripts.components; [GlobalClass] -public partial class BrickShieldSkillComponent : Node, ISkill +public partial class BrickShieldSkillComponent : SkillComponentBase { [Export] public PackedScene ShieldScene { get; set; } - private PlayerController _player; private Node2D _shieldInstance; - private SkillData _skillData; private GameManager _gameManager; private SkillManager _skillManager; private HealthComponent _shieldHealth; public override void _Ready() { - _gameManager = GetNode(Constants.GameManagerPath); - _skillManager = GetNode(Constants.SkillManagerPath); + _gameManager = GameManager.Instance; + _skillManager = SkillManager.Instance; } - public void Initialize(Node owner, SkillData data) + public override void Activate() { - _player = owner as PlayerController; - _skillData = data; - } - - public void Activate() - { - if (_player == null || ShieldScene == null || _shieldInstance != null) return; + if (Player == null || ShieldScene == null || _shieldInstance != null) return; _shieldInstance = ShieldScene.Instantiate(); - _player.AddChild(_shieldInstance); + Player.AddChild(_shieldInstance); _shieldInstance.Position = Vector2.Zero; _shieldInstance.TreeExiting += OnShieldDestroyed; _shieldHealth = _shieldInstance.GetNode("HealthComponent"); } - public void Deactivate() + public override void Deactivate() { if (_shieldInstance != null && IsInstanceValid(_shieldInstance)) { @@ -51,7 +43,7 @@ public partial class BrickShieldSkillComponent : Node, ISkill _shieldInstance = null; } - public void ApplyUpgrade(SkillUpgrade upgrade) + public override void ApplyUpgrade(SkillUpgrade upgrade) { upgrade.Properties.TryGetValue("shield_health", out var newHealth); if (_shieldHealth != null) @@ -63,10 +55,10 @@ public partial class BrickShieldSkillComponent : Node, ISkill private void OnShieldDestroyed() { - if (_gameManager != null && _skillData != null && _skillManager != null) + if (_gameManager != null && Data != null && _skillManager != null) { - _gameManager.RemoveSkill(_skillData.Name); - _skillManager.RemoveSkill(_skillData.Name); + _gameManager.RemoveSkill(Data.Name); + _skillManager.RemoveSkill(Data.Name); } _shieldInstance = null; } diff --git a/scripts/components/BrickThrowComponent.cs b/scripts/components/BrickThrowComponent.cs index c6d636c..d916aa2 100644 --- a/scripts/components/BrickThrowComponent.cs +++ b/scripts/components/BrickThrowComponent.cs @@ -5,16 +5,14 @@ using Mr.BrickAdventures.scripts.Resources; namespace Mr.BrickAdventures.scripts.components; [GlobalClass] -public partial class BrickThrowComponent : Node, ISkill +public partial class BrickThrowComponent : SkillComponentBase { [Export] public PackedScene BrickScene { get; set; } [Export] public float FireRate { get; set; } = 1.0f; - [Export] public PlayerController PlayerController { get; set; } [Export] public ThrowInputResource ThrowInputBehavior { get; set; } - + private bool _canThrow = true; private Timer _timer; - private SkillData _skillData; public override void _Ready() { @@ -59,60 +57,54 @@ public partial class BrickThrowComponent : Node, ISkill private void ThrowBrick(float powerMultiplier = 1f) { - if (!_canThrow || PlayerController == null || BrickScene == null) + if (!_canThrow || Player == null || BrickScene == null) return; var instance = BrickScene.Instantiate(); var init = instance.GetNodeOrNull("ProjectileInitComponent"); - + if (init != null) { var @params = new ProjectileInitParams() { - Position = PlayerController.GlobalPosition, - Rotation = PlayerController.Rotation, - Direction = PlayerController.LastDirection, + Position = Player.GlobalPosition, + Rotation = Player.Rotation, + Direction = Player.LastDirection, PowerMultiplier = powerMultiplier, }; - + init.Initialize(@params); } - + GetTree().CurrentScene.AddChild(instance); _canThrow = false; _timer.Start(); } - public void Initialize(Node owner, SkillData data) + public override void Initialize(Node owner, SkillData data) { - PlayerController = owner as PlayerController; - _skillData = data; + base.Initialize(owner, data); ThrowInputBehavior = (ThrowInputResource)ThrowInputBehavior?.Duplicate(); - if (PlayerController == null) + if (Data.Level > 0 && Data.Upgrades.Count >= Data.Level) { - GD.PushError("BrickThrowComponent: Owner is not a PlayerController."); - } - - if (_skillData.Level > 0 && _skillData.Upgrades.Count >= _skillData.Level) - { - ApplyUpgrade(_skillData.Upgrades[_skillData.Level - 1]); + ApplyUpgrade(Data.Upgrades[Data.Level - 1]); } } - public void Activate() + public override void Activate() { if (ThrowInputBehavior != null) ThrowInputBehavior.ThrowRequested += ThrowBrick; SetProcessInput(true); } - public void Deactivate() + public override void Deactivate() { if (ThrowInputBehavior != null) ThrowInputBehavior.ThrowRequested -= ThrowBrick; } - public void ApplyUpgrade(SkillUpgrade upgrade) + public override void ApplyUpgrade(SkillUpgrade upgrade) { foreach (var property in upgrade.Properties) { diff --git a/scripts/components/DoubleJumpSkillComponent.cs b/scripts/components/DoubleJumpSkillComponent.cs index d51221f..c0a2475 100644 --- a/scripts/components/DoubleJumpSkillComponent.cs +++ b/scripts/components/DoubleJumpSkillComponent.cs @@ -6,40 +6,25 @@ using Mr.BrickAdventures.scripts.Resources; namespace Mr.BrickAdventures.scripts.components; [GlobalClass] -public partial class DoubleJumpSkillComponent : Node, ISkill +public partial class DoubleJumpSkillComponent : SkillComponentBase { [Export] private PackedScene _doubleJumpAbilityScene; - private PlayerController _playerController; - - public void Initialize(Node owner, SkillData data) - { - _playerController = owner as PlayerController; - if (_playerController == null) - { - GD.PrintErr("DoubleJumpSkillComponent must be a child of a PlayerController."); - } - } - public void Activate() + public override void Activate() { - if (_playerController == null) return; + if (Player == null) return; - var hasAbility = _playerController.GetActiveAbilities().Any(ability => ability is DoubleJumpAbility); + var hasAbility = Player.GetActiveAbilities().Any(ability => ability is DoubleJumpAbility); if (!hasAbility) { var abilityInstance = _doubleJumpAbilityScene.Instantiate(); - _playerController.AddAbility(abilityInstance); + Player.AddAbility(abilityInstance); } } - public void Deactivate() + public override void Deactivate() { - _playerController?.RemoveAbility(); - } - - public void ApplyUpgrade(SkillUpgrade upgrade) - { - + Player?.RemoveAbility(); } } \ No newline at end of file diff --git a/scripts/components/ExitDoorComponent.cs b/scripts/components/ExitDoorComponent.cs index 602f53e..e32d143 100644 --- a/scripts/components/ExitDoorComponent.cs +++ b/scripts/components/ExitDoorComponent.cs @@ -22,7 +22,7 @@ public partial class ExitDoorComponent : Area2D, IUnlockable public override void _Ready() { - _gameManager = GetNode(Constants.GameManagerPath); + _gameManager = GameManager.Instance; _achievementManager = GetNode(Constants.AchievementManagerPath); BodyEntered += OnExitAreaBodyEntered; diff --git a/scripts/components/GroundPoundSkillComponent.cs b/scripts/components/GroundPoundSkillComponent.cs index 51a91eb..245697c 100644 --- a/scripts/components/GroundPoundSkillComponent.cs +++ b/scripts/components/GroundPoundSkillComponent.cs @@ -5,62 +5,59 @@ using Mr.BrickAdventures.scripts.Resources; namespace Mr.BrickAdventures.scripts.components; [GlobalClass] -public partial class GroundPoundSkillComponent : Node, ISkill +public partial class GroundPoundSkillComponent : SkillComponentBase { [Export] public float PoundForce { get; set; } = 1200f; [Export] public PackedScene ShockwaveScene { get; set; } - - private PlayerController _player; + private PlayerInputHandler _input; private bool _isPounding = false; - - public void Initialize(Node owner, SkillData data) + + public override void Initialize(Node owner, SkillData data) { - _player = owner as PlayerController; - if (_player != null) + base.Initialize(owner, data); + if (Player != null) { - _input = _player.GetNode("PlayerInputHandler"); + _input = Player.GetNode("PlayerInputHandler"); } } public override void _PhysicsProcess(double delta) { - if (_player == null || _input == null) + if (Player == null || _input == null) { return; } - + // Check if we just landed from a ground pound to create the shockwave. - if (_isPounding && _player.IsOnFloor()) + if (_isPounding && Player.IsOnFloor()) { _isPounding = false; if (ShockwaveScene != null) { var shockwave = ShockwaveScene.Instantiate(); - _player.GetParent()?.AddChild(shockwave); - shockwave.GlobalPosition = _player.GlobalPosition; + Player.GetParent()?.AddChild(shockwave); + shockwave.GlobalPosition = Player.GlobalPosition; } } // Check to initiate a ground pound. The player must be in the air. - if (_input.DownHeld && !_player.IsOnFloor() && !_isPounding) + if (_input.DownHeld && !Player.IsOnFloor() && !_isPounding) { // Apply a strong downward force, zeroing out horizontal movement. - _player.Velocity = new Vector2(0, PoundForce); + Player.Velocity = new Vector2(0, PoundForce); _isPounding = true; } } - - public void Activate() + + public override void Activate() { SetPhysicsProcess(true); } - - public void Deactivate() + + public override void Deactivate() { SetPhysicsProcess(false); _isPounding = false; } - - public void ApplyUpgrade(SkillUpgrade upgrade) { } } \ No newline at end of file diff --git a/scripts/components/MagneticSkillComponent.cs b/scripts/components/MagneticSkillComponent.cs index 255a03c..5ce6fa0 100644 --- a/scripts/components/MagneticSkillComponent.cs +++ b/scripts/components/MagneticSkillComponent.cs @@ -7,14 +7,12 @@ using Mr.BrickAdventures.scripts.Resources; namespace Mr.BrickAdventures.scripts.components; [GlobalClass] -public partial class MagneticSkillComponent : Node, ISkill +public partial class MagneticSkillComponent : SkillComponentBase { [Export] public Area2D MagneticArea { get; set; } [Export] public float MagneticMoveDuration { get; set; } = 1.25f; private Array _collectablesToPickUp = []; - private Node2D _owner; - private SkillData _skillData; public override void _Process(double delta) { @@ -25,11 +23,11 @@ public partial class MagneticSkillComponent : Node, ISkill _collectablesToPickUp.Remove(collectable); continue; } - + MoveCollectableToOwner(collectable); } } - + private void OnBodyEntered(Node2D body) { if (!HasComponentInChildren(body, "CollectableComponent")) return; @@ -37,11 +35,11 @@ public partial class MagneticSkillComponent : Node, ISkill if (_collectablesToPickUp.Contains(body)) return; _collectablesToPickUp.Add(body); } - + private void OnAreaEntered(Area2D area) { if (!HasComponentInChildren(area, "CollectableComponent")) return; - + if (_collectablesToPickUp.Contains(area)) return; _collectablesToPickUp.Add(area); } @@ -49,7 +47,7 @@ public partial class MagneticSkillComponent : Node, ISkill private bool HasComponentInChildren(Node node, string componentName) { if (node == null) return false; - + if (node.HasNode(componentName)) return true; foreach (var child in node.GetChildren()) @@ -59,28 +57,27 @@ public partial class MagneticSkillComponent : Node, ISkill return true; } } - + return false; } private void MoveCollectableToOwner(Node2D collectable) { - if (!IsInstanceValid(collectable) || !IsInstanceValid(_owner)) return; - - var direction = (_owner.GlobalPosition - collectable.GlobalPosition).Normalized(); + if (!IsInstanceValid(collectable) || !IsInstanceValid(Player)) return; + + var direction = (Player.GlobalPosition - collectable.GlobalPosition).Normalized(); var speed = direction.Length() / MagneticMoveDuration; collectable.GlobalPosition += direction.Normalized() * speed; } - public void Initialize(Node owner, SkillData data) + public override void Initialize(Node owner, SkillData data) { - _owner = owner as Node2D; - _skillData = data; - - if (_owner == null) + base.Initialize(owner, data); + + if (Player == null) { - GD.PushWarning("MagneticSkillComponent: Owner is not a Node2D."); + GD.PushWarning("MagneticSkillComponent: Owner is not a Player/Node2D."); } if (MagneticArea == null) @@ -96,34 +93,34 @@ public partial class MagneticSkillComponent : Node, ISkill } } } - - if (_skillData.Level > 0 && _skillData.Upgrades.Count >= _skillData.Level) + + if (Data.Level > 0 && Data.Upgrades.Count >= Data.Level) { - ApplyUpgrade(_skillData.Upgrades[_skillData.Level - 1]); + ApplyUpgrade(Data.Upgrades[Data.Level - 1]); } } - public void Activate() + public override void Activate() { if (MagneticArea == null) { GD.PushError("MagneticSkillComponent: MagneticArea is not set."); return; } - + MagneticArea.BodyEntered += OnBodyEntered; MagneticArea.AreaEntered += OnAreaEntered; } - public void Deactivate() + public override void Deactivate() { if (MagneticArea == null) return; - + MagneticArea.BodyEntered -= OnBodyEntered; MagneticArea.AreaEntered -= OnAreaEntered; } - public void ApplyUpgrade(SkillUpgrade upgrade) + public override void ApplyUpgrade(SkillUpgrade upgrade) { foreach (var property in upgrade.Properties) { diff --git a/scripts/components/PlayerDeathComponent.cs b/scripts/components/PlayerDeathComponent.cs index 1482530..c60bd7c 100644 --- a/scripts/components/PlayerDeathComponent.cs +++ b/scripts/components/PlayerDeathComponent.cs @@ -16,7 +16,7 @@ public partial class PlayerDeathComponent : Node2D public override void _Ready() { - _gameManager = GetNode(Constants.GameManagerPath); + _gameManager = GameManager.Instance; HealthComponent.Death += OnDeath; } diff --git a/scripts/components/SkillComponentBase.cs b/scripts/components/SkillComponentBase.cs new file mode 100644 index 0000000..b5e6222 --- /dev/null +++ b/scripts/components/SkillComponentBase.cs @@ -0,0 +1,29 @@ +using Godot; +using Mr.BrickAdventures.scripts.interfaces; +using Mr.BrickAdventures.scripts.Resources; + +namespace Mr.BrickAdventures.scripts.components; + +/// +/// Base class for all skill components to reduce boilerplate. +/// +public abstract partial class SkillComponentBase : Node, ISkill +{ + protected PlayerController Player { get; private set; } + protected SkillData Data { get; private set; } + + public virtual void Initialize(Node owner, SkillData data) + { + Player = owner as PlayerController; + Data = data; + + if (Player == null) + { + GD.PrintErr($"{GetType().Name} must be a child of a PlayerController."); + } + } + + public abstract void Activate(); + public abstract void Deactivate(); + public virtual void ApplyUpgrade(SkillUpgrade upgrade) { } +} diff --git a/scripts/components/SkillComponentBase.cs.uid b/scripts/components/SkillComponentBase.cs.uid new file mode 100644 index 0000000..ff38a53 --- /dev/null +++ b/scripts/components/SkillComponentBase.cs.uid @@ -0,0 +1 @@ +uid://dvuevrf5vr5jk diff --git a/scripts/components/SkillUnlockerComponent.cs b/scripts/components/SkillUnlockerComponent.cs index 956a513..a7cfd5b 100644 --- a/scripts/components/SkillUnlockerComponent.cs +++ b/scripts/components/SkillUnlockerComponent.cs @@ -20,8 +20,8 @@ public partial class SkillUnlockerComponent : Node public override void _Ready() { - _gameManager = GetNode(Constants.GameManagerPath); - SkillManager = GetNode(Constants.SkillManagerPath); + _gameManager = GameManager.Instance; + SkillManager = SkillManager.Instance; } private bool HasEnoughCoins(int amount) @@ -36,7 +36,6 @@ public partial class SkillUnlockerComponent : Node if (!HasEnoughCoins(skill.Upgrades[0].Cost)) return false; skill.Level = 1; - skill.IsActive = true; _gameManager.RemoveCoins(skill.Upgrades[0].Cost); // Add to session state via GameStateStore diff --git a/scripts/components/XRayVisionSkillComponent.cs b/scripts/components/XRayVisionSkillComponent.cs index fdd5ca1..5f3e55e 100644 --- a/scripts/components/XRayVisionSkillComponent.cs +++ b/scripts/components/XRayVisionSkillComponent.cs @@ -5,18 +5,19 @@ using Mr.BrickAdventures.scripts.Resources; namespace Mr.BrickAdventures.scripts.components; [GlobalClass] -public partial class XRayVisionSkillComponent : Node, ISkill +public partial class XRayVisionSkillComponent : SkillComponentBase { [Export(PropertyHint.Layers2DRender)] public uint SecretLayer { get; set; } [Export] public float Duration { get; set; } = 5.0f; - + private Camera2D _camera; private Viewport _viewport; private uint _originalVisibilityLayer; private Timer _timer; - - public void Initialize(Node owner, SkillData data) + + public override void Initialize(Node owner, SkillData data) { + base.Initialize(owner, data); _viewport = GetViewport(); _camera = GetViewport().GetCamera2D(); _timer = new Timer { OneShot = true }; @@ -24,16 +25,16 @@ public partial class XRayVisionSkillComponent : Node, ISkill _timer.Timeout += Deactivate; } - public void Activate() + public override void Activate() { if (_camera == null) return; - + _originalVisibilityLayer = _camera.VisibilityLayer; _camera.VisibilityLayer |= SecretLayer; _timer.Start(Duration); } - public void Deactivate() + public override void Deactivate() { if (_camera != null) { @@ -41,7 +42,7 @@ public partial class XRayVisionSkillComponent : Node, ISkill } } - public void ApplyUpgrade(SkillUpgrade upgrade) + public override void ApplyUpgrade(SkillUpgrade upgrade) { if (upgrade.Properties.TryGetValue("duration", out var newDuration)) {