Josh Posted Monday at 09:09 PM Posted Monday at 09:09 PM I am wondering if anyone actually uses multiple components heavily? The promise of this approach is that you would be able to develop modular components that allow you to mix and match behavior. That idea has always been confusing and unbelievable to me. If we just had a single script attachment per entity, your script code could look like this: function Script:Update() self:SetPosition(self.position + self.movespeed)--self is an entity if self.target ~= nil and self.target.health > 0 then self.target:SetHidden(true)--self.target is an entity end end Instead of the schizophrenic entity / component paradigm, where you have to code exactly for the component you expect to be there, in this case "HealthManager": function Script:Update() self.entity:SetPosition(self.entity.position + self.movespeed)--self is a component if self.target ~= nil and self.target.HealthManager.health > 0 then self.target:SetHidden(true) end end This seems to go against the dynamically typed nature of Lua, and makes design extremely rigid. I can't just check a health or team value to determine how to treat another entity, I either need to know the exact component I expect to see there, or iterate through all components, check for those values, and take the first value I find if there are multiple components with different values. What do you think? Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Dreikblack Posted Tuesday at 02:20 AM Posted Tuesday at 02:20 AM On 8/12/2025 at 3:09 AM, Josh said: I am wondering if anyone actually uses multiple components heavily? Everyone who are working on games? Same for other engines as well. On 8/12/2025 at 3:09 AM, Josh said: Instead of the schizophrenic entity / component paradigm Mixing entity and component would be actual schizophrenic if anything. Even LW4 don't do it with single component/script pet entity. And such shizo approach would not change a fact that entity component may not have "health" var. You need to know what are you doing. If you really want you already can dynamically use vars and functions of all components. Fixing not existing problems would create a ton of real problems which would kill an engine at very least for me. 2 Quote Check out Slipgate Tactics demo, which is made with Ultra Engine/Leadwerks 5: https://www.leadwerks.com/community/topic/61480-slipgate-tactics-demo/
reepblue Posted Tuesday at 03:11 AM Posted Tuesday at 03:11 AM During the development of the engine, I've been experimenting with the best way to develop and create things using the current design decisions. I first tried the multiple components and having them check the entity for corresponding components and that ended up to be a confusing mess. How was I supposed to keep track of what components leveraged each other without some sort of internal documentation? I went back to mono components using inheritance as I normally use C++. However, there has been many opportunities where I have added multiple components to an entity. Here are the senerios when I find myself doing so: When an entity needs to do 2 separate actions (for example: Spin and change color) Instead of writing a special component that spins and changes it's color, I can reuse 2 components to do so. I don't feel like I'm recoding something because the functionality is a little different and the two components don't have to acknowledge each other. This is important in Lua since there's no inheritance. Logic components. Instead of having multiple Pivots with Relays and Timers, I can reduce the count by organizing functionality with less clutter in the map. VR. I made a VR player, and I have the teleportation code in a separate component. This is really nice because the Hmd can always be returned with GetHmd so each piece of functionality can be compartmentalized. Overall, I like adding multiple components to entities but I avoid coding any checks to see if another component is attached. I would leave this feature alone, but not advertise it or encourage it. If you believe that supporting multiple components may prevent you from adding new features to the flowgraph system or prevent support for prefabs supporting flowgraph information, then we'd need to really consider. And if we're keeping multiple components for now, it'll be a bad idea to drop it after the 5.0 release. Quote Cyclone - Ultra Game System - Component Preprocessor - Tex2TGA - Darkness Awaits Template (Leadwerks) If you like my work, consider supporting me on Patreon!
Josh Posted Tuesday at 03:31 PM Author Posted Tuesday at 03:31 PM I have always disliked the ECS approach and using it only confirmed everything I thought about it. Beginners find it confusing, and I also find it confusing. Compare the code examples below. ECS: local pickinfo = world:Pick(p0, p1, true) if pickinfo.entity then for k, v in pairs(pickinfo.entity.components) do -- I don't actually know if this is right, because I don't remember how to do this, lol if type(v.Use) == "function" then v:Use(self.entity) end end end The fact that I wrote this system and I can't even remember how to use it, without checking the documentation, is pretty damning. One script, one entity: local pickinfo = world:Pick(p0, p1, true) if pickinfo.entity then if type(pickinfo.entity.Use) == "function" then pickinfo.entity:Use(self) end end Being able to just add properties and functions to entities is so convenient, and ECS totally throws that away and makes things far less modular and reusable. For example, Alienhead's footsteps component doesn't work with the default FPS player script, through no fault of his own. All the promised modularity of this approach depends on very specific programming to make it that way, instead of just letting emergent behaviors occur. The only examples people can ever give of ECS actually delivering modular behavior are extremely simplistic. On the C++ side, in both the stock components and my SCP game, I end up relying on an object-oriented hierarchy because the ECS approach is so hare-brained. Instead of checking for common properties, I cast to a common base class like Weapon, Projectile, Enemy, etc. What if instead of parsing component headers, the parser could read the class hierarchy of each object type, and display all the properties contained therein?: GameObject int health int team Enemy shared_ptr<NavAgent> agent SCP939 SCP173 SCP097 MTF Guard Scientist Player std::set<int> keycards runspeed LocalPlayer lookspeed RemotePlayer uint64_t steamid When you placed a LocalPlayer object in the scene, the following properties would be exposed, for example: health team keycards runspeed lookspeed In the future, I think things like hiding/showing an entity, changing its color, etc. would be best done using a command that is dragged into the flowgraph. This functionality won't be implemented for a while, but that's what I am thinking in the future. Everyone wants me to teach them how to program, but with the ECS design I am teaching them the wrong way. With Lua, dynamic typing is the right way, and with C++, a class hierarchy is the right way. The ECS approach makes me hop on one leg so I can show people something confusing. Just the thought of writing tutorials for it makes me feel like I should apologize to the user for the bad design. 1 1 Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Dreikblack Posted Tuesday at 04:29 PM Posted Tuesday at 04:29 PM 30 minutes ago, Josh said: When you placed a LocalPlayer object in the scene, the following properties would be exposed, for example: Do you mean in code? It would be terrible. Ideally class members should not be public at all. Only lack of @Getters and @Setters annotation (like in Java) makes me use public members sometimes to speed up coding a bit. 36 minutes ago, Josh said: Beginners find it confusing, and I also find it confusing I never was finding the most sane thing being confusing even as beginner. If anything is confusing it's lack of proper Inheritance in Lua (recently i found this tho https://www.lua.org/pil/16.2.html, can it be applied to components?) and lack of interface in C++ (and when i tried to use second parent to workaround i could not build a project). ECS itself (which is luckily not real ECS like DOTS from Unity, which is really sound terrible and confusing) is totally fine as it is. You should not make 100000500000 lines classes/scripts (speaking of confusing stuff...) when you can split it in different components with different purposes and reuse whenever you want instead of copy pasting same stuff everywhere and then change it everywhere when fixing a bug or enhancing a code. 54 minutes ago, Josh said: I cast to a common base class like Weapon, Projectile, Enemy, etc Just like it supposed to be. It would unbearable if only one var/method name could be per entity. Some kind of Interface like in Java would easily fix an issue when you want to use some abstract method without same parent. 47 minutes ago, Josh said: I end up relying on an object-oriented hierarchy because the ECS approach is so hare-brained What is that even suppose to mean? Maybe not following OOD is your issue in first place. And OOD is obviously best approach for anything complicated since it's following real life logic, meanwhile you for some reason want to put everything in same pile without categorizing things which quickly end up being terrible mess that would be impossible to support later by refactoring, fixing or improving. 1 Quote Check out Slipgate Tactics demo, which is made with Ultra Engine/Leadwerks 5: https://www.leadwerks.com/community/topic/61480-slipgate-tactics-demo/
Josh Posted Tuesday at 04:43 PM Author Posted Tuesday at 04:43 PM 10 minutes ago, Dreikblack said: Ideally class members should not be public at all. Only lack of @Getters and @Setters annotation (like in Java) makes me use public members sometimes to speed up coding a bit. I mean properties that can be set in the editor, in the entity properties editor. Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Dreikblack Posted Tuesday at 05:28 PM Posted Tuesday at 05:28 PM 49 minutes ago, Dreikblack said: lack of interface in C++ (and when i tried to use second parent to workaround i could not build a project) Managed to do it in test project. Will do it for sure in next games now. #pragma once #include "Leadwerks.h" using namespace Leadwerks; class InterfaceExample { protected: int health; public: virtual ~InterfaceExample() = default; virtual void changeHealth(int healthDelta) = 0; }; #pragma once #include "Leadwerks.h" #include "../BaseComponent.h" #include "InterfaceExample.h" using namespace Leadwerks; class Mover : public BaseComponent, public InterfaceExample { public: Vec3 movementspeed; Vec3 rotationspeed; bool globalcoords {false}; Mover(); virtual void Update(); virtual bool Load(table& properties, shared_ptr<Stream> binstream, shared_ptr<Scene> scene, const LoadFlags flags, shared_ptr<Object> extra); virtual bool Save(table& properties, shared_ptr<Stream> binstream, shared_ptr<Scene> scene, const SaveFlags flags, shared_ptr<Object> extra); virtual std::shared_ptr<Component> Copy(); void changeHealth(int healthDelta) override; }; Interface class also can have own implementation, so you can cast class to interface one (entity->GetComponent<InterfaceExample>()) and use its methods without doing anything in children classes except adding interface as a parent. Quote Check out Slipgate Tactics demo, which is made with Ultra Engine/Leadwerks 5: https://www.leadwerks.com/community/topic/61480-slipgate-tactics-demo/
Josh Posted Tuesday at 05:52 PM Author Posted Tuesday at 05:52 PM Maybe in your previous attempts, InterfaceExample was derived from the Object class? https://www.geeksforgeeks.org/cpp/diamond-problem-in-cpp/ Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Josh Posted Tuesday at 06:07 PM Author Posted Tuesday at 06:07 PM 1 hour ago, Dreikblack said: If anything is confusing it's lack of proper Inheritance in Lua Lua will never have inheritance. It has dynamic typing, which means you can just add whatever properties you want. Not exactly the same thing, but it usually meets the same need. Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Josh Posted Tuesday at 07:40 PM Author Posted Tuesday at 07:40 PM 18 hours ago, reepblue said: When an entity needs to do 2 separate actions (for example: Spin and change color) Instead of writing a special component that spins and changes it's color, I can reuse 2 components to do so. I don't feel like I'm recoding something because the functionality is a little different and the two components don't have to acknowledge each other. This is important in Lua since there's no inheritance. When does this actually happen in real life? Why is spinning and changing colors the only example anyone can ever think of? One-time state changes like changing colors or hiding an object are the only thing I used multiple components for in the FPS example, and those could be done better with visual functions, if I add that to the flowgraph. I can't think of a single thing that needs multiple ongoing Update() calls, where that wouldn't just be built into the single script as an option. 18 hours ago, reepblue said: Logic components. Instead of having multiple Pivots with Relays and Timers, I can reduce the count by organizing functionality with less clutter in the map. It sounds like these type of objects don't even need an entity, and could be done even better if you could just drag the script object into the flowgraph and have it only exist there, without any entity. 18 hours ago, reepblue said: VR. I made a VR player, and I have the teleportation code in a separate component. This is really nice because the Hmd can always be returned with GetHmd so each piece of functionality can be compartmentalized. Why is this nice? Can you not decide if your game should use teleporting or not? Is this for someone else to use, who cannot make up their mind, and also cannot handle the burden of a checkbox to indicate whether teleportation should be enabled? With the pushbutton in the FPS map, for example, I use three components for the logic, sound, and emission color change. Is this actually good? Why didn't I just build these features all into a single component? Is that additional functionality a huge burden we need to try to restructure all our code to try to avoid? Are there many different styles and behaviors of push buttons that are so different that I am afraid of locking myself into a finished design? It really seems to me that the advantages of multi-component ECS are vague and theoreitcal, while the disadvantages are concrete and intrusive. In my own code I find I am constantly making effort to work around the inconveniences that ECS introduces. Even worse, I feel this approach may be holding us back from advantages we could gain if we dig into the actual nature of the languages we are using, OOP for C++ and dynamic typing for Lua. Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Josh Posted Tuesday at 10:50 PM Author Posted Tuesday at 10:50 PM @Dreikblack Apparently, the diamond problem has been solved a long time. Check out virtual inheritance. Using that, I could even make it so that user-defined components ARE the Entity class, like this: class Player : public virtual Entity { public: int health = 100; void AddDamage(const int amount); }; Example of how it could be used: auto entities = world->GetEntitiesInArea(bounds) for (auto entity : entities) { // Cast the entity to a user-defined Player object auto player = entity->As<Player>(); if (player) { float dist = player->GetDistance(grenade);// Player can call all Entity methods player->AddDamage(dist);// Player also has its own user-defined methods auto model = player->As<Model>();// Check if player is a Model Entity...I think this can actually work if (model) model->Animate("pain"); } } Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Dreikblack Posted Wednesday at 02:37 AM Posted Wednesday at 02:37 AM 3 hours ago, Josh said: @Dreikblack Apparently, the diamond problem has been solved a long time. Check out virtual inheritance. It does not work for components, because Component have inference from Object without virtual Quote Check out Slipgate Tactics demo, which is made with Ultra Engine/Leadwerks 5: https://www.leadwerks.com/community/topic/61480-slipgate-tactics-demo/
Dreikblack Posted Wednesday at 02:59 AM Posted Wednesday at 02:59 AM 8 hours ago, Josh said: Lua will never have inheritance It kinda has tho https://www.lua.org/pil/16.2.html? Never tried, but wonder if it can be used for Components to avoid terrible giant scripts with copy-pasted code Quote Check out Slipgate Tactics demo, which is made with Ultra Engine/Leadwerks 5: https://www.leadwerks.com/community/topic/61480-slipgate-tactics-demo/
Josh Posted Wednesday at 03:07 AM Author Posted Wednesday at 03:07 AM 26 minutes ago, Dreikblack said: It does not work for components, because Component have inference from Object without virtual Fortunately, I have full access to the source code and I can change this at any time. Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Dreikblack Posted Wednesday at 04:03 AM Posted Wednesday at 04:03 AM 7 hours ago, Josh said: It really seems to me that the advantages of multi-component ECS are vague and theoreitcal, while the disadvantages are concrete and intrusive. In my own code I find I am constantly making effort to work around the inconveniences that ECS introduces. Even worse, I feel this approach may be holding us back from advantages we could gain if we dig into the actual nature of the languages we are using, OOP for C++ and dynamic typing for Lua. Vague and theoretical are disadvantages of ECS that you are trying to make up for no any good reason. Meanwhile ESC were described many times already and people actively use them. 8 hours ago, Josh said: When does this actually happen in real life? Why is spinning and changing colors the only example anyone can ever think of? One-time state changes like changing colors or hiding an object are the only thing I used multiple components for in the FPS example, and those could be done better with visual functions, if I add that to the flowgraph. I can't think of a single thing that needs multiple ongoing Update() calls, where that wouldn't just be built into the single script as an option. Sorry for being rude in this thread, but it's just you imagination limits + lack of game development experience (SCP project does not have even a demo to be counted, empty levels with nearly zero interactivity ofc. don't need multi-components yet). Example of flow-graph for relatively little level (looks chaotic because i tried to fit in one screen): 8 hours ago, Josh said: It sounds like these type of objects don't even need an entity, and could be done even better if you could just drag the script object into the flowgraph and have it only exist there, without any entity. In such cases they still would needs to be multi-components for composition. Also how would save-load work without entities, especially custom one like mine, where i searching for entities with SAVE tag? 8 hours ago, Josh said: With the pushbutton in the FPS map, for example, I use three components for the logic, sound, and emission color change. Is this actually good? Why didn't I just build these features all into a single component? Of course it's good. Making 100 components with 90% of duplicated code is sooooooo much worse than having 10 components with different functionality. Even in the editor it will look like a mess with 50 component fields when it can be just few per component and you can use only ones you need. 8 hours ago, Josh said: s that additional functionality a huge burden we need to try to restructure all our code to try to avoid? Restructure which code? You are the one who wants to make everyone restructure their existing code. Please, just stop reinventing bicycle in worse possible way. What you want is opposite of everything that OOP stands. Quote Check out Slipgate Tactics demo, which is made with Ultra Engine/Leadwerks 5: https://www.leadwerks.com/community/topic/61480-slipgate-tactics-demo/
reepblue Posted Wednesday at 06:06 AM Posted Wednesday at 06:06 AM 6 hours ago, Josh said: @Dreikblack Apparently, the diamond problem has been solved a long time. Check out virtual inheritance. Using that, I could even make it so that user-defined components ARE the Entity class, like this: class Player : public virtual Entity { public: int health = 100; void AddDamage(const int amount); }; Example of how it could be used: auto entities = world->GetEntitiesInArea(bounds) for (auto entity : entities) { // Cast the entity to a user-defined Player object auto player = entity->As<Player>(); if (player) { float dist = player->GetDistance(grenade);// Player can call all Entity methods player->AddDamage(dist);// Player also has its own user-defined methods auto model = player->As<Model>();// Check if player is a Model Entity...I think this can actually work if (model) model->Animate("pain"); } } I'm in favor of this! That would mean each component carries all functionality from the actual class itself. One thing I do notice is that Components tend to be used on fix amount of entities. For example, you're not going to apply the Monster's component to a sprite. If you can derive Monster from the model class, and change the mesh. This is what Quake and Source does. I'm all for this! 10 hours ago, Josh said: It sounds like these type of objects don't even need an entity, and could be done even better if you could just drag the script object into the flowgraph and have it only exist there, without any entity. The virtual nodes things would be interesting, but the flowgraph gets very cluttered. very fast. Adding imaginary nodes might just make it more confusing. I'm still a big fan of Hammer's I/O system. I actually think it's neater than messy nodes crossing over each other. I could set any entity's property the same and add delays to the output without a special component. 10 hours ago, Josh said: Why is this nice? Can you not decide if your game should use teleporting or not? Is this for someone else to use, who cannot make up their mind, and also cannot handle the burden of a checkbox to indicate whether teleportation should be enabled? Separation of functionality! Look how nice this is presented. This can be recreated with separators, but I like how I know this section is just for the teleport system. I will say this, if you're going to make a decision, do it now. I would not be a fan of the idea of you just cutting multiple components and leaving us hanging with planned features that multiple components can solve in the current build. Quote Cyclone - Ultra Game System - Component Preprocessor - Tex2TGA - Darkness Awaits Template (Leadwerks) If you like my work, consider supporting me on Patreon!
Josh Posted Wednesday at 08:05 AM Author Posted Wednesday at 08:05 AM 10 hours ago, reepblue said: If you can derive Monster from the model class, and change the mesh. This is what Quake and Source does. I'm all for this! That's actually not necessary with virtual inheritance. It is possible to create a Monster that appears to be derived from a Model and another from a Light, etc. (There's actually a hidden class that is derived from both the Monster and the specific entity class, and virtual inheritance resolves the conflict.) This is what I have in mind. The user-defined "component" and the entity are the same object: #include "Leadwerks.h" using namespace Leadwerks; //------------------------------------------------------- // This entity class simply moves or turns around a bit each frame //------------------------------------------------------- class Mover : public virtual Entity { Vec3 movespeed = Vec3(0,0,0); Vec3 turnspeed = Vec3(0,1,0); virtual void Update() { Turn(turnspeed); Move(movespeed); } } int main(int argc, const char* argv[]) { //Get the displays auto displays = GetDisplays(); //Create a window auto window = CreateWindow("Leadwerks", 0, 0, 1280, 720, displays[0], WINDOW_CENTER | WINDOW_TITLEBAR); //Create a world auto world = CreateWorld(); //Create a framebuffer auto framebuffer = CreateFramebuffer(window); //Create a camera auto camera = CreateCamera(world); //Create a Model / Mover entity auto box = CreateBox<Mover>(world); box->SetPosition(0,0,2);// calling an entity method is fine box->turnspeed.y = -2.0f;// so is this //Main loop while (window->Closed() == false and window->KeyDown(KEY_ESCAPE) == false) { world->Update(); world->Render(framebuffer); } return 0; } Quote My job is to make tools you love, with the features you want, and performance you can't live without.
reepblue Posted Wednesday at 04:05 PM Posted Wednesday at 04:05 PM I mean, I'm all for this. I can then make nice wrapper functions for my "components". std::shared<ScaryMonster> CreateScaryMonster(shared_ptr<World> world, const int intialstate = STATE_IDLE) { auto ent = LoadModel<ScaryMonster>(world, "Models/Characters/Monsters/ScaryMonster.mdl"); ent->state = intialstate; return ent; } Then in the flowgraph, you can pre-populate the nodes with entity functions so the end user always has access to those commands. Of course, that's another conversation. My only concern is you breaking people's existing projects unless you plan to have ECS as a legacy feature for a few versions. Quote Cyclone - Ultra Game System - Component Preprocessor - Tex2TGA - Darkness Awaits Template (Leadwerks) If you like my work, consider supporting me on Patreon!
Josh Posted Wednesday at 04:21 PM Author Posted Wednesday at 04:21 PM I'm not sure of anything yet, but I want to continue experimenting with this. If it is possible to deliver something dramatically better, with a smooth transition for existing component code, then I think it is worth investigating before the release. 32 minutes ago, reepblue said: I mean, I'm all for this. I can then make nice wrapper functions for my "components". And then if you wanted to know if something was a monster (or maybe a more general base class) you could cast the entity itself: auto pickinfo = world->Pick(p0, p1, true); if (pickinfo.entity) { auto monster = pickinfo.entity->As<Monster>(); if (monster and monster->health > 0) monster->Kill(); } It's also worth noting that virtual inheritance could probably let you compose "components" that are built on others. This is similar to multiple component reuse, but instead of making the decision in the editor, you are making the decision in code, and a single class is exposed to the editor. Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Josh Posted Wednesday at 05:34 PM Author Posted Wednesday at 05:34 PM 11 hours ago, reepblue said: Separation of functionality! Look how nice this is presented. This can be recreated with separators, but I like how I know this section is just for the teleport system. Wow, cool. Is anyone going to have two different maps that require two different teleport colors, or two different sound effects? If not then it would make more sense for them to just modify those values in the code. In reality default settings are typically treated as holy scripture, and there is a 99% percent chance that not a single person will ever modify those defaults. Sorry for being critical, but I am really trying to separate out hypothetical benefits and real ones that will actually produce real benefits. This is not always easy but I need to judge this stuff carefully because the downside of multiple components is never knowing what type of object an entity really is supposed to be. 1 Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Josh Posted Wednesday at 06:07 PM Author Posted Wednesday at 06:07 PM Okay, so with my Monster example above, given that there is still a necessity to cast to Monster class, I don't see a lot of difference between that and this single-component approach: auto pickinfo = world->Pick(p0, p1, true); if (pickinfo.entity and pickinfo.entity->actor) { auto monster = pickinfo.entity->actor->As<Monster>(); if (monster and monster->health > 0) monster->Kill(); } Currently, interactions between entities have to be done like this: auto pickinfo = world->Pick(p0, p1, true); if (pickinfo.entity) { for (auto c : pickinfo.entity->components) { auto monster = c->As<Monster>(); if (monster and monster->health > 0) monster->Kill(); } } I have three objections to this: 1) Any time you call a method, set a value, or get a value from another entity, a for loop is required. This is tedious and makes me want to avoid entity interactions, unless I absolutely have to do something. 2) Entity interactions get very complicated and ambiguous. Look at the bullet impact code: for (auto c : pickinfo.entity->components) { auto base = c->As<BaseComponent>(); if (base) base->Damage(damage, entity); } Where is the health value stored? If you have a separate health value stored for each component, you better make sure they all start at the same value, and it's easy for them to get out of sync. If there is just one health value stored in another component, like a health manager, then you can run into two problems: If each component decrements HealthManger->health, and you have two components that do this, you are applying double damage. If only the HealthManager component decrements the health value, then you had better make sure the HealthManger gets called first! Otherwise other components won't know if they are supposed to respond with a pain sound, or respond with a death sound, because the health value might not have been set to zero yet. This is a problem I actually ran into when developing the stock components. The player would not perform all their "dying" actions correctly because the health value was on a separate component and was sometimes decreased last, so the camera and controls of the dead player were staying active, even though health had dropped below zero. It took me a long time to realize the cause of this. You could solve this by defining a component order, but it's very easy to make mistakes with that, and I would feel like apologizing if I was making a tutorial and trying to explain it. 3) Retrieving a value from another entity involves a lot of code and is ambiguous. int team = 0; for (auto c : entity->components) { auto npc = c->As<NPC>(); if (npc) team = npc->team; } If the user has everything set up correctly so that there aren't two components with the same base class and different values, everything should be fine...but people make mistakes and adding a layer of confusion always makes it harder to see those mistakes. All the same things can be said about Lua, only with Lua no casting is necessary, you just check if the values you are expecting are present on the entity. With the single component design, all the methods and properties are attached directly to the entity object, something that was not possible in Leadwerks 4: local pickinfo = world:Pick(p0, p1, true); if pickinfo.entity then if type(pickinfo.entity.health) == "number" and type(pickinfo.entity.Kill) == "function" then if pickinfo.entity.health > 0 then pickinfo.entity:Kill() end end end Retrieving values from another entity becomes very simple: if type(entity.team) == "number" and type(entity.health) == "number" then if entity.team ~= self.team and entity.health > 0 then self:Attack(entity) end end Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Josh Posted Wednesday at 06:48 PM Author Posted Wednesday at 06:48 PM Here is an example of a component derived from another component, using virtual inheritance. The base component can still be used on its own, or its functionality can be combined with the derived component. DerivedComponent.zip Edit: I don't think virtual inheritance is actually needed at all for this. Quote My job is to make tools you love, with the features you want, and performance you can't live without.
Dreikblack Posted Thursday at 03:18 AM Posted Thursday at 03:18 AM 9 hours ago, Josh said: Wow, cool. Is anyone going to have two different maps that require two different teleport colors, or two different sound effects? If not then it would make more sense for them to just modify those values in the code. In reality default settings are typically treated as holy scripture, and there is a 99% percent chance that not a single person will ever modify those defaults. Sorry for being critical, but I am really trying to separate out hypothetical benefits and real ones that will actually produce real benefits. Not true at all. Different functionality should be kept in different components that are kept in own sections. And you keep making up artificial problems by cherry-picking. There is infinity variations which fields component may and should have and mixing everything in same place is silly as heck. You would know it if you read even half of what i wrote here already. 9 hours ago, Josh said: This is not always easy but I need to judge this stuff carefully because the downside of multiple components is never knowing what type of object an entity really is supposed to be. And again made up problem. By this logic there should not be any classes at all except all, just Object or something, because someone don't know what is they doing lol. Nothing would change with mono-comp in this matter. 8 hours ago, Josh said: 1) Any time you call a method, set a value, or get a value from another entity, a for loop is required. This is tedious and makes me want to avoid entity interactions, unless I absolutely have to do something. Another made up problem. In reality you do entity->GetComponent<Monster>() - no loop required...... 8 hours ago, Josh said: Where is the health value stored? If you have a separate health value stored for each component, you better make sure they all start at the same value, and it's easy for them to get out of sync. If there is just one health value stored in another component, like a health manager, then you can run into two problems: Oh, look! Another made up issue, what a surprise! I NEVER had such problem because i have a proper code with OOD in mind. In reality you know what component to use - spoiler it's would be base character class without loops again. Or health manager. If someone with source code add virtual inheritance for Component from Object, you could even make an interface class for health and stuff without artificial BaseComponent. 9 hours ago, Josh said: 3) Retrieving a value from another entity involves a lot of code and is ambiguous. 9 hours ago, Josh said: If the user has everything set up correctly so that there aren't two components with the same base class and different values, everything should be fine...but people make mistakes and adding a layer of confusion always makes it harder to see those mistakes. At this point i don't even try to count how many issues you made up. Seriously, just stop. Chance of changing component values are 1%, but having two different character component for single entity is more than 0.000001? And it's above 0 only due Editor GUI in anything, And you want use 0 chance of most stupid mistake to screw the system.... 9 hours ago, Josh said: if type(entity.team) == "number" and type(entity.health) == "number" then if entity.team ~= self.team and entity.health > 0 then self:Attack(entity) end end It's even more simple if you use GetComponent() method, which you keep ignore just like you keep ignoring me and my arguments. Whole topic is nonsense and exit because you keep pretend only monkeys and LLM will use your engine. And in both case nothing will help, but hurt actual engine users. Quote Check out Slipgate Tactics demo, which is made with Ultra Engine/Leadwerks 5: https://www.leadwerks.com/community/topic/61480-slipgate-tactics-demo/
Dreikblack Posted Thursday at 03:18 AM Posted Thursday at 03:18 AM On 8/13/2025 at 9:07 AM, Josh said: Fortunately, I have full access to the source code and I can change this at any time. So please do it? Quote Check out Slipgate Tactics demo, which is made with Ultra Engine/Leadwerks 5: https://www.leadwerks.com/community/topic/61480-slipgate-tactics-demo/
reepblue Posted Thursday at 04:12 AM Posted Thursday at 04:12 AM 10 hours ago, Josh said: Wow, cool. Is anyone going to have two different maps that require two different teleport colors, or two different sound effects? If not then it would make more sense for them to just modify those values in the code. In reality default settings are typically treated as holy scripture, and there is a 99% percent chance that not a single person will ever modify those defaults. Sorry for being critical, but I am really trying to separate out hypothetical benefits and real ones that will actually produce real benefits. This is not always easy but I need to judge this stuff carefully because the downside of multiple components is never knowing what type of object an entity really is supposed to be. Well, if the goal is to have end users upload their own components so the download section we eventually have a library of them, some components would need to have open-ended parameters. I designed that to be as versatile as possible. If I wanted to make a teleport system, I would do it my way, with my models, and my sounds and baked it into the main player. It seems like your goal is shifting from people gluing things that already exist to actually getting them to program. Although I agree with your viewpoints since mono-components (Or just Actors) is how I coded Cyclone on Leadwerks 4. The only thing that that bothers me regarding this topic is that you're talking about removing options for developers. Right now, the engine supports multi-components, but if you want to cram everything into one, you can. If you want multiple components and have them reference each other, that's fine too. I also don't like that a core design of the engine is being reconsidered right before the final release and many people have active projects they have been working on. I know you wish to steer people way from overcomplicating things, but I believe that developers should have that freedom to design their game how they wish. I understand your perspective that "no decision is a bad decision", and supporting both can seen as a non-decision. But there's nothing wrong with what we have now. You can write your tutorials using the mono approach, I can use mono components, and people like Dreik and Alienhead can still code how they want. 2 Quote Cyclone - Ultra Game System - Component Preprocessor - Tex2TGA - Darkness Awaits Template (Leadwerks) If you like my work, consider supporting me on Patreon!
Recommended Posts
Join the conversation
You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.