12 hours ago, AxeGuywithanAxe said:
In my game engine, different component types have speciific logic when they are activated and deactivated, so they are in the base class, and most components have some sort of "tick" logic.
But that is something, I wanted to avoid. In the beginning a Model was capable of drawing itself by drawing its Mesh and Material. If we avoid inheritance, we can make all these methods non-virtual to gain some performance, but this looks not very DoD, but rather OoD? So currently, I really extract the data from the scene and render the complete batch of Models based on the data of the Model, but not inside the Model. Why would a Model anyway be capable of drawing itself? It merely provides a description about its appearance (declarative vs imperative)?
12 hours ago, AxeGuywithanAxe said:
You'll have to be more descriptive of your method, in most ecs approaches, scripts are handled by using a "CScriptComponent", so you would have to explain what your scripts actually do, and the point of them in more depth.
My scripts do nearly everything at the moment, similar to Unity's MonoBehavior. So there is a duality, I do not like about my codebase:
-
Models contain a description of their appearance, but contain no drawing logic. A render pass will take care of that based on the data.
-
Scripts contain some typical hooks Update etc. in which they are capable of executing some operations (so not very descriptive at all). Currently, this basically involves changing some parameters of whatever at runtime (materials, transforms, etc.).
12 hours ago, AxeGuywithanAxe said:
Well with an ECS method, you will have data in one class and logic in the system class. This means that you're adding two classes in an entity - component -system model for every one class you would have made using an entity component model
Thanks this is a very clear definition. Though given this definition, I would prefer ECS over EC. Why would you add logic to the Component, because this way you will deviate from DoD to OoD? In the most extreme case, you can say that each E and C corresponds to a table in some relational database, which only contains data (so no logic)? ECS seems also somewhat similar to a producer-consumer system.
12 hours ago, AxeGuywithanAxe said:
Yeah , I have a function called "GetComponentOfClass" and "GetComponentsOfClass". I programmed an automatic reflection system that preprocesses my c++ code and generates reflection data for classes, enums, structs, functions, properties, etc, but there are dozens of simple ways to create custom type info.
And I guess, you use that as well for displaying each Component in the editor. Not only the engine defined ones, but user created scripts as well since you can basically display all member variables in an appropriate way. A visitor would be "clean" alternative for the engine defined ones, but could not anticipate the user defined ones without instructing the user to do so. So in that sense reflection is the most flexible solution. Though, you need to give up the data encapsulation provided by the typical getter/setter pair, since detecting an arbitrarily named getter/setter does not look very trivial (at least more difficult than making all member variables public).
12 hours ago, Hodgman said:
This really doesn't look like you're using any DoD. From the look of the code, it seems like you'd have something like this?
for each render component as renderable
transform = renderable->m_entity->m_transform
set_draw_data( transform )
draw( renderable )
The renderer extracts the "renderables" which will be filtered in some collections (e.g. opaque, transparent, brdf, no brdf, etc.). The second line will be consequence of the ECS. At the moment I extend the entities, lacking components, but after refactoring it will indeed look something like that. The last two lines are sort of present as well. Am I misunderstanding something?
The following seems DoD to me from the perspective of the Components:
RenderSystem::set_draw_data(Transform)
RenderSystem::Draw(Renderable)
whereas this seems OoD to me from the perspective of the Components:
Transform::set_draw_data()
Renderable::Draw()
Edit: Though, I now also realize that DoD could mean packing all related data together independent of logical functionality. The drawback could be possible duplication.
12 hours ago, Hodgman said:
Then reconcile those two ideal layouts into something that works in practice. Figure out if you need any conversion transforms in the middle (e.g. gameplay outputs data set X, which is then converted to data set Y, which is consumed by the renderer).
But during the "conversion" you can have bad cache coherency. So isn't this moving the problem?
12 hours ago, Hodgman said:
Inheritance is not a tool for code re-use / extension. Composition is a tool for code re-use / extension.
UE4 uses this monolytic hierarchy, letting you extend everything. I agree that composition and aggregation are better practices, but inheritance sometimes look like the only way of hooking something to an existing system.