• 0 Posts
  • 1 Comment
Joined 10 months ago
cake
Cake day: June 7th, 2024

help-circle
  • I can tell you the approach to these problems in my most recent project.

    In my project, I have a central “MainGame” node that is the root of the scene where the main game loop happens, and then there is an “OverworldManager”, which then hosts “OverworldMap” nodes and swaps them as required, as well as hosting the Player character node as a sibling to the OverworldMap, rather than a descendant of it, so that I can warp it around easily.

    But MainGame has multiple other children, two of them being the InventoryManager and the PersistenceManager nodes. You can access these as soon as you have a reference to the MainGame node by simply calling GetChild(), altough I have wrapper methods for accessing those.

    The InventoryManager node hosts a list of tuples in the form of (ItemType, amount), and it has multiple methods AddItem, RemoveItem, HasItem, etc. All of these just access this list of tuples.

    The PersistenceManager is responsible for keeping track of persistent changes in the many OverworldMaps. It’s just a single wrapper for a list of NodePaths for nodes that have been “flagged”. Because OverworldManager never has more than one map loaded at any given time, every node in the map will keep the same exact NodePath relative to the scene root even if you unload and reload the map. This means that, when for example a locked door or a destructible crate is instantiated as part of the map, you can check in its _Ready function whether the game’s PersistenceManager has flagged the path to this crate, and in that case, just destroy it again or QueueFree it outright. You should then make sure to have the PersistenceManager flag this node when you open it/destroy it/etc. You can actually extend this approach to have the PersistenceManager be able to hold multiple flags with values for a given node.

    Then, when you save the game, you can easily add independent Save and Load functions to each of these managers and call all of them from a SaveManager node if you want to persist the data across runs. Really, all of these managers may as well be autoload scripts, but behind the scenes autoloads are just nodes that are siblings to your root node. Personally, I avoid autoloads entirely because I’d rather manage these nodes myself, but there is nothing wrong per se with using autoloads.

    As for HP and damage; I don’t actually use a node dedicated to HP. Instead, my BattleScene holds Battler nodes, which define their many attributes in battle, one of them being HP. It also has a static function CalculateDamage(Battler attacker, Technique technique, Battler target) that I use to calculate how much HP a given technique should remove, and because it is a private function of Battler, I also get access to private Battler data such as its stat boosts. For persisting the player’s HP, I have a dedicated PlayerManager node. This obviously only makes sense if you have separate Overworld and Battle scenes; if you are fighting enemies in the Overworld in real time, your approach will need to be different.

    I hope that helps.