OpenColloq WS24 ECS
BIN
OpenColloq/WS24_EntityComponentSystem/content/._index.md.swp
Normal file
BIN
OpenColloq/WS24_EntityComponentSystem/content/._index.md.un~
Normal file
|
After Width: | Height: | Size: 34 KiB |
|
After Width: | Height: | Size: 4.3 KiB |
505
OpenColloq/WS24_EntityComponentSystem/content/_index.md
Normal file
|
|
@ -0,0 +1,505 @@
|
|||
+++
|
||||
title = "Entity Component System - It's not a system"
|
||||
outputs = ["Reveal"]
|
||||
+++
|
||||
|
||||
# Entity Component System
|
||||
|
||||
---
|
||||
|
||||
## What is (an) ECS?
|
||||
- {{< frag c="unnecessary" >}}
|
||||
- {{< frag c="useful" >}}
|
||||
- {{< frag c="not a system" >}}
|
||||
|
||||
{{% note %}}
|
||||
|
||||
Talk about structure of presentation here:
|
||||
- define terms like "entity", "component", "system"
|
||||
- go over other approaches to "motivate" ECS
|
||||
- main 3 game engines will be mentioned (Unity, Unreal, Godot)
|
||||
- talking about the level of programming engines, not games
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
## What are entities?
|
||||
[^1]
|
||||
|
||||
[^1]: https://br.ign.com/league-of-legends-wild-rift/89123/feature/wild-rift-tudo-sobre-o-lol-mobile ; Image: Riot Games
|
||||
|
||||
---
|
||||
|
||||
## What are entities?
|
||||
[^2]
|
||||
|
||||
[^2]: https://pressakey.com/gameinfos,4981,screenshots,,,Age-of-Empires-Definitive-Edition,.html
|
||||
|
||||
---
|
||||
|
||||
## What are entities?
|
||||
- Objects in a game (or simulation)
|
||||
- Can have different behaviours
|
||||
- {{< frag c="Basically everything" >}}
|
||||
|
||||
---
|
||||
|
||||
# INHERITANCE
|
||||
|
||||
---
|
||||
|
||||
{{% section %}}
|
||||
|
||||
{{< slide transition="none" >}}
|
||||
|
||||
## Inheritance
|
||||
```mermaid
|
||||
graph TD;
|
||||
Entity-->MoveableEntity;
|
||||
Entity-->PhysicsEntity;
|
||||
```
|
||||
|
||||
{{% note %}}
|
||||
|
||||
Entity: Basic information like transform and mesh in our example
|
||||
MoveableEntity: Entity with functions to move with and support animations
|
||||
PhysicsEntity: Walls, Falling Boulders and stuff; Colliders and Gravity
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
{{< slide transition="none" >}}
|
||||
|
||||
## Inheritance
|
||||
```mermaid
|
||||
graph TD;
|
||||
Entity-->MoveableEntity;
|
||||
Entity-->PhysicsEntity;
|
||||
MoveableEntity-->Character;
|
||||
PhysicsEntity-->BoxColliderEntity;
|
||||
```
|
||||
|
||||
{{% note %}}
|
||||
|
||||
Entity: Basic information like transform and mesh in our example
|
||||
MoveableEntity: Entity with functions to move with and support animations
|
||||
PhysicsEntity: Walls, Falling Boulders and stuff; Colliders and Gravity
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
{{< slide transition="none" >}}
|
||||
|
||||
## Inheritance
|
||||
```mermaid
|
||||
graph TD;
|
||||
Entity-->MoveableEntity;
|
||||
Entity-->PhysicsEntity;
|
||||
MoveableEntity-->Character;
|
||||
Character-->Player;
|
||||
Character-->NPC;
|
||||
PhysicsEntity-->BoxColliderEntity;
|
||||
```
|
||||
|
||||
{{% note %}}
|
||||
|
||||
Entity: Basic information like transform and mesh in our example
|
||||
MoveableEntity: Entity with functions to move with and support animations
|
||||
PhysicsEntity: Walls, Falling Boulders and stuff; Colliders and Gravity
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
{{% /section %}}
|
||||
|
||||
---
|
||||
|
||||
## Godot
|
||||

|
||||
[^3]
|
||||
|
||||
[^3]: Screenshot: Godot Engine
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Godot Code
|
||||
```cpp
|
||||
class Node2D : public CanvasItem {
|
||||
...
|
||||
}
|
||||
.
|
||||
.
|
||||
.
|
||||
class PhysicsBody2D : public CollisionObject2D {
|
||||
...
|
||||
}
|
||||
class CharacterBody2D : public PhysicsBody2D {
|
||||
...
|
||||
}
|
||||
```
|
||||
[^4]
|
||||
|
||||
[^4]: https://github.com/godotengine/godot
|
||||
|
||||
---
|
||||
|
||||
{{% section %}}
|
||||
{{< slide transition="none" >}}
|
||||
|
||||
## Inheritance
|
||||
```mermaid
|
||||
graph TD;
|
||||
Entity-->MoveableEntity;
|
||||
Entity-->PhysicsEntity;
|
||||
MoveableEntity-->Character;
|
||||
Character-->Player;
|
||||
Character-->NPC;
|
||||
PhysicsEntity-->BoxColliderEntity;
|
||||
MoveableEntity-->Vehicle;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
{{< slide transition="none" >}}
|
||||
|
||||
## Multiple Inheritance
|
||||
```mermaid
|
||||
graph TD;
|
||||
Entity-->MoveableEntity;
|
||||
Entity-->PhysicsEntity;
|
||||
MoveableEntity-->Character;
|
||||
Character-->Player;
|
||||
Character-->NPC;
|
||||
PhysicsEntity-->BoxColliderEntity;
|
||||
MoveableEntity-->Vehicle;
|
||||
BoxColliderEntity-->Vehicle;
|
||||
```
|
||||
|
||||
{{% /section %}}
|
||||
|
||||
---
|
||||
|
||||
<section data-noprocess>
|
||||
<h1>Godot</h1>
|
||||
<div style="display: flex; flex-direction: row; justify-content: center; align-items: center;">
|
||||
<img style="margin-right: 10%;" src="Godot_player_scene_nodes.webp">
|
||||
<ul>
|
||||
<li class="fragment" >uses hierarchy instead</li>
|
||||
<li class="fragment" >child nodes as "components"</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
---
|
||||
|
||||
## What are components?
|
||||
- {{< frag c="Split entities from behaviour" >}}
|
||||
- {{< frag c="Data associated with a certain \"behaviour\"" >}}
|
||||
|
||||
---
|
||||
|
||||
# COMPOSITION
|
||||
|
||||
---
|
||||
|
||||
# Composition
|
||||
```mermaid
|
||||
graph LR;
|
||||
EntityA-->BoxColliderComponent;
|
||||
EntityA-->StaticMeshComponent;
|
||||
EntityB-->SphereColliderComponent;
|
||||
EntityB-->DynamicMeshComponent;
|
||||
EntityB-->PlayerControllerComponent;
|
||||
linkStyle default stroke:lime,stroke-width:4px;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Composition
|
||||
- {{< frag c="Entities have minimal data and behaviour" >}}
|
||||
- {{< frag c="Entities hold their components or references to them" >}}
|
||||
|
||||
{{% fragment %}}
|
||||
```cpp
|
||||
class Component;
|
||||
|
||||
class Entity {
|
||||
//...
|
||||
private:
|
||||
std::unordered_map<std::type_info, Component*> m_components;
|
||||
}
|
||||
```
|
||||
{{% /fragment %}}
|
||||
|
||||
{{% note %}}
|
||||
|
||||
Wanted to have a look at Unreal Source code, but...
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Unreal
|
||||
|
||||
Code in Unreal's AActor class[^5]:
|
||||
|
||||
```cpp
|
||||
/**
|
||||
* All ActorComponents owned by this Actor. Stored as a Set as actors may have a large number of components
|
||||
* @see GetComponents()
|
||||
*/
|
||||
TSet<TObjectPtr<UActorComponent>> OwnedComponents;
|
||||
|
||||
/**
|
||||
* Get all components derived from class 'ComponentType' and fill in the OutComponents array with the result.
|
||||
* It's recommended to use TArrays with a TInlineAllocator to potentially avoid memory allocation costs.
|
||||
* TInlineComponentArray is defined to make this easier, for example:
|
||||
* {
|
||||
* TInlineComponentArray<UPrimitiveComponent*> PrimComponents(Actor);
|
||||
* }
|
||||
*
|
||||
* @param bIncludeFromChildActors If true then recurse in to ChildActor components and find components of the appropriate type in those Actors as well
|
||||
*/
|
||||
template<class ComponentType, class AllocatorType>
|
||||
void GetComponents(TArray<ComponentType, AllocatorType>& OutComponents, bool bIncludeFromChildActors = false) const
|
||||
{
|
||||
typedef TPointedToType<ComponentType> T;
|
||||
|
||||
OutComponents.Reset();
|
||||
ForEachComponent_Internal<T>(T::StaticClass(), bIncludeFromChildActors, [&](T* InComp)
|
||||
{
|
||||
OutComponents.Add(InComp);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
[^5]: Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h
|
||||
|
||||
{{% note %}}
|
||||
|
||||
next, Unity, but...
|
||||
|
||||
*b. Distributing Examples
|
||||
You may Distribute Examples (including as modified by you) in Source Code or object code to any third party.*
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Unity
|
||||
[^6]
|
||||
|
||||
[^6]:https://docs.unity3d.com/6000.0/Documentation/Manual/UsingTheInspector.html
|
||||
|
||||
{{% note %}}
|
||||
|
||||
- can't confirm what Unity uses (no source found)
|
||||
- interface suggests composition
|
||||
- Unity DOTS?
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## What are systems?
|
||||
- {{< frag c="███████████████████" >}}
|
||||
- {{< frag c="█████████████████" >}}
|
||||
- {{< frag c="████████████████████" >}}
|
||||
|
||||
{{% note %}}
|
||||
We'll talk about it later.
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
# Entity Component System
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
{{% note %}}
|
||||
|
||||
ECS is Data-Oriented rather than Object-Oriented
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
## Entity Component System
|
||||
- {{< frag c="split components even more from entities" >}}
|
||||
- {{< frag c="entities are minimal data" >}}
|
||||
- {{< frag c="components store data associated with certain behaviours" >}}
|
||||
- {{< frag c="components aren't managed by their entities" >}}
|
||||
|
||||
{{% note %}}
|
||||
|
||||
-
|
||||
- entities can just be ids
|
||||
- component manager
|
||||
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## What are systems?
|
||||
- {{< frag c="main way of interacting with components" >}}
|
||||
- {{< frag c="loop over every component of a type" >}}
|
||||
- {{< frag c="e.g. Rendering System, Physics System..." >}}
|
||||
|
||||
{{% note %}}
|
||||
|
||||
- due to systems, want to optimise for iterating over components of a type
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
## Examples:
|
||||
|
||||
- [Unity DOTS](https://unity.com/dots)
|
||||
- [Bevy](https://bevyengine.org/)
|
||||
- [EnTT](https://github.com/skypjack/entt)
|
||||
|
||||
{{% fragment %}}
|
||||
|
||||
> One thing known to most is that *EnTT* is also used in Minecraft.
|
||||
> Given that the game is available literally everywhere, I can confidently say that the library has been sufficiently tested on every platform that can come to mind.
|
||||
|
||||
{{% /fragment %}}
|
||||
|
||||
{{% note %}}
|
||||
|
||||
Bevy ECS used for [Tiny Glade](https://store.steampowered.com/app/2198150/Tiny_Glade/)
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
## Cache
|
||||
|
||||
CPU |L1 |L2 |L3
|
||||
-------------|-------|-------|-----
|
||||
Pentium N4200|96 KiB |128 KiB|2 MiB
|
||||
i7 14700HX |1800 KB|28 MB |33 MB
|
||||
|
||||
{{% note %}}
|
||||
|
||||
top: silas' laptop
|
||||
bottom: mine
|
||||
|
||||
Mine are probably also KiB/MiB, because Windows is doing Windows things
|
||||
|
||||
Cache Locality less important with newer cpus, but will probably still lead to benefits.
|
||||
Storing data contigous should reduce cache misses, since accesses are more predictable.
|
||||
Collider Component may have 3\*float64 position + 4\*float64 rotation + 3\*float64 size + 10\*float64 miscellanious = 160 Byte
|
||||
300 of those = 48 KB
|
||||
500 of those = 80 KB
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
## How to implement it in C++
|
||||
### Entities:
|
||||
```cpp
|
||||
//one possibility
|
||||
typedef uint_32t UID;
|
||||
|
||||
typedef UID Entity;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## How to implement it in C++
|
||||
### Components:
|
||||
A [std::flat_map](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p0429r9.pdf) is a fitting datatype.
|
||||
|
||||
{{% fragment %}}
|
||||
|
||||
GCC libstdc++ | Clang libc++ | MSVC STL
|
||||
---------------|---------------------|---------------
|
||||
not implemented|partially implemented|not implemented
|
||||
|
||||
{{% /fragment %}}
|
||||
|
||||
[^7]
|
||||
[^7]: https://en.cppreference.com/w/cpp/compiler\_support/23
|
||||
|
||||
---
|
||||
|
||||
## How to implement it in C++
|
||||
### Components:
|
||||
|
||||
```cpp
|
||||
class ComponentManager{
|
||||
template<typename comp_type> requires std::is_base_of<Component, comp_type>
|
||||
foreachComponent(std::function func){
|
||||
//...
|
||||
}
|
||||
|
||||
template<typename comp_type> requires std::is_base_of<Component, comp_type>
|
||||
addComponentToEntity(Entity entity){
|
||||
//...
|
||||
}
|
||||
|
||||
//some type of ComponentMap store
|
||||
}
|
||||
```
|
||||
|
||||
{{% note %}}
|
||||
|
||||
possible ComponentMap store:
|
||||
```cpp
|
||||
std::unordered_map<std::typeid, std::size_t> m_typeOffsetMap;
|
||||
void* m_componentMaps;
|
||||
```
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
## How to implement it in C++
|
||||
### ComponentMap:
|
||||
|
||||
```cpp
|
||||
template <typename component_type>
|
||||
class ComponentMap
|
||||
std::vector<component_type> m_values;
|
||||
std::unordered_map<Entity, size_type> m_mapping;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Links
|
||||
- Images from [deathgenerator.com](https://deathgenerator.com)
|
||||
- Helpful [thesis by Toni Härkönen](https://trepo.tuni.fi/bitstream/handle/123456789/27593/H%C3%A4rk%C3%B6nen.pdf)
|
||||
- [Data Structures for Entity Systems: Contiguous memory](https://t-machine.org/index.php/2014/03/08/data-structures-for-entity-systems-contiguous-memory/)
|
||||
|
||||
520
OpenColloq/WS24_EntityComponentSystem/content/_index.md~
Normal file
|
|
@ -0,0 +1,520 @@
|
|||
+++
|
||||
title = "Entity Component System - It's not a system"
|
||||
outputs = ["Reveal"]
|
||||
+++
|
||||
|
||||
# Entity Component System
|
||||
|
||||
---
|
||||
|
||||
## Why am I doing this?
|
||||
|
||||
- {{< frag c ="My own bad implementation" >}}
|
||||
{{% fragment %}}
|
||||
 {{% /fragment %}}
|
||||
|
||||
{{% note %}}
|
||||
My implementation in GL3 (explain course shortly) was horrible.
|
||||
ECS was introduced in the middle of GL3.
|
||||
|
||||
Tino said I could talk about very niche topics, so I'm talking about a very niche topic.
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
## What is (an) ECS?
|
||||
- {{< frag c="unnecessary" >}}
|
||||
- {{< frag c="useful" >}}
|
||||
- {{< frag c="not a system" >}}
|
||||
|
||||
{{% note %}}
|
||||
|
||||
Talk about structure of presentation here:
|
||||
- define terms like "entity", "component", "system"
|
||||
- go over other approaches to "motivate" ECS
|
||||
- main 3 game engines will be mentioned (Unity, Unreal, Godot)
|
||||
- talking about the level of programming engines, not games
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
## What are entities?
|
||||
[^1]
|
||||
|
||||
[^1]: https://br.ign.com/league-of-legends-wild-rift/89123/feature/wild-rift-tudo-sobre-o-lol-mobile ; Image: Riot Games
|
||||
|
||||
---
|
||||
|
||||
## What are entities?
|
||||
[^2]
|
||||
|
||||
[^2]: https://pressakey.com/gameinfos,4981,screenshots,,,Age-of-Empires-Definitive-Edition,.html
|
||||
|
||||
---
|
||||
|
||||
## What are entities?
|
||||
- Objects in a game (or simulation)
|
||||
- Can have different behaviours
|
||||
- {{< frag c="Basically everything" >}}
|
||||
|
||||
---
|
||||
|
||||
# INHERITANCE
|
||||
|
||||
---
|
||||
|
||||
{{% section %}}
|
||||
|
||||
{{< slide transition="none" >}}
|
||||
|
||||
## Inheritance
|
||||
```mermaid
|
||||
graph TD;
|
||||
Entity-->MoveableEntity;
|
||||
Entity-->PhysicsEntity;
|
||||
```
|
||||
|
||||
{{% note %}}
|
||||
|
||||
Entity: Basic information like transform and mesh in our example
|
||||
MoveableEntity: Entity with functions to move with and support animations
|
||||
PhysicsEntity: Walls, Falling Boulders and stuff; Colliders and Gravity
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
{{< slide transition="none" >}}
|
||||
|
||||
## Inheritance
|
||||
```mermaid
|
||||
graph TD;
|
||||
Entity-->MoveableEntity;
|
||||
Entity-->PhysicsEntity;
|
||||
MoveableEntity-->Character;
|
||||
PhysicsEntity-->BoxColliderEntity;
|
||||
```
|
||||
|
||||
{{% note %}}
|
||||
|
||||
Entity: Basic information like transform and mesh in our example
|
||||
MoveableEntity: Entity with functions to move with and support animations
|
||||
PhysicsEntity: Walls, Falling Boulders and stuff; Colliders and Gravity
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
{{< slide transition="none" >}}
|
||||
|
||||
## Inheritance
|
||||
```mermaid
|
||||
graph TD;
|
||||
Entity-->MoveableEntity;
|
||||
Entity-->PhysicsEntity;
|
||||
MoveableEntity-->Character;
|
||||
Character-->Player;
|
||||
Character-->NPC;
|
||||
PhysicsEntity-->BoxColliderEntity;
|
||||
```
|
||||
|
||||
{{% note %}}
|
||||
|
||||
Entity: Basic information like transform and mesh in our example
|
||||
MoveableEntity: Entity with functions to move with and support animations
|
||||
PhysicsEntity: Walls, Falling Boulders and stuff; Colliders and Gravity
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
{{% /section %}}
|
||||
|
||||
---
|
||||
|
||||
## Godot
|
||||

|
||||
[^3]
|
||||
|
||||
[^3]: Screenshot: Godot Engine
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Godot Code
|
||||
```cpp
|
||||
class Node2D : public CanvasItem {
|
||||
...
|
||||
}
|
||||
.
|
||||
.
|
||||
.
|
||||
class PhysicsBody2D : public CollisionObject2D {
|
||||
...
|
||||
}
|
||||
class CharacterBody2D : public PhysicsBody2D {
|
||||
...
|
||||
}
|
||||
```
|
||||
[^4]
|
||||
|
||||
[^4]: https://github.com/godotengine/godot
|
||||
|
||||
---
|
||||
|
||||
{{% section %}}
|
||||
{{< slide transition="none" >}}
|
||||
|
||||
## Inheritance
|
||||
```mermaid
|
||||
graph TD;
|
||||
Entity-->MoveableEntity;
|
||||
Entity-->PhysicsEntity;
|
||||
MoveableEntity-->Character;
|
||||
Character-->Player;
|
||||
Character-->NPC;
|
||||
PhysicsEntity-->BoxColliderEntity;
|
||||
MoveableEntity-->Vehicle;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
{{< slide transition="none" >}}
|
||||
|
||||
## Multiple Inheritance
|
||||
```mermaid
|
||||
graph TD;
|
||||
Entity-->MoveableEntity;
|
||||
Entity-->PhysicsEntity;
|
||||
MoveableEntity-->Character;
|
||||
Character-->Player;
|
||||
Character-->NPC;
|
||||
PhysicsEntity-->BoxColliderEntity;
|
||||
MoveableEntity-->Vehicle;
|
||||
BoxColliderEntity-->Vehicle;
|
||||
```
|
||||
|
||||
{{% /section %}}
|
||||
|
||||
---
|
||||
|
||||
<section data-noprocess>
|
||||
<h1>Godot</h1>
|
||||
<div style="display: flex; flex-direction: row; justify-content: center; align-items: center;">
|
||||
<img style="margin-right: 10%;" src="Godot_player_scene_nodes.webp">
|
||||
<ul>
|
||||
<li class="fragment" >uses hierarchy instead</li>
|
||||
<li class="fragment" >child nodes as "components"</li>
|
||||
</ul>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
---
|
||||
|
||||
## What are components?
|
||||
- {{< frag c="Split entities from behaviour" >}}
|
||||
- {{< frag c="Data associated with a certain \"behaviour\"" >}}
|
||||
|
||||
---
|
||||
|
||||
# COMPOSITION
|
||||
|
||||
---
|
||||
|
||||
# Composition
|
||||
```mermaid
|
||||
graph LR;
|
||||
EntityA-->BoxColliderComponent;
|
||||
EntityA-->StaticMeshComponent;
|
||||
EntityB-->SphereColliderComponent;
|
||||
EntityB-->DynamicMeshComponent;
|
||||
EntityB-->PlayerControllerComponent;
|
||||
linkStyle default stroke:lime,stroke-width:4px;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Composition
|
||||
- {{< frag c="Entities have minimal data and behaviour" >}}
|
||||
- {{< frag c="Entities hold their components or references to them" >}}
|
||||
|
||||
{{% fragment %}}
|
||||
```cpp
|
||||
class Component;
|
||||
|
||||
class Entity {
|
||||
//...
|
||||
private:
|
||||
std::unordered_map<std::type_info, Component*> m_components;
|
||||
}
|
||||
```
|
||||
{{% /fragment %}}
|
||||
|
||||
{{% note %}}
|
||||
|
||||
Wanted to have a look at Unreal Source code, but...
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Unreal
|
||||
|
||||
Code in Unreal's AActor class[^5]:
|
||||
|
||||
```cpp
|
||||
/**
|
||||
* All ActorComponents owned by this Actor. Stored as a Set as actors may have a large number of components
|
||||
* @see GetComponents()
|
||||
*/
|
||||
TSet<TObjectPtr<UActorComponent>> OwnedComponents;
|
||||
|
||||
/**
|
||||
* Get all components derived from class 'ComponentType' and fill in the OutComponents array with the result.
|
||||
* It's recommended to use TArrays with a TInlineAllocator to potentially avoid memory allocation costs.
|
||||
* TInlineComponentArray is defined to make this easier, for example:
|
||||
* {
|
||||
* TInlineComponentArray<UPrimitiveComponent*> PrimComponents(Actor);
|
||||
* }
|
||||
*
|
||||
* @param bIncludeFromChildActors If true then recurse in to ChildActor components and find components of the appropriate type in those Actors as well
|
||||
*/
|
||||
template<class ComponentType, class AllocatorType>
|
||||
void GetComponents(TArray<ComponentType, AllocatorType>& OutComponents, bool bIncludeFromChildActors = false) const
|
||||
{
|
||||
typedef TPointedToType<ComponentType> T;
|
||||
|
||||
OutComponents.Reset();
|
||||
ForEachComponent_Internal<T>(T::StaticClass(), bIncludeFromChildActors, [&](T* InComp)
|
||||
{
|
||||
OutComponents.Add(InComp);
|
||||
});
|
||||
}
|
||||
```
|
||||
|
||||
[^5]: Engine/Source/Runtime/Engine/Classes/GameFramework/Actor.h
|
||||
|
||||
{{% note %}}
|
||||
|
||||
next, Unity, but...
|
||||
|
||||
*b. Distributing Examples
|
||||
You may Distribute Examples (including as modified by you) in Source Code or object code to any third party.*
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Unity
|
||||
[^6]
|
||||
|
||||
[^6]:https://docs.unity3d.com/6000.0/Documentation/Manual/UsingTheInspector.html
|
||||
|
||||
{{% note %}}
|
||||
|
||||
- can't confirm what Unity uses (no source found)
|
||||
- interface suggests composition
|
||||
- Unity DOTS?
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## What are systems?
|
||||
- {{< frag c="███████████████████" >}}
|
||||
- {{< frag c="█████████████████" >}}
|
||||
- {{< frag c="████████████████████" >}}
|
||||
|
||||
{{% note %}}
|
||||
We'll talk about it later.
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
# Entity Component System
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
{{% note %}}
|
||||
|
||||
ECS is Data-Oriented rather than Object-Oriented
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
## Entity Component System
|
||||
- {{< frag c="split components even more from entities" >}}
|
||||
- {{< frag c="entities are minimal data" >}}
|
||||
- {{< frag c="components store data associated with certain behaviours" >}}
|
||||
- {{< frag c="components aren't managed by their entities" >}}
|
||||
|
||||
{{% note %}}
|
||||
|
||||
-
|
||||
- entities can just be ids
|
||||
- component manager
|
||||
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## What are systems?
|
||||
- {{< frag c="main way of interacting with components" >}}
|
||||
- {{< frag c="loop over every component of a type" >}}
|
||||
- {{< frag c="e.g. Rendering System, Physics System..." >}}
|
||||
|
||||
{{% note %}}
|
||||
|
||||
- due to systems, want to optimise for iterating over components of a type
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
## Examples:
|
||||
|
||||
- [Unity DOTS](https://unity.com/dots)
|
||||
- [Bevy](https://bevyengine.org/)
|
||||
- [EnTT](https://github.com/skypjack/entt)
|
||||
|
||||
{{% fragment %}}
|
||||
|
||||
> One thing known to most is that *EnTT* is also used in Minecraft.
|
||||
> Given that the game is available literally everywhere, I can confidently say that the library has been sufficiently tested on every platform that can come to mind.
|
||||
|
||||
{{% /fragment %}}
|
||||
|
||||
{{% note %}}
|
||||
|
||||
Bevy ECS used for [Tiny Glade](https://store.steampowered.com/app/2198150/Tiny_Glade/)
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
## Cache
|
||||
|
||||
CPU |L1 |L2 |L3
|
||||
-------------|-------|-------|-----
|
||||
Pentium N4200|96 KiB |128 KiB|2 MiB
|
||||
i7 14700HX |1800 KB|28 MB |33 MB
|
||||
|
||||
{{% note %}}
|
||||
|
||||
top: silas' laptop
|
||||
bottom: mine
|
||||
|
||||
Mine are probably also KiB/MiB, because Windows is doing Windows things
|
||||
|
||||
Cache Locality less important with newer cpus, but will probably still lead to benefits.
|
||||
Storing data contigous should reduce cache misses, since accesses are more predictable.
|
||||
Collider Component may have 3\*float64 position + 4\*float64 rotation + 3\*float64 size + 10\*float64 miscellanious = 160 Byte
|
||||
300 of those = 48 KB
|
||||
500 of those = 80 KB
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
## How to implement it in C++
|
||||
### Entities:
|
||||
```cpp
|
||||
//one possibility
|
||||
typedef uint_32t UID;
|
||||
|
||||
typedef UID Entity;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## How to implement it in C++
|
||||
### Components:
|
||||
A [std::flat_map](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2022/p0429r9.pdf) is a fitting datatype.
|
||||
|
||||
{{% fragment %}}
|
||||
|
||||
GCC libstdc++ | Clang libc++ | MSVC STL
|
||||
---------------|---------------------|---------------
|
||||
not implemented|partially implemented|not implemented
|
||||
|
||||
{{% /fragment %}}
|
||||
|
||||
[^7]
|
||||
[^7]: https://en.cppreference.com/w/cpp/compiler\_support/23
|
||||
|
||||
---
|
||||
|
||||
## How to implement it in C++
|
||||
### Components:
|
||||
|
||||
```cpp
|
||||
class ComponentManager{
|
||||
template<typename comp_type> requires std::is_base_of<Component, comp_type>
|
||||
foreachComponent(std::function func){
|
||||
//...
|
||||
}
|
||||
|
||||
template<typename comp_type> requires std::is_base_of<Component, comp_type>
|
||||
addComponentToEntity(Entity entity){
|
||||
//...
|
||||
}
|
||||
|
||||
//some type of ComponentMap store
|
||||
}
|
||||
```
|
||||
|
||||
{{% note %}}
|
||||
|
||||
possible ComponentMap store:
|
||||
```cpp
|
||||
std::unordered_map<std::typeid, std::size_t> m_typeOffsetMap;
|
||||
void* m_componentMaps;
|
||||
```
|
||||
|
||||
{{% /note %}}
|
||||
|
||||
---
|
||||
|
||||
## How to implement it in C++
|
||||
### ComponentMap:
|
||||
|
||||
```cpp
|
||||
template <typename component_type>
|
||||
class ComponentMap
|
||||
std::vector<component_type> m_values;
|
||||
std::unordered_map<Entity, size_type> m_mapping;
|
||||
```
|
||||
|
||||
---
|
||||
|
||||

|
||||
|
||||
---
|
||||
|
||||
## Links
|
||||
- Images from [deathgenerator.com](https://deathgenerator.com)
|
||||
- Helpful [thesis by Toni Härkönen](https://trepo.tuni.fi/bitstream/handle/123456789/27593/H%C3%A4rk%C3%B6nen.pdf)
|
||||
- [Data Structures for Entity Systems: Contiguous memory](https://t-machine.org/index.php/2014/03/08/data-structures-for-entity-systems-contiguous-memory/)
|
||||
|
||||
BIN
OpenColloq/WS24_EntityComponentSystem/content/aoe.jpg
Normal file
|
After Width: | Height: | Size: 3 MiB |
BIN
OpenColloq/WS24_EntityComponentSystem/content/dracula_ecs.png
Normal file
|
After Width: | Height: | Size: 51 KiB |
|
After Width: | Height: | Size: 19 KiB |
|
After Width: | Height: | Size: 20 KiB |
BIN
OpenColloq/WS24_EntityComponentSystem/content/godot_news.png
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
OpenColloq/WS24_EntityComponentSystem/content/lol.jpg
Normal file
|
After Width: | Height: | Size: 221 KiB |
|
After Width: | Height: | Size: 11 KiB |
BIN
OpenColloq/WS24_EntityComponentSystem/content/metroid_ending.gif
Normal file
|
After Width: | Height: | Size: 78 KiB |
|
After Width: | Height: | Size: 117 KiB |
|
After Width: | Height: | Size: 16 KiB |
|
After Width: | Height: | Size: 24 KiB |
|
After Width: | Height: | Size: 24 KiB |