From 81b0a81d10e7121ff4aff676b73ffefcd1cea7cf Mon Sep 17 00:00:00 2001 From: Raphael Schmitz Date: Tue, 19 Sep 2023 21:46:16 +0200 Subject: [PATCH 1/8] Initial PR --- .../entity-component-model/introduction.md | 47 ++++++++++ .../media/ecs-choice.jpg | 3 + .../engine/entity-component-model/usage.md | 91 +++++++++++++++++++ 3 files changed, 141 insertions(+) create mode 100644 en/manual/engine/entity-component-model/introduction.md create mode 100644 en/manual/engine/entity-component-model/media/ecs-choice.jpg create mode 100644 en/manual/engine/entity-component-model/usage.md diff --git a/en/manual/engine/entity-component-model/introduction.md b/en/manual/engine/entity-component-model/introduction.md new file mode 100644 index 000000000..186a4e1c4 --- /dev/null +++ b/en/manual/engine/entity-component-model/introduction.md @@ -0,0 +1,47 @@ +# ECS (Entity Component System) Introduction + +# Problem +> `Dog` is a subclasses of `Animal`. + +This example is often used as an example of inheritance +in introductions to programming. However, when things get more complex, +we get problems: +- `Dog` and `Fish` can swim, so we create `SwimmingAnimal` as a class in between +- `Bee` and `Bird` can fly, so we create `FlyingAnimal` +- What do we now do with the `Duck`, who can do both? + +We have the exact same problem in video games. +Enemies can walk, shoot, fly - but not all of them can do everything. +Even something basic like hitpoints is not universal, as some enemies are indestructible. + +# Solution + + +> Entity component system (ECS) is a software architectural pattern mostly used in video game development for the representation of game world objects. An ECS comprises entities composed from components of data, with systems which operate on entities' components. +> _-[Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system)_ + + +The general idea of an ECS is that an _entity_ - an "object" in your virtual world - +does not really do anything. It is mostly just a "bag of components". + +The selection of components on an entity decides what it does. +An entity with a collider component can collider, an entity with a sound component can make a noise, etc. + +## Differing opinions + +For the "System" part of the term, there are two interpretations: + +A) "Entity-and-Component System" +...in which the components contain the data they need, and also the functionality that works with that data. + +B) "Entity, Component, System" +...in which a component only contains data, while a third part - the system - +contains the functionality. + +Stride allows working in both ways. A) can be achieved by using +[scripts](https://doc.stride3d.net/latest/en/manual/scripts/index.html) +while the usage of B) is described in this section of the manual. + +### Which one to choose? + +![media/ecs-choice.jpg](media/ecs-choice.jpg) diff --git a/en/manual/engine/entity-component-model/media/ecs-choice.jpg b/en/manual/engine/entity-component-model/media/ecs-choice.jpg new file mode 100644 index 000000000..a12c6433e --- /dev/null +++ b/en/manual/engine/entity-component-model/media/ecs-choice.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a54e019040ee38ba3e8bd22db06bf72d66da05e44ad5e41ca73a2671ec22ab1c +size 37751 diff --git a/en/manual/engine/entity-component-model/usage.md b/en/manual/engine/entity-component-model/usage.md new file mode 100644 index 000000000..e094c01b0 --- /dev/null +++ b/en/manual/engine/entity-component-model/usage.md @@ -0,0 +1,91 @@ +# ECS Usage + +## Classes + +The three parts of "Entity Component System" map to the following classes: + +- Entity - [`Stride.Engine.Entity`](https://doc.stride3d.net/latest/en/api/Stride.Engine.Entity.html) +- Component - [`Stride.Engine.EntityComponent`](https://doc.stride3d.net/latest/en/api/Stride.Engine.EntityComponent.html) +- System - [`Stride.Engine.EntityProcessor`](https://doc.stride3d.net/latest/en/api/Stride.Engine.EntityProcessor.html) + + +## Minimal Setup + +A component can be defined by deriving a class from `EntityComponent`. + +By adding the attribute `DefaultEntityComponentProcessor` to an `EntityComponent`, +an `EntityProcessor` can be assigned to it. This will automatically set up and run +the `EntityProcessor` if the `EntityComponent` is in the scene. + +An `EntityComponent` also needs to indicate that it can be serialized +by adding the attribute `DataContract` to it. + +A system can be defined by deriving a class from `EntityProcessor`. + + +### Code + +#### Component +```csharp +[DataContract(nameof(MyComponent))] +[DefaultEntityComponentProcessor(typeof(MyProcessor))] +public class MyComponent : EntityComponent +{ + public int MyValue { get; set; } +} +``` + +#### System +```csharp +public class MyProcessor : EntityProcessor +{ + public override void Update(GameTime time) + { + foreach (var myComponent in ComponentDatas.Values) + { + Console.WriteLine($"myComponent with value {myComponent.MyValue} at {time.Total.TotalSeconds}"); + } + } +} +``` + +### Additional Note +An `EntityComponent` can currently not be drag-dropped onto an entity in Game Studio. +t has to be added by selecting an entity, and then clicking the "Add component" button +in the property grid. + +Alternatively, this can also be done in [code via `entity.Add(entityComponent)`](https://doc.stride3d.net/latest/en/api/Stride.Engine.Entity.html#Stride_Engine_Entity_Add_Stride_Engine_EntityComponent_). + + +## Advanced Features + +### More Component Attributes + +#### Display +By adding the `Display` attribute, a nicer name can be shown in Game Studio. +```csharp +[Display("My better name")] +``` + +#### ComponentCategory +By default, your components will be listed in the category "Miscellaneous". +By adding the `ComponentCategory` attribute, a different category can be chosen. +If the chosen name does not exist yet, it ill be added to the list in Game Studio. +```csharp +[ComponentCategory("My own components")] +``` + +#### ComponentOrder +By adding the `ComponentOrder` attribute, the order in which +components are listed in Game Studio can be changed. +```csharp +[ComponentOrder(2001)] +``` + +### Separation of EntityComponent and Data + +`EntityProcessor` is a shortcut for `EntityProcessor`. + +By explicitly using `EntityProcessor` instead, a different type can be chosen +for the actual data. This way, the `EntityComponent` can e.g. have "heavier" startup data and +references, while the data object that needs to be processed every frame can be kept small. From fc8a1265fd12540f31f0adefe7cfee737de93be0 Mon Sep 17 00:00:00 2001 From: Raphael Schmitz Date: Tue, 19 Sep 2023 22:47:05 +0200 Subject: [PATCH 2/8] Fix typos and add some cool stuff --- .../engine/entity-component-model/usage.md | 22 +++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-) diff --git a/en/manual/engine/entity-component-model/usage.md b/en/manual/engine/entity-component-model/usage.md index e094c01b0..971bb57e1 100644 --- a/en/manual/engine/entity-component-model/usage.md +++ b/en/manual/engine/entity-component-model/usage.md @@ -51,7 +51,7 @@ public class MyProcessor : EntityProcessor ### Additional Note An `EntityComponent` can currently not be drag-dropped onto an entity in Game Studio. -t has to be added by selecting an entity, and then clicking the "Add component" button +It has to be added by selecting an entity, and then clicking the "Add component" button in the property grid. Alternatively, this can also be done in [code via `entity.Add(entityComponent)`](https://doc.stride3d.net/latest/en/api/Stride.Engine.Entity.html#Stride_Engine_Entity_Add_Stride_Engine_EntityComponent_). @@ -70,7 +70,7 @@ By adding the `Display` attribute, a nicer name can be shown in Game Studio. #### ComponentCategory By default, your components will be listed in the category "Miscellaneous". By adding the `ComponentCategory` attribute, a different category can be chosen. -If the chosen name does not exist yet, it ill be added to the list in Game Studio. +If the chosen name does not exist yet, it will be added to the list in Game Studio. ```csharp [ComponentCategory("My own components")] ``` @@ -82,6 +82,24 @@ components are listed in Game Studio can be changed. [ComponentOrder(2001)] ``` + +### Component Combinations +By passing the types of other components to the `EntityProcessor` constructor, +it will only include entities _that also have those other components_. + +For example, the following `EntityProcessor` will only process entities which +have a `MyComponent`, `TransformComponent` and `AnimationComponent` on them. + +```csharp +public class MyProcessor : EntityProcessor +{ + public MyProcessor() : base(typeof(TransformComponent), typeof(AnimationComponent)) + { + } +} +``` + + ### Separation of EntityComponent and Data `EntityProcessor` is a shortcut for `EntityProcessor`. From d7ea7de6787bd62a8059518cff97e0f9dea06009 Mon Sep 17 00:00:00 2001 From: Raphael Schmitz Date: Tue, 19 Sep 2023 22:49:54 +0200 Subject: [PATCH 3/8] Make wording less ambiguous --- en/manual/engine/entity-component-model/usage.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/en/manual/engine/entity-component-model/usage.md b/en/manual/engine/entity-component-model/usage.md index 971bb57e1..a1456d69d 100644 --- a/en/manual/engine/entity-component-model/usage.md +++ b/en/manual/engine/entity-component-model/usage.md @@ -87,8 +87,8 @@ components are listed in Game Studio can be changed. By passing the types of other components to the `EntityProcessor` constructor, it will only include entities _that also have those other components_. -For example, the following `EntityProcessor` will only process entities which -have a `MyComponent`, `TransformComponent` and `AnimationComponent` on them. +For example, the following `EntityProcessor` is for `MyComponent`, but will skip any entity +that does not also have both `TransformComponent` and `AnimationComponent` on it. ```csharp public class MyProcessor : EntityProcessor From cdd52a9f14eaa9bd29addd6d584155f8cae45a31 Mon Sep 17 00:00:00 2001 From: Raphael Schmitz Date: Wed, 20 Sep 2023 00:20:16 +0200 Subject: [PATCH 4/8] Fx typo --- en/manual/engine/entity-component-model/introduction.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/en/manual/engine/entity-component-model/introduction.md b/en/manual/engine/entity-component-model/introduction.md index 186a4e1c4..0d953c733 100644 --- a/en/manual/engine/entity-component-model/introduction.md +++ b/en/manual/engine/entity-component-model/introduction.md @@ -25,7 +25,7 @@ The general idea of an ECS is that an _entity_ - an "object" in your virtual wor does not really do anything. It is mostly just a "bag of components". The selection of components on an entity decides what it does. -An entity with a collider component can collider, an entity with a sound component can make a noise, etc. +An entity with a collider component can collide, an entity with a sound component can make a noise, etc. ## Differing opinions From 79863a300dc62e8f2c58b809c63da4c3d5de444d Mon Sep 17 00:00:00 2001 From: Raphael Schmitz Date: Wed, 20 Sep 2023 00:42:08 +0200 Subject: [PATCH 5/8] Add info about overrides --- en/manual/engine/entity-component-model/usage.md | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/en/manual/engine/entity-component-model/usage.md b/en/manual/engine/entity-component-model/usage.md index a1456d69d..48ea6ac04 100644 --- a/en/manual/engine/entity-component-model/usage.md +++ b/en/manual/engine/entity-component-model/usage.md @@ -107,3 +107,11 @@ public class MyProcessor : EntityProcessor By explicitly using `EntityProcessor` instead, a different type can be chosen for the actual data. This way, the `EntityComponent` can e.g. have "heavier" startup data and references, while the data object that needs to be processed every frame can be kept small. + +This will require overriding a method `GenerateComponentData`, which produces a `TData` instance +from a `TComponent` instance. + +### Overrides +`EntityProcessor` also provides several methods which can be overridden in order to react to certain events. +They are not overly complicated, so that their usage should be clear from their doc comments. + From a394cf4548cfc9744a26d30833aff1a1b1964fd1 Mon Sep 17 00:00:00 2001 From: Raphael Schmitz Date: Wed, 20 Sep 2023 00:49:39 +0200 Subject: [PATCH 6/8] Add part about non-default processors --- en/manual/engine/entity-component-model/usage.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/en/manual/engine/entity-component-model/usage.md b/en/manual/engine/entity-component-model/usage.md index 48ea6ac04..2edd34348 100644 --- a/en/manual/engine/entity-component-model/usage.md +++ b/en/manual/engine/entity-component-model/usage.md @@ -100,6 +100,15 @@ public class MyProcessor : EntityProcessor ``` +### Non-default Processors +Adding processors for a type of component via the attribute `DefaultEntityComponentProcessor` +has been explained above. However, as the name implies, this is for the _default_ processor. +Non-default processors can also be added via +```csharp +EntityManager.Processors.Add(entityProcessor); +``` + + ### Separation of EntityComponent and Data `EntityProcessor` is a shortcut for `EntityProcessor`. From 968bf91459630efd85492bc8478efa1ea319251e Mon Sep 17 00:00:00 2001 From: Raphael Schmitz Date: Wed, 20 Sep 2023 19:43:27 +0200 Subject: [PATCH 7/8] Change code example --- en/manual/engine/entity-component-model/usage.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/en/manual/engine/entity-component-model/usage.md b/en/manual/engine/entity-component-model/usage.md index 2edd34348..889bf9601 100644 --- a/en/manual/engine/entity-component-model/usage.md +++ b/en/manual/engine/entity-component-model/usage.md @@ -105,7 +105,7 @@ Adding processors for a type of component via the attribute `DefaultEntityCompon has been explained above. However, as the name implies, this is for the _default_ processor. Non-default processors can also be added via ```csharp -EntityManager.Processors.Add(entityProcessor); +SceneSystem.SceneInstance.Processors.Add(entityProcessor); ``` From d77bf9a2a297c2796960ff25305df58153d3fc0d Mon Sep 17 00:00:00 2001 From: Raphael Schmitz Date: Mon, 9 Oct 2023 19:15:53 +0200 Subject: [PATCH 8/8] Update according to comments --- .../engine/entity-component-model/index.md | 53 +++++++++++-------- .../entity-component-model/introduction.md | 47 ---------------- .../entity-component-model/media/7438980.png | 3 -- en/manual/toc.md | 1 + 4 files changed, 32 insertions(+), 72 deletions(-) delete mode 100644 en/manual/engine/entity-component-model/introduction.md delete mode 100644 en/manual/engine/entity-component-model/media/7438980.png diff --git a/en/manual/engine/entity-component-model/index.md b/en/manual/engine/entity-component-model/index.md index 1e13192e8..0d953c733 100644 --- a/en/manual/engine/entity-component-model/index.md +++ b/en/manual/engine/entity-component-model/index.md @@ -1,38 +1,47 @@ -# Entity-Component Model +# ECS (Entity Component System) Introduction -
+# Problem +> `Dog` is a subclasses of `Animal`. -# Overview +This example is often used as an example of inheritance +in introductions to programming. However, when things get more complex, +we get problems: +- `Dog` and `Fish` can swim, so we create `SwimmingAnimal` as a class in between +- `Bee` and `Bird` can fly, so we create `FlyingAnimal` +- What do we now do with the `Duck`, who can do both? -@'Stride.Engine.Entity' is the base class for objects that are managed by the high-level engine. +We have the exact same problem in video games. +Enemies can walk, shoot, fly - but not all of them can do everything. +Even something basic like hitpoints is not universal, as some enemies are indestructible. -To improve flexibility, entity are component-based: they can contains as many components as required, containing data and/or logic. +# Solution +> Entity component system (ECS) is a software architectural pattern mostly used in video game development for the representation of game world objects. An ECS comprises entities composed from components of data, with systems which operate on entities' components. +> _-[Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system)_ -![media/7438980.png](media/7438980.png) +The general idea of an ECS is that an _entity_ - an "object" in your virtual world - +does not really do anything. It is mostly just a "bag of components". +The selection of components on an entity decides what it does. +An entity with a collider component can collide, an entity with a sound component can make a noise, etc. +## Differing opinions +For the "System" part of the term, there are two interpretations: -A @'Stride.Engine.Entitycomponent' is tied to its entity (that is, one component can't be added to two entities at the same time). +A) "Entity-and-Component System" +...in which the components contain the data they need, and also the functionality that works with that data. -# How to create an entity and some components +B) "Entity, Component, System" +...in which a component only contains data, while a third part - the system - +contains the functionality. -```cs -// Create entity -var myEntity = new Entity(); - -// Create a model component (so that model is rendered) -var modelComponent = new ModelComponent { Model = model }; -myEntity.Set(ModelComponent.Key, modelComponent); - -// Set entity position -myEntity.Transformation.Translation = new Vector3(100.0f, 100.0f, 0.0f); - -// Add entity to scene; from now on its model will be rendered -Entities.Add(myEntity); -``` +Stride allows working in both ways. A) can be achieved by using +[scripts](https://doc.stride3d.net/latest/en/manual/scripts/index.html) +while the usage of B) is described in this section of the manual. +### Which one to choose? +![media/ecs-choice.jpg](media/ecs-choice.jpg) diff --git a/en/manual/engine/entity-component-model/introduction.md b/en/manual/engine/entity-component-model/introduction.md deleted file mode 100644 index 0d953c733..000000000 --- a/en/manual/engine/entity-component-model/introduction.md +++ /dev/null @@ -1,47 +0,0 @@ -# ECS (Entity Component System) Introduction - -# Problem -> `Dog` is a subclasses of `Animal`. - -This example is often used as an example of inheritance -in introductions to programming. However, when things get more complex, -we get problems: -- `Dog` and `Fish` can swim, so we create `SwimmingAnimal` as a class in between -- `Bee` and `Bird` can fly, so we create `FlyingAnimal` -- What do we now do with the `Duck`, who can do both? - -We have the exact same problem in video games. -Enemies can walk, shoot, fly - but not all of them can do everything. -Even something basic like hitpoints is not universal, as some enemies are indestructible. - -# Solution - - -> Entity component system (ECS) is a software architectural pattern mostly used in video game development for the representation of game world objects. An ECS comprises entities composed from components of data, with systems which operate on entities' components. -> _-[Wikipedia](https://en.wikipedia.org/wiki/Entity_component_system)_ - - -The general idea of an ECS is that an _entity_ - an "object" in your virtual world - -does not really do anything. It is mostly just a "bag of components". - -The selection of components on an entity decides what it does. -An entity with a collider component can collide, an entity with a sound component can make a noise, etc. - -## Differing opinions - -For the "System" part of the term, there are two interpretations: - -A) "Entity-and-Component System" -...in which the components contain the data they need, and also the functionality that works with that data. - -B) "Entity, Component, System" -...in which a component only contains data, while a third part - the system - -contains the functionality. - -Stride allows working in both ways. A) can be achieved by using -[scripts](https://doc.stride3d.net/latest/en/manual/scripts/index.html) -while the usage of B) is described in this section of the manual. - -### Which one to choose? - -![media/ecs-choice.jpg](media/ecs-choice.jpg) diff --git a/en/manual/engine/entity-component-model/media/7438980.png b/en/manual/engine/entity-component-model/media/7438980.png deleted file mode 100644 index ea122c5ab..000000000 --- a/en/manual/engine/entity-component-model/media/7438980.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:63339369b83d3a8c64066bbdd0ba4264fa5ea5e1ade3671a0ae9ce9507342016 -size 2950 diff --git a/en/manual/toc.md b/en/manual/toc.md index 1ca502991..b31ae5121 100644 --- a/en/manual/toc.md +++ b/en/manual/toc.md @@ -52,6 +52,7 @@ ### [Asset bundles](engine/assets/asset-bundles.md) ### [Asset control](engine/assets/asset-control.md) ## [Entity component model](engine/entity-component-model/index.md) +### [Usage](engine/entity-component-model/usage.md) ### [Manage entities](engine/entity-component-model/managing-entities.md) ## [File system](engine/file-system.md)