Open ghost opened 9 years ago
I took a glance at the component system and even though it's a bit weird to me, I like it. I will pull the code and check how everything works. Be ready to be flooded with question and document the system because this is new to me.
On Wed, Nov 26, 2014 at 7:38 PM, Sherushe notifications@github.com wrote:
This took a long time but I'm happy with the result. I added some components and systems to test if it works and I managed to get a moving tank.
I created a Readme which contains the change log and some explainations about the entity component system ( at the moment, it's just code samples ).
I hope you like it. The advantage with this system is that you can easily combine functionnalities with components, and creating new functionnalities is just creating a new system.
— Reply to this email directly or view it on GitHub https://github.com/Sherushe/tanks/issues/38.
Restructure process - Classes added
Systems:
Components:
It's awesome that you like it. Yea sure, you can ask me whatever questions you want.
Also I changed the naming conventions a bit, but I will correct it soon. Call every component class ...Component and every system class ...System is also a good thing I think.
So the entities are all generic. You spawn the entity based on the parameters you give it, not any object like Tank or Bullet?
Yeah right.
So in the entity component system, what we call "entity" is just an unsigned int ( the id ). To that id, we associate components, which is a struct of data.
Then they are the systems which are called once per frame.
The system retrieves all entities with certain components ( for example the movement system retrieves all entities with the tranform component and the velocity component ) and then the system does operations on these entities.
Note that we can also use components as flags, with no data.
What I could implement though is factories. For example a tank factory, so that every time we want to spawn a tank, we don't need to specify every component.
Yes that is what I was thinking. I was thinking having a factory header that just defines all types of objects we need in the game.
Also the component table/mask in the environment is a bit confusing to me. How does it work?
Actually every entity has also a mask. This mask tells which components the entity has. You probably noticed that the mask variable type is std::bitset. Every bit represents a component ( the bit position for a component is predefinied ).
The component table stores a list of pointers. Each pointer points to an array of components. For example the array of Transform component. I stored the same components contigously in the memory to have better performances.
For example I see the following line: struct BoundingCircle : public Component< BoundingCircle >
With the code: template< typename T > struct Component { static const unsigned bitpos; };
I may not followed the use of the type correctly, but what role does passing a type through the template parameter have? I mean, where is it being used?
Also I suggest commenting (possibly heavy documenting) the code in environment.h. Maybe it's because I'm not used to templates but I have a hard time following what is going on.
So I traced back to where to how the system is determining what is what, and came across this:
template<typename T, typename U, typename... Rest>
ComponentMask getMask()
{
ComponentMask mask = getMask
Explain how this works (recursion is not one of my strong points).
Ok, I will try to comment a bit more once I get some spare time.
For the Component template, maybe wikipedia explains better than me. http://en.wikipedia.org/wiki/Curiously_recurring_template_pattern See under object counter.
The basic purpose of this is to assign a unique id to every component. And the id is automatically assigned.
Also
Component
even though it's a static variable.
Component::bitpos != Component::bitpos
I meant
Component < Transform > ::bitpos != Component < Velocity > ::bitpos
Ok I'll study up on the design.
For the getMask, I'm using variadic templates
Once you understand those, I think it will be clear why I use recursion.
The "printf" example is worth a look in the link I sent you.
Also note that with the current design we can easily have multiple environments. One for the menu, one for the game, etc...
ok so getmask works similarly to a stack, where on each recurse function call, it "pops" the type from the template parameter list?
On Thu, Nov 27, 2014 at 5:43 AM, Sherushe notifications@github.com wrote:
The "printf" example is worth a look in the link I sent you.
— Reply to this email directly or view it on GitHub https://github.com/Sherushe/tanks/issues/38#issuecomment-64774205.
Yea, basically.
Sorry I removed the vc++ related files. Maybe you will have to recreate a project.
Yea, I figured that when I tried to change to the experimental branch, but the solution was empty On Nov 27, 2014 2:58 PM, "Sherushe" notifications@github.com wrote:
Sorry I removed the vc++ related files. Maybe you will have to recreate a project.
— Reply to this email directly or view it on GitHub https://github.com/Sherushe/tanks/issues/38#issuecomment-64826409.
I like the wiki page.
On the other note, I did a couple small modification on the input system and tank_controls. I also created a MouseControls component that will be used for the GUI. I am currently stuck trying to figure out why Visual Studio doesn't want to see the declaration of the update function.
On Thu, Nov 27, 2014 at 4:42 PM, A Braker abraker95@gmail.com wrote:
Yea, I figured that when I tried to change to the experimental branch, but the solution was empty On Nov 27, 2014 2:58 PM, "Sherushe" notifications@github.com wrote:
Sorry I removed the vc++ related files. Maybe you will have to recreate a project.
— Reply to this email directly or view it on GitHub https://github.com/Sherushe/tanks/issues/38#issuecomment-64826409.
Just a note about the design. The components should only contain data, getters and setters. The logic must be done in the systems. The code will be more clear that way.
I will implement a system so that the collision information is not in a component. The collision informations is not associated to an entity. It's a more global state of the system.
A lot of ECS use the event system like this one. Another idea would be to have components arrays which are not associated to the entities but to the world.
I figured that the components just had values, so I followed that model when creating the MouseControler, but I think the update function has no harm in being there.
You mentioned that the max number of entities is 32. This would give problems when making the GUI and HUD since the number of entities will result a way bigger number than that. Consider on implementing a system that can handle a variable amount of entities.
On Fri, Nov 28, 2014 at 12:24 PM, A Braker abraker95@gmail.com wrote:
I figured that the components just had values, so I followed that model when creating the MouseControler, but I think the update function has no harm in being there.
It has harm being there sorry to tell it like that. If you do it that way that's oop. It couples the component with the system and the ecs is all about decoupling.
It can handle a fixed number of components, but the number can be easily configured ( via the constructor ). It simplifies the code and the performances are better. But the best would be to create another environment for the GUI.
Why can't it be a hybrid OOP and ESC?
On Fri, Nov 28, 2014 at 3:17 PM, Sherushe notifications@github.com wrote:
It can handle a fixed number of components, but the number can be easily configured ( via the constructor ). It simplifies the code and the performances are better. But the best would be to create another environment for the GUI.
— Reply to this email directly or view it on GitHub https://github.com/Sherushe/tanks/issues/38#issuecomment-64925859.
Don't you want to have a clean code? We can do oop when we have to. If it is just to put code in a function we can also do it in the system class.
Did you read a little bit about ecs?
Alright. You might want to fix up the update functions then. I am just used to breaking up the code into smaller, better defined parts instead of having a function with a huge list of statements.
On Fri, Nov 28, 2014 at 4:30 PM, Sherushe notifications@github.com wrote:
Don't you want to have a clean code? We can do oop when we have to. If it is just to put code in a function we can also do it in the system class.
Did you read a little bit about ecs?
— Reply to this email directly or view it on GitHub https://github.com/Sherushe/tanks/issues/38#issuecomment-64929646.
Please document any files you add. I had a link error which took me sometime to figure out I was missing files for projectile in my project to solve it.
The Component system is not optimal. I think I will a dynamic-type of system because it's easier and takes less memory.
What would that design be?
I need to think about it. Maybe I will do the mainstream ECS design where every entity is an object which contains a vector of components. Althought I would prefer components to be contiguous in the memory. Maybe there is a better design.
Well tell me if you come up with something. The ECS design is getting cluttered.
According to the ECS design, is every entity independent of the other? If so, then viewController depends on the Map and crashes without it.
Yes, but it was a bug. It sould not crash when a component is missing. Are you testing everything? I'm impressed you found this malfunction.
I found this when I trying to get the label drawn. The map overlayed the label, so I commented it out and that happened. Yes, I'm testing and still trying to get the label working. For some reason its blinking, and also doesn't want to accept the set font outside a local scope.
Also a layer management system would be nice. The map is overlaying the drawn label, which is another issue that needs resolving.
It's going to be a long while until I push. Getting the label drawn properly is difficult for reasons described above.
Also, commenting out every system update except the render system crashes the game.
Well...
Look at the draw order, if it's overlaying.
For the crash, did you pull the commit I just made? It's probably because of the map bug that it crashes.
Also for the project in general, tell me if's more a pain that fun. Because these past couple of days I was waiting for you to push something so I don't do too much but if it continues like that, it's better if we stop this. I don't really like slow projects. We should either stop for good or do something eaiser. Think about it.
With the final exams approaching, the time spent on the project decreases. I should be able to work on the project much more often starting about after next week. Sorry if I was halting your progress, you can push new commits. It will just take me some time to merge, but I don't think that would be a big issue unless we worked on the same thing.
Ok, if it doesn't bother you, I will push commits when I get things done. I guess it's unavoidable when our rythm is different.
I will try to push shortly after you so you won't need to deal with the merges.
I didn't do anything yet. Push when you want. I will work on it when I'm done with my studies ( in 3~4 hours ).
I will test if we can use some kind of factory design in our program. Resource loading or data initilialization should not be in systems, because it introduces data races.
I'm already using something similar to factories with the system constructors.
On Wed, Dec 10, 2014 at 4:44 PM, Sherushe notifications@github.com wrote:
I will test if we can use some kind of factory design in our program. Resource loading or data initilialization should not be in systems, because it introduces data races.
— Reply to this email directly or view it on GitHub https://github.com/Sherushe/tanks/issues/38#issuecomment-66529604.
I guess it's the UISystem one.
Yeah, I will do something similar for textures, maps, entities, etc. Althought doing it with the system constructor is good but it's only done once. That's a problem, buttons can be created in the middle of the execution for example. My first attempt was to do it inside the system update but it leads to system order of execution to be important. For example, the map can only be loaded after the tilesheet is loaded. That leads to weird dependancies so I thought the best would be to do it separatly.
I think it's the best option here unless you have something better.
Here is my tossed idea:
First make every entity identifiable by name by adding a Name component when creating any entities. unsigned createEntity(T*... t, string _name) in Environment.h
The components indicated by arrows are the ones that need parameters filled. The texture will be located by the name of the entity.
Tank would have these parameters: Tank(x, y, keys)
Tank: --> new Transform(400.f, 300.f, 0.f), new Velocity(0.f, 0.f), new TextureHandle("Tank_0.png"), --> new TankControls(p2_keys), new BoundingCircle(), new Gun(), new Sprite()
Factory System:
template
The factory system would be responsible for creating more entities as a bulk of components. To distinguish, I will call them objects. So it would contain a chain of if statements to pick which object fits the request.
struct Tank { Transform* trans, Velocity* vel, TextureHandle* tex, TankControls* ctrl, BoundingCircle* crcleBnd Gun* gun; Sprite *sprite;
Tank() { /^ construct /) ~Tank() {/ destroy */ } }
System::update() { if(create_entity) { Factory.createObject(new Tank(400.f, 300.f, p2_keys)); } }
This took a long time but I'm happy with the result. I added some components and systems to test if it works and I managed to get a moving tank.
I created a Readme which contains the change log and some explainations about the entity component system ( at the moment, it's just code samples ).
I hope you like it. The advantage with this system is that you can easily combine functionnalities with components, and creating new functionnalities is just creating a new system.