Post by Admin on Jul 16, 2016 4:11:07 GMT
Arvid Backman backman Jul 30 2015 01:57
I've also had some problem with re-generating code after removing fields from components where it didn't work to generate new code. And I'm guessing it's because of the compile errors that's produced after removing the fields? Is there a workaround for this so you, manually, don't have to do this? @sschmid
Maxim Zaks @mzaks Jul 30 2015 03:05
Hi guys,
it is very cool to see people interested in Entitas and trying stuff out.
First the question about how to combine Unity with Entitas and empowering game designers came up a couple of times, so I decided to write a blog post about it. I hope it will provide answers to the questions which came up also here.
Andreas Wilcox @svdvorak Jul 30 2015 03:42
So, I've been fiddling with Entitas a little and I've stumbled upon the same issues as @dweawyn, @bcatcho and backman.
I've created a similar solution as @dweawyn where I created a ComponentContainer behavior to which I attach IComponents, a StartSystem finds all those containers and creates entities for them (added some code to the generator to make this easier). This only lets me initialize entities using gameobjects which is fine right now but would be nice to keep the gameobjects connected somehow.
Code generation is a bit of a hassle when refactoring. I'm not having trouble adding things since it just adds generated code but removing things requires you to fix them in the generated code before you can regenerate since generation only works for compiling code as I understand.
A few other things I've noticed:
OnEntityAdded does not only respond to when entities matching the trigger are added but also when the component of an existing entity matching the trigger is changed so name is a bit confusing.
Is there an implicit design recommendation to make your components very small? Anything more than 3-4 fields gets pretty unwieldy when adding or replacing a component.
The Match-One game uses the update function from Unity which is not fixed so any framerate issues will carry over to your systems, isn't this a problem in larger projects?
Seems I missed your response @mzaks, looking forward to reading how you've solved that problem.
Maxim Zaks @mzaks Jul 30 2015 03:43
Now to the generator part.
Yes it can become inconvenient specifically because the generator works with Runtime reflection. So if the code does not compile you can't generate again. In large projects I would suggest to create a separate C# project/solution which contains just component classes and than use generator code so that it will produce generated extensions. This however means that you don't get Unity Menu, you have to do it manually, or write a demon which will trigger on every file change.
Now when you want to go with the standard way there you have to be aware of following caveats:
Renaming Component properties is the easiest one. Just use rename refactoring of your IDE and generate. Things should not break because properties only affect method parameter names in the generated methods. Your code should be safe.
Renaming Component name. Again use rename refactoring of your IDE, but after generate you will get compile errors due to the fact that Component name is reflected in generated Method Names. This is in my experience easily fixable. However if you want to avoid the hassle you can go to the generated class after you rename refactored your component name and than perform rename refactoring on each method name. It is up to 7 method names. It is inconvenient, but not as inconvenient as solving compile errors. Press generate and you are good to go.
Adding new properties to component. This by itself is fine, However after generate you will get compile errors. Because 2 method will get more parameters (AddXXX/ReplaceXXX). If your IDE lets you refactor method signature, than you are good. However if we are reasonable you have to change your code anyways so that you can add and replace components according to new set of properties. In this case having compile errors is actually a good thing.
Removing properties from component. This will directly lead to compilation errors because you probably used it somewhere already or at least the generated classes are using them. In this case you can just comment out implementation inside of (AddXXX/ReplaceXXX) methods of generated classes and fix your code which uses a property which you just removed. Press generate and you are good to go.
Deleting component. Delete the generated class completely, fix your code.
Maybe @sschmid will have some more tips or will come up with some tools for making it even better.
This is however how my team does it in our project.
For reference the project is a bigger simulation game with more that 300 Systems and more than 150 Component classes.
Andreas Wilcox @svdvorak Jul 30 2015 03:56
Excellent writeup @mzaks (and just after I posted)! It kinda sucks that the code has to compile for the generator to work since it would be great if one could just delete the generated folder and regenerate everything (which is what I did at first, bad idea). It's mostly point nr 2 & 4 that's bothered me, having to fix generated code as a stopgap is a bit annoying. An autogenerate-trigger sounds handy though, I'll have to look into that.
Kamil Chmurzynski @cloudjubei Jul 30 2015 05:58
Hey guys, I'm working with @mzaks and @sschmid, and I just wanted to add my bit to the discussion and maybe it will clarify some things for you guys.
I read that you guys try to wrap IComponents or Entities into behaviours. You would like to edit components on the fly in the editor - you certainly can do so (or your artists or designers). Once you run your game in the hierarchy view, you can see all the entities that you've created and select them to edit all their components. @sschmid shows exactly how this is done at the Unite talk (for instance when he moves a Gem by changing its position component or by changing a Gem to be movable or its sprite). Just watch the video again to see where the editor windows are.
Now why you shouldn't wrap IComponents or Entities into behaviours or anything else. While we use Entitas we treat Unity simply as a Rendering Engine. Technically we treat it as a bit more because we do put some RootBehaviour that executes all the systems in its Update function and we need to access player input, but apart from this - we're oblivious to the fact that we're using Unity. Technically the idea is that you could take the game you write using Entitas and if you switch the Rendering Engine (for instance to some other C# based engine) then you still would get it to run. In the simulation game that @mzaks mentioned - we actually only need 2 MonoBehaviours (we use a couple more cos we also use some external plugins, but if not for those we only require really 2). The first is the aforementioned RootBehaviour that basically Executes all systems and the other is an InputBehaviour that reacts to player input to create Entities with Components that describe the input. Apart from these 2 Behaviours we don't care how Unity works. Sure you have to know that if you want to create some UI you probably need a Canvas and stuff like that, but then just create a an Entity with a HUDComponent that will inside hold a reference to a GameObject. Then you can access this Entity and its component if you need to change its visual appearance.
The same story goes for using prefabs or creating any GameObjects. Write a system that probably in the constructor gets the prefab from the Resources folder and then on Execute, Instantiates the GameObjects and adds GameObjectComponents (with the GameObject as a parameter) to some entities. Voila, you've just added some GameObjects to the scene and you can still access them in the editor like @sschmid shows in the talk.
Once you understand the relationship between Unity - Entitas and the fact that you want to use Unity pretty much only as a Rendering Engine, then it will become clearer how you should structure your code.
Maxim Zaks @mzaks Jul 30 2015 06:11
@svdvorak about the other things
Replacing component is generally just remove and add. As a matter of fact we didn't had replace for a long time. This was introduced as convenience and also as performance optimisation afterwards. This is basically why OnEntityAdded is also triggered when you replace. Agree that it can look a bit confusing in the beginning though.
Yeah you are better with small components also for the reason that you can achieve more fine grain querying for entities. I would suggest putting multiple properties on the same components only if it is wrong to separate them e.g. PositionComponent has to have x,y,z as property in a 3D setup.
Update vs. fix update is pretty much game specific. This is one of my favourite topics to be honest In case of update you will get slow motion effect, in case of fixed update you get visual glitches. Also in case of fixed updates, you might get into the cycle where each update produces even more work for the next update and this might kill your simulation. So as I sad it is game specific, you might argue that for reaction game visual glitches are better than slow motion. However if you think about it, visual glitch means that you give less time for player to react. Slow motion is giving more time for player to react. Frame rate issue is normally on us developers. We added features which are harder to compute on a certain type of hardware. Now comes the million dollar question. Should we make players life harder or easier because of our mistake? And last but not least everything what I just wrote states for deterministic simulations, where all computations are tick and not delta time based.
Andreas Wilcox @svdvorak Jul 30 2015 06:27
Thanks for the great replies.
@cloudjubei I get the point that you can see the entities in the hierarchy while running but what I'm after is essentially level editing. I'm making a strategy game and when making a level I want to be able to place my units on the map in Unity during design and not have to write code to place them. I totally agree about the separation of Entitas and Unity, it creates cleaner code (when you treat Unity stuff as View from MVC/MVVM-patterns) and makes it so much easier to unit test. As I mentioned I made a solution that works right now where I can design in Unity by setting up gameobjects with IComponents (in a container, IComponents still know nothing about Unity) which then a system finds and creates entities for (with those components). But after start runtime the GameObject IComponents are disconnected from the entities so you still have to go to the Entitas-pool to edit any properties. I haven't gotten far with it yet so we'll see how this turns out. Maybe just having a way to jump from the original GameObject to the Entity in the Pool-view could be enough.
@mzaks
Andreas Wilcox @svdvorak Jul 30 2015 06:35
Ah, then I get why. I just noticed that those events aren't mentioned in the wiki, when they are it should probably be mentioned. You don't mind a pull request to update the wiki with that info (and about the events)?
I kinda figured so. Still need to wrap my head around how to create components effectively, still to used to having a single container for a feature instead of multiple.
Ok, it's a tricky problem for sure. The fact you manually have to handle which to use normally is kind of messy, it's absolutely nicer to have one which just works... that's why I'm curious how that has worked for your projects. I'll just follow YAGNI until it becomes a problem =)
Arvid Backman backman Jul 30 2015 06:38
Holy shit! All these answers and questions are just great! Thanks a bunch guys.
The game we currently are developing, which have been in development for a little over a year now, at the studio I'm working at we have written our own Entity-Component System. And we are treating Unity exactly as @cloudjubei said, "As a Rendering Engine". It's cool to see another solution and example of this approach!
Brandon Catcho @bcatcho Jul 30 2015 09:38
@cloudjubei I think you are underscoring what I realized after spending about 8 hours with Entitas so far: It really makes you reconsider how you work with Unity. Unfortunately for me this means re-imagining how I architect my Unity games. In the short term this will slow me down but I think I've seen enough potential to try and work through some of these challenges.
One note: The DebugSystems object is a big hinderance on the performance of the GameView in the Unity Editor. I think it may have something to do with the name of the object updating over and over but I can't tell. Is it due to the performance monitoring or the graph and constant update of the GameObject's name?
Maxim Zaks @mzaks Jul 30 2015 16:46
@bcatcho we just stumbled upon some debug issues ourselves @sschmid has a fix in the pipeline.
Simon Schmid @sschmid Jul 30 2015 16:52
Hey guys! It's nice to see that you're giving Entitas a try! It will be worth it
There have already been really good answers and I just want to share my take on it. Most of these points have already been made, so it's more like supporting suggestions already been made.
Code Generator
I totally get you guys. When you just got started using Entitas and the Code Generator, there are a few pitfalls, the biggest one beeing to only be able to generate when your solution is compiling. In the beginning I struggled with that issue, too. But, I think it's just an issue in the beginning, when you're playing around and create / delete and rename Components and their fields all the time. Once you got the hang of it and you know what to keep in mind, this issue completely vanishes into the background. Personally, I don't even think about that anymore (and I love renaming and deleting
Also, imagine a plain old Person class with string name and int age which you use everywhere in your game. If you decide to remove the age field, you'd have to fix all the places you use it. So this issue isn't really exclusive to Entitas and the Code Generator - it just feels worse, because you cannot generate anymore until you fixed everything.
Designing levels
Let me explain, how I see this:
For me levels are just data - some configuration where things are and what their state is. E.g. a building at a certain position in the world that can be attacked and has a certain health.
I don't really care if I get this information from a json or a scene from Unity. In both cases I parse the source and create entities based on the data. In this example I'd create an Entity with BuildingComponent, PositionComponent, AttackableComponent, HealthComponent
The cool thing is, when you're designing your level in Unity, you already have the view, too! So when you parse your scene you already can link the actual building GameObject to the Entity by adding a ViewComponent
public class ViewComponent : IComponent {
public GameObject gameObject;
}
Again: a designer is completely free to create a level. He/she can setup e.g. multiple buildings at different positions, with different health and so on... the important part is: All the Monobehaviours on that GameObject should NOT have any game related logic! Only configuration like transform, health, attackable, etc. They might have some View related logic like animating something on the building. The GameObject should be treated as a dumb view with no behaviour! It's just a View
Maxim Zaks @mzaks Jul 30 2015 16:56
@svdvorak stuff become easier when you instantiate your game objects in systems according to some entity. Than you can have a GameObjectComponent which links entity to the game object. This way for example when you want to destroy an entity you can destroy GameObject by listening for GameObjectComponent will be removed.
That sad I would suggest destroying entities only in cases when it is really necessary. Destroying entities can be expensive. And most of the time flagging an entity as destroyed by a DestroyComponent is enough.
Now sometimes you need a link from GameObject to Entity. Fro example when you have a collider on a game object. OnCollision you know which game object was hit but it would be interesting to jump from GameObject to entity. In this case we have an EntityLinkBehaviour which has only one public field entity which we set when we create the game object from an entity.
If you think about it, it is like IoC you want to be in control of creating objects so that you can query for them.
If you can't create the game object yourself because it is part of the scene or a child of a prefab, you can find the game object afterward and put a reference on it into a component. You don't have to because you could query for this game object all the time, but performance wise it is better to have a LinkComponent because traversing GameObject tree in Unity might get expensive.
my GameObjectComponent is @sschmid ViewComponent
Simon Schmid @sschmid Jul 30 2015 17:09
@mzaks not sure about not destroying entities. I do that all the time when they are not used anymore. The way I usually do it is: I flag an entity
e.isDestroy = true;
and then the last system in the chain is the DestroySystem
(see github.com/sschmid/Match-One/blob/master/Assets/Sources/Features/Destroy/DestroySystem.cs)
This way all components are still available to other systems that might want to respond to destroyed entities, like the RemoveViewSystem which still can reference the actual GameObject and can destroy that as well compared to destroying the Entity directly in the middle of the systems chain. In this case all components will be removed and cannot be accessed anymore.
Alternatively you can react on group changes directly and destroy the view
see github.com/sschmid/Match-One/blob/master/Assets/Sources/Features/RenderResource/RemoveViewSystem.cs#L12
In general, the Match One example covers a lot of these ideas
github.com/sschmid/Match-One
Maxim Zaks @mzaks Jul 30 2015 17:31
@sschmid agree it depends on the simulation. Some times it is better to keep the entities around in case that you want to resurrect them or something
Andreas Wilcox @svdvorak Jul 30 2015 17:50
@sschmid & @mzaks Ok, it sounds I'm doing the correct thing by going through the level and generating entities for Views (gameobjects) already in the scene. Finding GameObjects in the scene continuously during runtime would be incredibly wasteful so I'll make do with doing it once during startup using a link component. I guess I'll have to jump to the entities in the debug pool if I want to change any values for testing during play though, would have been nice to edit the components in the View and have them reflected on the corresponding entities. Maybe I can just make a button in the inspector that moves your gameobject selection in the hierarchy from the gameobject to the entity.
Another question: should components have references to other entities? Essentially, how do you handle "parenting" in Entitas? For example, right now I have a squad entity with a system that creates unit entities for each squad entity. When changing the dimensions of the squad I destroy all units in the squad and recreate them but I must make sure to do that only for that specific squad. Right now I added an integer field for squad number in each unit component but could/should I have an Entity field which references the squad entity?
Oh, have any of you any experience of doing integration testing using Unity Test Tools and Entitas?
Thank you so much for taking time and giving these great replies! The Match-One example project is great also! More fully fledged than most frameworks usually have.
Arvid Backman backman Jul 30 2015 22:04
Thank you!
As @svdvorak I would also like to thank you all for answering all questions about Entitas! I'm getting more and more excited about this!
movrajr @movrajr Jul 30 2015 22:32
@svdvorak I wonder if you could regard Entitas as a database system. Then you would have to add an ID component to each entity. Instead of storing references to other entities within entities themselves, association between entities would be handled in a temporary table.
movrajr @movrajr Jul 30 2015 22:58
Maybe some inspiration here www.datomic.com/rationale.html
umaelements @umaelements Jul 30 2015 23:33
Has anyone used Entitas as a basis for a Unity headless multiplayer rpg server?
dweawyn @dweawyn Jul 30 2015 23:51
@sschmid @mzaks @cloudjubei Thanks for all the answers. I really appreciate that you share your experience with the framework. It definitely helps newcomers to switch to this new mindset.
I've also had some problem with re-generating code after removing fields from components where it didn't work to generate new code. And I'm guessing it's because of the compile errors that's produced after removing the fields? Is there a workaround for this so you, manually, don't have to do this? @sschmid
Maxim Zaks @mzaks Jul 30 2015 03:05
Hi guys,
it is very cool to see people interested in Entitas and trying stuff out.
First the question about how to combine Unity with Entitas and empowering game designers came up a couple of times, so I decided to write a blog post about it. I hope it will provide answers to the questions which came up also here.
Andreas Wilcox @svdvorak Jul 30 2015 03:42
So, I've been fiddling with Entitas a little and I've stumbled upon the same issues as @dweawyn, @bcatcho and backman.
I've created a similar solution as @dweawyn where I created a ComponentContainer behavior to which I attach IComponents, a StartSystem finds all those containers and creates entities for them (added some code to the generator to make this easier). This only lets me initialize entities using gameobjects which is fine right now but would be nice to keep the gameobjects connected somehow.
Code generation is a bit of a hassle when refactoring. I'm not having trouble adding things since it just adds generated code but removing things requires you to fix them in the generated code before you can regenerate since generation only works for compiling code as I understand.
A few other things I've noticed:
OnEntityAdded does not only respond to when entities matching the trigger are added but also when the component of an existing entity matching the trigger is changed so name is a bit confusing.
Is there an implicit design recommendation to make your components very small? Anything more than 3-4 fields gets pretty unwieldy when adding or replacing a component.
The Match-One game uses the update function from Unity which is not fixed so any framerate issues will carry over to your systems, isn't this a problem in larger projects?
Seems I missed your response @mzaks, looking forward to reading how you've solved that problem.
Maxim Zaks @mzaks Jul 30 2015 03:43
Now to the generator part.
Yes it can become inconvenient specifically because the generator works with Runtime reflection. So if the code does not compile you can't generate again. In large projects I would suggest to create a separate C# project/solution which contains just component classes and than use generator code so that it will produce generated extensions. This however means that you don't get Unity Menu, you have to do it manually, or write a demon which will trigger on every file change.
Now when you want to go with the standard way there you have to be aware of following caveats:
Renaming Component properties is the easiest one. Just use rename refactoring of your IDE and generate. Things should not break because properties only affect method parameter names in the generated methods. Your code should be safe.
Renaming Component name. Again use rename refactoring of your IDE, but after generate you will get compile errors due to the fact that Component name is reflected in generated Method Names. This is in my experience easily fixable. However if you want to avoid the hassle you can go to the generated class after you rename refactored your component name and than perform rename refactoring on each method name. It is up to 7 method names. It is inconvenient, but not as inconvenient as solving compile errors. Press generate and you are good to go.
Adding new properties to component. This by itself is fine, However after generate you will get compile errors. Because 2 method will get more parameters (AddXXX/ReplaceXXX). If your IDE lets you refactor method signature, than you are good. However if we are reasonable you have to change your code anyways so that you can add and replace components according to new set of properties. In this case having compile errors is actually a good thing.
Removing properties from component. This will directly lead to compilation errors because you probably used it somewhere already or at least the generated classes are using them. In this case you can just comment out implementation inside of (AddXXX/ReplaceXXX) methods of generated classes and fix your code which uses a property which you just removed. Press generate and you are good to go.
Deleting component. Delete the generated class completely, fix your code.
Maybe @sschmid will have some more tips or will come up with some tools for making it even better.
This is however how my team does it in our project.
For reference the project is a bigger simulation game with more that 300 Systems and more than 150 Component classes.
Andreas Wilcox @svdvorak Jul 30 2015 03:56
Excellent writeup @mzaks (and just after I posted)! It kinda sucks that the code has to compile for the generator to work since it would be great if one could just delete the generated folder and regenerate everything (which is what I did at first, bad idea). It's mostly point nr 2 & 4 that's bothered me, having to fix generated code as a stopgap is a bit annoying. An autogenerate-trigger sounds handy though, I'll have to look into that.
Kamil Chmurzynski @cloudjubei Jul 30 2015 05:58
Hey guys, I'm working with @mzaks and @sschmid, and I just wanted to add my bit to the discussion and maybe it will clarify some things for you guys.
I read that you guys try to wrap IComponents or Entities into behaviours. You would like to edit components on the fly in the editor - you certainly can do so (or your artists or designers). Once you run your game in the hierarchy view, you can see all the entities that you've created and select them to edit all their components. @sschmid shows exactly how this is done at the Unite talk (for instance when he moves a Gem by changing its position component or by changing a Gem to be movable or its sprite). Just watch the video again to see where the editor windows are.
Now why you shouldn't wrap IComponents or Entities into behaviours or anything else. While we use Entitas we treat Unity simply as a Rendering Engine. Technically we treat it as a bit more because we do put some RootBehaviour that executes all the systems in its Update function and we need to access player input, but apart from this - we're oblivious to the fact that we're using Unity. Technically the idea is that you could take the game you write using Entitas and if you switch the Rendering Engine (for instance to some other C# based engine) then you still would get it to run. In the simulation game that @mzaks mentioned - we actually only need 2 MonoBehaviours (we use a couple more cos we also use some external plugins, but if not for those we only require really 2). The first is the aforementioned RootBehaviour that basically Executes all systems and the other is an InputBehaviour that reacts to player input to create Entities with Components that describe the input. Apart from these 2 Behaviours we don't care how Unity works. Sure you have to know that if you want to create some UI you probably need a Canvas and stuff like that, but then just create a an Entity with a HUDComponent that will inside hold a reference to a GameObject. Then you can access this Entity and its component if you need to change its visual appearance.
The same story goes for using prefabs or creating any GameObjects. Write a system that probably in the constructor gets the prefab from the Resources folder and then on Execute, Instantiates the GameObjects and adds GameObjectComponents (with the GameObject as a parameter) to some entities. Voila, you've just added some GameObjects to the scene and you can still access them in the editor like @sschmid shows in the talk.
Once you understand the relationship between Unity - Entitas and the fact that you want to use Unity pretty much only as a Rendering Engine, then it will become clearer how you should structure your code.
Maxim Zaks @mzaks Jul 30 2015 06:11
@svdvorak about the other things
Replacing component is generally just remove and add. As a matter of fact we didn't had replace for a long time. This was introduced as convenience and also as performance optimisation afterwards. This is basically why OnEntityAdded is also triggered when you replace. Agree that it can look a bit confusing in the beginning though.
Yeah you are better with small components also for the reason that you can achieve more fine grain querying for entities. I would suggest putting multiple properties on the same components only if it is wrong to separate them e.g. PositionComponent has to have x,y,z as property in a 3D setup.
Update vs. fix update is pretty much game specific. This is one of my favourite topics to be honest In case of update you will get slow motion effect, in case of fixed update you get visual glitches. Also in case of fixed updates, you might get into the cycle where each update produces even more work for the next update and this might kill your simulation. So as I sad it is game specific, you might argue that for reaction game visual glitches are better than slow motion. However if you think about it, visual glitch means that you give less time for player to react. Slow motion is giving more time for player to react. Frame rate issue is normally on us developers. We added features which are harder to compute on a certain type of hardware. Now comes the million dollar question. Should we make players life harder or easier because of our mistake? And last but not least everything what I just wrote states for deterministic simulations, where all computations are tick and not delta time based.
Andreas Wilcox @svdvorak Jul 30 2015 06:27
Thanks for the great replies.
@cloudjubei I get the point that you can see the entities in the hierarchy while running but what I'm after is essentially level editing. I'm making a strategy game and when making a level I want to be able to place my units on the map in Unity during design and not have to write code to place them. I totally agree about the separation of Entitas and Unity, it creates cleaner code (when you treat Unity stuff as View from MVC/MVVM-patterns) and makes it so much easier to unit test. As I mentioned I made a solution that works right now where I can design in Unity by setting up gameobjects with IComponents (in a container, IComponents still know nothing about Unity) which then a system finds and creates entities for (with those components). But after start runtime the GameObject IComponents are disconnected from the entities so you still have to go to the Entitas-pool to edit any properties. I haven't gotten far with it yet so we'll see how this turns out. Maybe just having a way to jump from the original GameObject to the Entity in the Pool-view could be enough.
@mzaks
Andreas Wilcox @svdvorak Jul 30 2015 06:35
Ah, then I get why. I just noticed that those events aren't mentioned in the wiki, when they are it should probably be mentioned. You don't mind a pull request to update the wiki with that info (and about the events)?
I kinda figured so. Still need to wrap my head around how to create components effectively, still to used to having a single container for a feature instead of multiple.
Ok, it's a tricky problem for sure. The fact you manually have to handle which to use normally is kind of messy, it's absolutely nicer to have one which just works... that's why I'm curious how that has worked for your projects. I'll just follow YAGNI until it becomes a problem =)
Arvid Backman backman Jul 30 2015 06:38
Holy shit! All these answers and questions are just great! Thanks a bunch guys.
The game we currently are developing, which have been in development for a little over a year now, at the studio I'm working at we have written our own Entity-Component System. And we are treating Unity exactly as @cloudjubei said, "As a Rendering Engine". It's cool to see another solution and example of this approach!
Brandon Catcho @bcatcho Jul 30 2015 09:38
@cloudjubei I think you are underscoring what I realized after spending about 8 hours with Entitas so far: It really makes you reconsider how you work with Unity. Unfortunately for me this means re-imagining how I architect my Unity games. In the short term this will slow me down but I think I've seen enough potential to try and work through some of these challenges.
One note: The DebugSystems object is a big hinderance on the performance of the GameView in the Unity Editor. I think it may have something to do with the name of the object updating over and over but I can't tell. Is it due to the performance monitoring or the graph and constant update of the GameObject's name?
Maxim Zaks @mzaks Jul 30 2015 16:46
@bcatcho we just stumbled upon some debug issues ourselves @sschmid has a fix in the pipeline.
Simon Schmid @sschmid Jul 30 2015 16:52
Hey guys! It's nice to see that you're giving Entitas a try! It will be worth it
There have already been really good answers and I just want to share my take on it. Most of these points have already been made, so it's more like supporting suggestions already been made.
Code Generator
I totally get you guys. When you just got started using Entitas and the Code Generator, there are a few pitfalls, the biggest one beeing to only be able to generate when your solution is compiling. In the beginning I struggled with that issue, too. But, I think it's just an issue in the beginning, when you're playing around and create / delete and rename Components and their fields all the time. Once you got the hang of it and you know what to keep in mind, this issue completely vanishes into the background. Personally, I don't even think about that anymore (and I love renaming and deleting
Also, imagine a plain old Person class with string name and int age which you use everywhere in your game. If you decide to remove the age field, you'd have to fix all the places you use it. So this issue isn't really exclusive to Entitas and the Code Generator - it just feels worse, because you cannot generate anymore until you fixed everything.
Designing levels
Let me explain, how I see this:
For me levels are just data - some configuration where things are and what their state is. E.g. a building at a certain position in the world that can be attacked and has a certain health.
I don't really care if I get this information from a json or a scene from Unity. In both cases I parse the source and create entities based on the data. In this example I'd create an Entity with BuildingComponent, PositionComponent, AttackableComponent, HealthComponent
The cool thing is, when you're designing your level in Unity, you already have the view, too! So when you parse your scene you already can link the actual building GameObject to the Entity by adding a ViewComponent
public class ViewComponent : IComponent {
public GameObject gameObject;
}
Again: a designer is completely free to create a level. He/she can setup e.g. multiple buildings at different positions, with different health and so on... the important part is: All the Monobehaviours on that GameObject should NOT have any game related logic! Only configuration like transform, health, attackable, etc. They might have some View related logic like animating something on the building. The GameObject should be treated as a dumb view with no behaviour! It's just a View
Maxim Zaks @mzaks Jul 30 2015 16:56
@svdvorak stuff become easier when you instantiate your game objects in systems according to some entity. Than you can have a GameObjectComponent which links entity to the game object. This way for example when you want to destroy an entity you can destroy GameObject by listening for GameObjectComponent will be removed.
That sad I would suggest destroying entities only in cases when it is really necessary. Destroying entities can be expensive. And most of the time flagging an entity as destroyed by a DestroyComponent is enough.
Now sometimes you need a link from GameObject to Entity. Fro example when you have a collider on a game object. OnCollision you know which game object was hit but it would be interesting to jump from GameObject to entity. In this case we have an EntityLinkBehaviour which has only one public field entity which we set when we create the game object from an entity.
If you think about it, it is like IoC you want to be in control of creating objects so that you can query for them.
If you can't create the game object yourself because it is part of the scene or a child of a prefab, you can find the game object afterward and put a reference on it into a component. You don't have to because you could query for this game object all the time, but performance wise it is better to have a LinkComponent because traversing GameObject tree in Unity might get expensive.
my GameObjectComponent is @sschmid ViewComponent
Simon Schmid @sschmid Jul 30 2015 17:09
@mzaks not sure about not destroying entities. I do that all the time when they are not used anymore. The way I usually do it is: I flag an entity
e.isDestroy = true;
and then the last system in the chain is the DestroySystem
(see github.com/sschmid/Match-One/blob/master/Assets/Sources/Features/Destroy/DestroySystem.cs)
This way all components are still available to other systems that might want to respond to destroyed entities, like the RemoveViewSystem which still can reference the actual GameObject and can destroy that as well compared to destroying the Entity directly in the middle of the systems chain. In this case all components will be removed and cannot be accessed anymore.
Alternatively you can react on group changes directly and destroy the view
see github.com/sschmid/Match-One/blob/master/Assets/Sources/Features/RenderResource/RemoveViewSystem.cs#L12
In general, the Match One example covers a lot of these ideas
github.com/sschmid/Match-One
Maxim Zaks @mzaks Jul 30 2015 17:31
@sschmid agree it depends on the simulation. Some times it is better to keep the entities around in case that you want to resurrect them or something
Andreas Wilcox @svdvorak Jul 30 2015 17:50
@sschmid & @mzaks Ok, it sounds I'm doing the correct thing by going through the level and generating entities for Views (gameobjects) already in the scene. Finding GameObjects in the scene continuously during runtime would be incredibly wasteful so I'll make do with doing it once during startup using a link component. I guess I'll have to jump to the entities in the debug pool if I want to change any values for testing during play though, would have been nice to edit the components in the View and have them reflected on the corresponding entities. Maybe I can just make a button in the inspector that moves your gameobject selection in the hierarchy from the gameobject to the entity.
Another question: should components have references to other entities? Essentially, how do you handle "parenting" in Entitas? For example, right now I have a squad entity with a system that creates unit entities for each squad entity. When changing the dimensions of the squad I destroy all units in the squad and recreate them but I must make sure to do that only for that specific squad. Right now I added an integer field for squad number in each unit component but could/should I have an Entity field which references the squad entity?
Oh, have any of you any experience of doing integration testing using Unity Test Tools and Entitas?
Thank you so much for taking time and giving these great replies! The Match-One example project is great also! More fully fledged than most frameworks usually have.
Arvid Backman backman Jul 30 2015 22:04
Thank you!
As @svdvorak I would also like to thank you all for answering all questions about Entitas! I'm getting more and more excited about this!
movrajr @movrajr Jul 30 2015 22:32
@svdvorak I wonder if you could regard Entitas as a database system. Then you would have to add an ID component to each entity. Instead of storing references to other entities within entities themselves, association between entities would be handled in a temporary table.
movrajr @movrajr Jul 30 2015 22:58
Maybe some inspiration here www.datomic.com/rationale.html
umaelements @umaelements Jul 30 2015 23:33
Has anyone used Entitas as a basis for a Unity headless multiplayer rpg server?
dweawyn @dweawyn Jul 30 2015 23:51
@sschmid @mzaks @cloudjubei Thanks for all the answers. I really appreciate that you share your experience with the framework. It definitely helps newcomers to switch to this new mindset.