I’ve been designing and just started working on a top-down roguelike game with only a few combat interactions: attack, basic attack, dodge, block and active skills. As you progress through a run, you upgrade your weapon’s properties and attacks and get new active skills. The game is mostly focused on what weapon you have and how you built it. Of course, that’s all the design, what I have made so far was quite literally just movement (walking and dodging) and taking damage.
I’m trying to get a better understanding and practice with composition, so everything I did with the project was based on it (using Mastering Composition for Beginners in Godot and Using Composition to Make More Scalable Games in Godot for reference). Now that I am finally trying to approach combat, I hit a wall. At first, I though the easiest way to go on about it was by making an AttackComponent that checks if an attack was requested (whether through InputComponent for the player or EnemyAIComponent for enemy NPCs) and calls an attack if true, but because, as I mentioned before, the attacks themselves will change based on upgrades, I thought maybe I should make the attacks easier to build, which could be achieved by making components for the attacks, but that means that attacks will be Nodes, and since the main source of variety between the player across runs will be the different attacks paired with different upgrades and properties, that means a LOT of Nodes, which I imagine would not be practical and probably terrible for performance.
I believe combining both systems — having an AttackComponent that checks if the entity can and should attack and calls an attack (based on what attack options the entity has access to), and the attacks themselves being indeed Nodes with their own components for their properties and animations, which are assigned to the AttackComponent — would work, but something feels off about it.
Edit: I had forgotten to mention that I am a beginner. I can code systems at surface level, similar to how one would in a tutorial that has no compromise with future features that may interact with each other, which is exactly why I’m struggling with this.


