Showing posts with label ecs. Show all posts
Showing posts with label ecs. Show all posts

2018-06-01

Hybrid ECS in Unity

Previously we tried the Pure ECS to create a Pong animation, this article will show example snippet of how to use Hybrid ECS. With hybrid ECS we can use normal game object to act as the entity. What you need to do is:
  • create a prefab, 
  • drag-and-drop your custom Component script (MonoBehavior, not a struct that inherited from IComponentData, so must be exactly one class per file) to the prefab, 
  • then add the GameObjectEntity script to the prefab. 
  • Next, you can instantiate the prefab as usual. 
  • Use a class inherited from ComponentSystem to manipulate the values of those components.
To create a System that uses those GameObjectEntity, you can use injected property or method:

class SomeSystem1 : ComponentSystem {
  ComponentGroup group;
  protected override void OnUpdate() {
    if(group == null || group.CalculateLength() < 1) {
      group = GetComponentGroup(typeof(Direction2D), typeof(Coord2D), typeof(Health)); // must be cached as data member    }
    var dirs = group.GetComponentArray<Coord2D>(); 
    // do something with it, 
    // note that if you want to use Job/Schedule, 
    // you must use [Inject]
  }
}

class SomeSystem2 : ComponentSystem {
  struct Data {

    public GameObjectArray gameObjects;
    public ComponentArray<Position2D> Positions; 
    public ComponentArray<Heading2D> Headings;
    public ComponentArray<Health> Healths;
  }
  [Inject] Data data;
  protected override void OnUpdate() {
    // do something with data.*
    // inherit from JobComponentSystem 
    // if you want to use Job/Schedule
    // also read this
  }
}

One of the biggest benefit of using Hybrid ECS than Pure ECS is that you don't have to wait/implement missing component/system (Animation for example) that not yet implemented by Unity to make stuff works correctly.

This is the example the difference between creating hybrid ECS way and standard/normal way (btw this is not using a correct composition of component, just minimal conversion between those two):


Difference between prefab in Hybrid ECS way and in normal way:


Example code for the system:


For more info, see this slide Unity ECS Intro

Update 2019-05-07: see this video for better understanding how to use DOTS (the ECS new name on unity 2019)

2018-05-10

Rendering Sprite using ECS and JobSystem in Unity

Old style Unity programming, known for slow performance when number of GameObjects grows, that can be solved by managing the update call ourself. Object pooling known to be used to minimize GC overhead (that can cause stutter). ECS (Entity Component System), is a architectural pattern, known best for simplifying a complex system, that popularized and mostly used in Games. In ECS, composition are preferred than inheritance (like Golang :3 yay).
  • Component is a structure that consist of one or more computable element, for example: Position, Sprite, Velocity, Input, AI, etc. 
  • Entity is collection of Components, for example: 
    • Player (consist of Position, Velocity, Sprite, Input), 
    • Enemy (consist of Position, Velocity, Sprite, AI), 
    • Tree/Pillar (consist of Position, Sprite), etc.
  • System is a function that process components in a batch, for example: 
    • Movement (uses Position, Velocity),
    • Render (uses Position, Sprite),
    • PlayerControl (uses Player.Velocity, Input)
    • Bot (uses Enemy.Velocity, Player.Position)
In Unity, the latest stable version (2018.1.0, 2018-05-02) at the time of this article written have built in support for ECS. The benefit of using built-in ECS is the new Job System (utilizing multi-core and cache-friendly, automatic scheduling, prevent race condition) and Burst Compiler that able to utilize SIMD. There's another alternative for ECS that known long time ago if you don't want to use Unity's, such as Entitas framework (which has best documentation among others), Artemis (C# version), Leopotam, and EgoECS.

To use the Unity ECS, there's two method that can be used:
  • Hybrid, to create hybrid ECS, all you need to do is add an EntityGameObject script on the prefab.
  • Pure, you must create an entity manually.
To start any type of ECS project, all you must do is edit Packages/manifest.json, update to something like this:

{
    "dependencies": {
        "com.unity.incrementalcompiler": "0.0.38", 
        "com.unity.entities": "0.0.12-preview.1"
    }, 
    "registry": "https://staging-packages.unity.com", 
    "testables": [
        "com.unity.collections", 
        "com.unity.entities", 
        "com.unity.jobs"
    ]
}

Then you must go to Edit > Project Settings > Player, Other Settings, Scripting Runtime Version to 4.x. Also it's better to use il2cpp than Mono for the scripting backend.
To start a pure ECS, first you must decompose all Component to structs, for example:


Then start create the bootstrap code (one that spawns the entity):


Then create a system to manipulate the values:


Add the GameBootstrap to the main camera or the canvas (don't forget to add the canvas). Set these values on your Unity:
  • Main camera > projection to "perspective"
  • Canvas 
    • Canvas Scaler reference resolution to 800 x 600 (or whatever you like)
    • Screen match ratio to 0.5
    • X rotation to 90, render mode to "screen space - camera"
    • Drag your main camera to the "Render Camera"
  • Create a directory "Resources/" inside "Assets/" and add a ball.png image with transparency, in my case I used 600x600 image.
  • Install or git clone SpriteInstanceRenderer component to render the sprite using ECS. This component requires TransformMatrix, Heading2D and Position/Position2D component to render the sprite.
That's it, now you have created a simple pong animation with ECS, it would show something like this (I add a text on each corner to make sure the coordinate system is right):



To debug the entities, since it would not shown on the Hierarchy panel, click the Window > Entity Debugger. It would show something like this:


When you click one of the entity, you watch the current component values on Inspector panel, like this:


An the core utilization on the profiler: