My goal with coding this RPG is to achieve the following:

  • Neat and organized code achieved by dividing the code into multiple "chunks" (just scripts attached to base Nodes), This way I could avoid the dreaded 300+ lines scripts and also abstract the complexity and encapsulate the logic, Say have a "AttackingManager" Node and a "TakeDamage" Node as children of the parent "Battler" Node

  • Using classes to organize long data, There will be an "Action" class that includes a reference to the battler performing the action + the type of action + action data (attack damage, spell type) + action target (self, enemy, all allies, all enemies), This way we can avoid functions with like 5 arguments.

  • Using inheritance, To simplify logic I'll make a base "Battler" class, Then have 2 child classes being the "AllyBattler" and the "EnemyBattler", Each class will override the parent methods like "decide action" and "defeated" in their own way.

  • Straight and easy to track code, I really don't want any Spaghetti code, I'll try to make it so that a code sequence is in on place, So no jumping around objects to track errors !

  • Using functions to reduce repeated code, If i find myself using a line of code repeatedly then making a little static function to run that code should reduce the risk of error and simplify code !

  • Using an array to handle battler actions, I think that having each battler "decide an action" and then appending that action in an array of "Actions" in the "BattleManager" scene would be a neat way of coding the turn system, when all battlers have appended their actions we'll first sort the actions based on the battlers speed stat, Then we'll iterate over the array and perform each action and remove it once we're done with it.

Anyway that's it, Tell me if you have any criticism !

  • xyz replied to this.

    buzzbuzz20xx Don't overdesign in advance. Although it's good to start with some organizational ideas, it's very hard to anticipate the architecture requirements. Especially if you're at the same time prototyping the game mechanics as well. Be ready to refactor a lot. Add abstractions gradually when the need arises organically as the project grows. Be very conservative with introducing new classes to the system. First make it work then make it neatly designed (if you really must).

    Ditto for introducing new functions. Don't instantly wrap code into "reusable" functions just because it looks like you might reuse it in the future. Wait for the real need to appear. Don't be dogmatic about eliminating all repetition (the famous DRY principle). Sometimes it's not worth the effort.

    Dividing code into too many functions will make it harder to follow. Even if calls are perfectly hierarchically organized, it can still feel spaghetted. It's similar to a problem of deeply nested ifs, only worse because you need to jump through files. Often the code will be much more self explanatory if you just flatten everything out into one long sequence, with various aspects of the task grouped into commented sections. Fewer calls may be better for performance as well.

    Class inheritance is a double edged sword. Keep it to a bare minimum. Ideally, avoid it completely if you can.

    300 lines of code is not much. Develop a tolerance to larger source files. Use editor's folding and search capabilities to navigate with more ease.

    Think a lot about names. Make them short but expressive. Names are much more important than it seems at first.

    Don't use generic OO buzzwords or pattern names in names of your classes and objects, just for the sake of appearing "smart" or "organized". Avoid abstract names like the plague e.g. SomethingSomethingDispatcherComponent.
    A BattleManager is really just a Battle. Unless you have multiple battles going on at the same time. It that case it's simply a War

    Games typically have short lifespans. They are not libraries that require decades long maintenance. However they require good performance. Conclusion: Prioritize performance over insistence on clever design. Half a second delay is nothing for a website. It is a suicide though for a game.

    Offload as much legwork as possible to engine's native code. GDScript is slow but it has many helper classes that you can delegate work to. Often times that means adapting your data architecture to what the engine is expecting, abandoning your neat preconceived organization. Ditto for delegating work to threads.

    Don't watch too many Uncle Bob videos. Watch some by OO heretics like Casey Muratori as well, to get exposed to alternatives to crude OO dogmas.

      I think it's great you're being proactive in thinking about organization. I doubt @xyz has ever had a godot project get completely bogged down in thick spaghetti (already being so experienced & wicked smart), but the rest of us mere mortals should give organization a bit of forethought unless your game is a prototype for a single feature for something else.

      My first real attempt at making a game got so wildly disorganized it became next to impossible for me to add any more features. RIP Stactory.

      On my second attempt I flattened everything out, 15 nodes under the root level node each responsible for their own game system. It doesn't negatively affect me that many are reaching 900 lines as I know what each node (class) is doing. In fact I have a number of huge bloated classes now yet getting into the game and adding new features is still as easy as it was a year ago. Here are my biggest organizational tips:

      1. Similar to what @xyz said, build around godot's nodes first
      2. Pay close attention to the order of which nodes ready up first, initialize first, and enter/exit the tree.
      3. To really avoid a mess, have a consistent way of letting nodes communicate & transfer information
      4. > xyz "Think a lot about names. Make them short but expressive" (and this 100x)

      Good luck with that. I'm doing something similar but trying to keep it on the small side.

      buzzbuzz20xx to add onto all the great responses, also get used to making databases that you can pull from. You can manage code and info a LOT easier when you create a global with shorthand for some of your more frequently used elements so you're not writing filepaths/nodepaths every other line. Helps a lot. Example from my horror game: I made a global database of all my scenes (just a global script with largely constants) and was able to build arrays of those to change my enemy encounter locations on the fly without writing 8 to 9 filepaths per array.