Let's say I have a hypothetical scene like this with components and states attached to a node. The underlying code may be ignored for the time being.

So here, I have a bunch of components, each with their own individual code to run the specific things they do. I have states also as nodes, which will usually be modifying components so that they do the required action, like RunState would set the velocity in VelocityComponent to some velocity so it will start moving, and IdleState would set the velocity in VelocityComponent to (0,0) so it stops moving. So on and so forth, all good thus far.

Now, let's say that I want to add a new feature to my enemies so that, whenever they take damage, it will play a squish + flash effect on the enemy. The HitboxComponent could send a signal for when it detects a collision and the squish and flash components can listen to that signal. Naturally I would make some components for this as well.

This is all fine too. However, imagine that I have only started adding this feature on the 101st enemy. I now have to go through the 100 other enemies I made before this enemy just to add these components. That would take a lot of time that wouldn't really be worth it. This seems to be a situation where inheritance would actually help, but I have no idea how to fit inheritance in such a setup, so my setup is a little flawed in this scenario.

My question is, how would I handle node composition like this in such case? Is there anything I could change with this setup so that it makes it easy to update my nodes in the future? I want my components and states to be independent from each other so that I can reuse them for my other projects, so something that gives me the benefit of having multiple independent components while also being able to update my nodes/classes quickly so they have similar behavior.

NOTE: I'm aware that you can use 'Inherited Scene' in Godot, but I was wondering if there was a way to avoid using it. It's a little unreliable as it does seldom break, but I can always use Git in case scenes break. Regardless, I would like to save 'Inherited Scene' as a last resort. Any way to setup components along with some kind of inheritance would be much preferred.

    Awfy Maybe create base EnemyComponent that has the common components like health velocity statemachine etc.. then if you want to have different enemies then you add the special components? This way you can just update the common component to add the thing to every enemy while keeping the special cases to special enemies..

    Thats how i would do it.

    You either plan everything out or refactor.. either way you end up to do some work in the end.. its inevitable

    • Edited

    Awfy Node based components as well as node based state machines wouldn't be my first choice when building systems in Godot. That said, you can make a tool script or editor plugin that opens your 100 scenes, adds wanted nodes to them, and resaves them.

    • Awfy replied to this.

      xyz Honestly, mine either. It's just what I see most people do, but I wonder if I can convert it to a resource based system. What'd you recommend?

      • xyz replied to this.
        • Edited

        Awfy I'd start with actual use cases. Not with abstractions. Don't do ExampleEnemy. Make several real ones.

        For running state specific code I'd use a dictionary of callables. Some time ago I posted a callable based state machine implementation. Can't find it now though.

        For functionality variation, I'd keep all code in one class and drive variation with data stored in resources. If a need for a very different kind of enemy arises - I'd introduce a fully new class. Even at the cost of some repeating code. And again drive its variation with data. I'd strive to keep the class inheritance tree as shallow as possible, ideally non-existent.

        If I just couldn't live without an ecs like system, I'd keep majority of common functionality in one big base component and only introduce larger high-level components with functionalities that directly correspond to enemy semantics in the actual game - for example MageAbilities or Hovercraft. I'd keep the overall number of components in the system as low as possible.

        See the problem nowadays is that many people got indoctrinated with this notion that a system should be chopped up into as tiny pieces as possible. The main idea behind that is: if we slice everything up into smallest possible chunks, and make chunks simple looking, then the whole system will be simple, because - duh - everything in it is simple. This conclusion is obviously fallacious. The complexity of any system is primarily determined by the structure of communication channels between components. Not how easy on the eyes each individual component is.

        So the more components you have, the more they need to intermingle, the more complicated the system gets. Regardless of how drool-proof and obvious each component is by itself.

        Contrary to naive intuition, in big systems large components can lower the complexity of the system while simpler more atomic components can do the opposite. From that follows xyz's controversial system design adage: Simple components spaghettify the system!

        The famous spaghetti code metaphor doesn't refer to spaghetti's elongated shape, it refers to their tendency to get tangled when a bunch of them is thrown together into a bowl.