Create a Unity ECS Project
Full workflows and code to set up an ECS project with the latest Unity Editor and compatible package versions
Last updated
Full workflows and code to set up an ECS project with the latest Unity Editor and compatible package versions
Last updated
Basic game settings will be configured in a GameObject in a Sub Scene and can be viewed in the "Entity Inspector" at runtime.
Github branch link: https://github.com/moetsi/Unity-DOTS-Multiplayer-XR-Sample/tree/Setting-up-a-project-for-ECS
Install Unity Hub 3.1.2 if you do not have it already
Install Unity 2020 LTS if you do not have it already
Go to "Installs" on the left side of Unity Hub pop-up window
Click "Add" and choose 2020 LTS
Once 2020 LTS is downloaded, click on the three vertical dots menu (kebab menu) in the top right corner to add platform modules depending on your development and target platforms (OSX/Linux/Windows)
Include iOS Build Support if you plan on completing the AR Foundation section of this gitbook
Go to "Projects" in Unity Hub and click "New" in the top left corner of the window and select 2020 LTS and create a new 3D project, "Asteroids 3D XR Multiplayer"
Note For those on a Fedora system (does not apply to Mac or Windows)
Upon installing the burst compiler you might get a cascading error that began with blah blah... DllNotFoundException: libdl.so ...blah blah
/usr/lib64/libdl.so.2
and creating a symlink ln -s libdl.so.2 libdl.so
solved the error
Editor needs a restart after adding the symlink
Once you're in Unity, navigate to Package Manager from "Window"
Within PackageManager find the little "gear" icon and select Advanced Project Settings
Check the box next to Enable Preview Packages and also Show Dependencies at the bottom of the window
This will allow you to view the preview packages that are included included in the package manifest
Outside of the Unity Editor, navigate to your project folder (wherever you saved it locally) and open manifest.json (inside the Packages folder) with Visual Studio code or your choice of editor
These are all the packages that are currently included in your project
We are now going to manually add a new package, the Hybrid Rendering package
Add the following line to the manifest somewhere between the curly braces and save:
When you click back into the Editor, Unity will notice the updated manifest and "pull" down the hybrid renderer package we added (you'll see the "Importing" window pop-up with a loading bar)
If interested, read up to the "Hybrid Renderer" section in this blog post to learn what makes the Hybrid Renderer "hybrid"
Read the whole blog post if you want to be an ECS master, it is a great post!
Hybrid Renderer automatically pulls in ECS dependencies (everything you need for ECS)
You can see the dependencies of the package if you navigate back to the PackageManager in the Editor and select the Hybrid Renderer
A key dependency is Entities, which brings in even more additional dependencies
Entities v0.50.1-preview.2
Burst v1.6.4
Properties v1.7.0-preview
Properties UI v1.7.0-preview
Serialization v1.7.0-preview.1
Collections v1.2.3
Mathematics v1.2.5
Asset Bundle v1.0.0
Unity Web Request v2.3.1-preview
Performance testing API v2.3.1-preview
Mono Cecil v1.10.1
Jobs v0.50.0-preview.9
Scriptable Build Pipeline v1.19.2
Platform v0.50.0-preview.4
Roslyn Compiler for Unity v0.2.1-preview
Unity Profiling Core API v1.0.0
Adding certain packages directly from the Package Manager window is no longer possible (explanation in this post)
For the duration of this gitbook, we will almost exclusively be adding packages through the manifest
Now we will add support for Universal Render Pipeline
This error is what happens if you do not add the Universal Render Pipeline (URP)
We could have also chosen to add High Definition Render Pipeline (HDRP), but we want to support mobile devices
More discussion on difference between URP vs. HDRP can be found here
Add the following line to the manifest somewhere between the curly braces and save
We now have an ECS project set up
created a new project
added hybrid renderer to the manifest
added universal render pipeline support
Unity has no plans to sunset GameObject/MonoBehaviour functionality given how incredibly powerful and mature their workflows are. That's why Unity built tools and workflows for developers to support GameObject workflows while also utilizing DOTS (a sorta 2-in-1, you can use both!).
One such workflow is the use of "Sub Scenes." Unity gives you the ability to split your scene into several Sub Scenes, which you use to partition various GameObjects and Entities. When a Sub Scene window is open (a.k.a. 'editable'), it operates in "GameObject world." When a Sub Scene window is closed, it operates in "Entity-performant world" (so to speak).
How is this helpful? Here's an example: Visual artists can build GameObject assets in Sub Scenes, as long as they have the Sub Scene window open in Editor. When done editing, the visual artist closes the Sub Scene window, which triggers the conversion of these GameObjects into Entities. The Entities can be streamed in and out as needed. The conversion-to-entities allows for enormous environments (as demo'd in the Megacity walkthrough below). If all those entities had been game objects, it would absolutely destroy the performance of a normal authoring scene.
This is how it works: This conversion of GameObjects into Entities within a Sub Scene takes place either when (1) you hit Play in Editor while the Sub Scene is open at the time, or when (2) you close the Sub Scene from its Inspector.
The conversion process itself shouldn't take long at all, even for massive scale environments like the Megacity demo.
External resources, if interested:
Unity's Megacity walkthrough: https://www.youtube.com/watch?v=j4rWfPyf-hk Watch this if you want a general understanding of the benefits of Sub Scenes.
Unity's post about Sub Scene conversion workflows: https://forum.unity.com/threads/new-subscene-converttoentity-workflows.638785/ Read this if you want to be up to speed with the latest and greatest updates.
Procedural generation of Sub Scenes: https://forum.unity.com/threads/generate-sub-scenes-programmatically.868984/#post-6598072 Read this if you are hardcore.
Right click on the Hierarchy window and choose "New Sub Scene" > "Empty Scene"
Name this Scene "ConvertedSubScene"
This will automatically create a new folder with the parent scene name
This will also automatically create a new folder called "SceneDependencyCache" which is used by Unity to help load/unload Sub Scenes
Select "ConvertedSubScene" in Hierarchy
Check out the settings in the Inspector
"Auto Load Scene" is selected true by default, which means this Sub Scene will automatically load its Entities when the scene is loaded
Double click on "ConvertedSubScene" in Assets/Scenes/SampleScene and hit the play button
Notice there are no cameras in the Sub Scene so nothing renders
Return to "SampleScene" in Assets/Scenes and hit the play button
Notice that the skybox renders because a camera is present
You can see how Unity is able to handle both GameObjects and Entities at runtime without adding a single Entity, Component, or System. The GameObject camera functions as expected even with a Sub Scene loaded into the scene.
Unity has release DOTS-specific Editor windows to help developers manage their DOTS projects. The windows available can be found in "Window" > "DOTS".
Let's combine all these views into a single view that has tabs for DOTS Hierarchy, Systems, Components, and Archetypes
We will use these windows to see:
Entities (hexagon icon)
Components (puzzle piece icon)
Systems (hexagon with arrows icon)
As well as "Archetypes" (types of entities) (hexagon with interior edges icon)
If you are confused by Worlds and Systems read the section on "System organization" at the bottom of the link here.
Let's checkout the amount of entities we currently have in our project by navigating to DOTS Hierarchy by clicking on the DOTS Hierarchy tab
You should see 3 entities (while the Sub Scene is "open")
Now let's close the Sub Scene by hitting the "close" button in the inspector when the ConvertedSubScene is selected in the Hierarchy
You Should now see 5 entities
Click through the 5 entities and notice how their components and values are shown in the Editor Inspector window
Think of the current 5 entities as autogenerated Unity.Entities "boiler plate" for our current scene / SubScene setup
We now are able to navigate Entities, Systems, Archetypes and see their associated data in the Inspector.
We now have a Sub Scene loading into our scene
We created a Sub Scene "ConvertedSubScene" in the Hierarchy
Created a "DOTS Window" containing the new DOTS Editor Views
Saw how the number of entities changes when a Sub Scene is open vs. closed because of the Sub Scene conversion work flow
Conversion WorkflowTo use Unity’s DOTS technology, you need to create entities, components and systems.
The generation process that consumes GameObjects (authoring data) and generates entities and components (runtime data) is called conversion.
This process is the preferred way of authoring ECS data
It is a fundamental part of DOTS, and not something temporary
Conversion is only about data, there is no conversion process for code
The overall workflow looks like this:
The Unity Editor is a user interface to work with authoring data
The conversion from authoring data to runtime data happens in the Unity Editor
The runtime (e.g. the game) should only ever have to deal with runtime data
Fundamental principlesAuthoring data and runtime data are optimized for wildly different goals.
Authoring data is optimized for flexibility
Human understandability and editability
Version control (mergeability, no duplication)
Teamwork organization
Runtime data is optimized for performance
Cache efficiency
Loading time and streaming
Distribution size
A key observation is that nothing requires a 1:1 mapping between GameObjects and entities.
A single GameObject can turn into a set of entities, e.g. procedural generation
Multiple GameObjects can be aggregated into a single entity, e.g. LOD baking
Some GameObjects might have no purpose at runtime, e.g. level editing markers
The same can be said about components. A conversion system can read from any amount of Unity components and add any amount of ECS components to any amount of entities.
Key conceptsAll those concepts get explained in further detail in the rest of this document, but it's useful to introduce some vocabulary beforehand.
Authoring scene A regular Unity scene, containing GameObjects, destined to be converted to runtime data.
Subscene A simple GameObject component that references an authoring scene and will either load the authoring scene (when the Subscene is in edit mode), or stream in the converted entity scene (when the Subscene is closed).
Entity scene The result of converting an authoring scene. Because entity scenes are the output of an asset import, they are stored in the Library folder. Entity scenes can be made of multiple sections, and each of those can be independently loaded.
LiveConversion When an authoring scene is loaded as GameObjects for editing, every change will trigger an update to the entity scene, making it look as if the entity scene was directly edited, we call this process LiveConversion.
It is worth the effort to read through the Conversion Workflow documentation and wrap your head around Authoring/Conversion as it is a key part of ECS development
Unity's Talk on conversion workflows: https://www.youtube.com/watch?v=TdlhTrq1oYk Watch this if you want a more in-depth explanation (and/or prefer videos).
Create a new folder called "Scripts and Prefabs" in the "Assets" folder within the Project window
Navigate to the "Scripts and Prefabs" folder, right click, choose "Create" > "ECS" > "Runtime Component Type", and name it "GameSettingsComponent"
This is the "Component" from Entity Component System
The Component type is an interface called IComponentData (link to Unity docs)
Copy the below code snippet into GameSettingsComponent.cs:
Make sure to first clear the file before pasting in this code snippet.
Components cannot store data pre-runtime. So, to set game settings in the Editor ("authoring"), we will need to use the conversion workflow
public float asteroidVelocity = 10f; (cannot set values in IComponentData)
Navigate to "ConvertedSubScene" and create a new Empty GameObject named "GameSettings"
This GameObject will hold a script that will allow us to "author" game settings in the Editor and have those values converted at runtime into the GameSettingsComponent
In "Scripts and Prefabs", right click, choose "Create" > "ECS" > "Authoring Component Type", and create "SetGameSettingsSystem"
"Authoring" will allow us to add data in the Editor before runtime
SetGameSettingsSystem.cs
If you ever want to set data before runtime in the Editor ("authoring") and have it exist at runtime as Component data for ECS to use, you will use a conversion workflow similar to above:
Create the IComponentData that you will need
Create an IConvertGameObjectToEntity (also an Interface, link to Unity docs) with public fields that match IComponentData
Within the IConvertGameObjectToEntity use Convert() to take the MonoBehaviour data and set it to a Component during the conversion process
On the next page we show how to use [GenerateAuthoringComponent]
to add IComponentData directly on GameObjects
Click on the "GameSettings" object in the Hierarchy, then in the Inspector click "Add Component" and select SetGameSettingsSystem to add the MonoBehaviour to the GameObject
Make sure it's added and then navigate back to "SampleScene"
Select "ConvertedSubScene" from the Hierarchy (make sure it's selected) and then click "Reimport" in Inspector
Navigate to the DOTS Hierarchy window and notice a new Entity with a GameSettingsComponent
The new Entity with a GameSettingComponent can also be seen via a new EntityArchetype
Nice! The Sub Scene has followed the Convert() process and we have added the GameSettingsComponent to the converted GameSettings GameObject
Remember, the GameSettings GameObject in our ConvertedSubScene automatically gets converted because it is a GameObject in a Sub Scene.
Our SetGameSettingsSystem set on that GameObject has "Convert()" triggered when going through the conversion workflow, which:
takes the new Entity (which used to be the GameSettings GameObject) and
adds a GameSettingsComponent to it, then:
sets the GameSettingsComponent data to the data set in the Editor
...which results in an Entity with a GameSettingsComponent. We will use this Entity in the next section.
A different way to get GameObject data into an ECS Component
In the latest ECS release GameObjectConversionSystem can also look for classic Unity components. So you can add data to a GameObject through a normal MonoBehavior component, and then "search" for that MonoBehavior component in an EntityQuery.
Here's the "hello world" of conversion systems, that does a 1:1 conversion of all authoring components of a certain type to their ECS equivalent.
In a GameObjectConversionSystem
, ForEach
will not create jobs. It runs on the main thread, without Burst, and this allows accessing classic Unity without restraint. This is also why it doesn't require a call to .Run()
or .Schedule()
.
Also note that the entity query looks for classic Unity components, in this case FooAuthoring
that derives from MonoBehaviour
. Since those are reference types, they do not require ref
or in
.
We now have "authored" data on a GameObject that's been converted to Component data on an Entity
We created GameSettingsComponent.cs as our IComponentData the ("C" in "ECS")
We created SetGameSettingsSystem.cs which uses Unity's Sub Scene Conversion Workflow
We created GameSettings GameObject in ConvertedSubScene and added SetGameSettings as a Component
We navigated to our DOTS Editor windows to see that the new Entity and its GameSettingsComponent have been added to the Entity list
Github branch link: https://github.com/moetsi/Unity-DOTS-Multiplayer-XR-Sample/tree/Setting-up-a-Project-for-ECS
git clone https://github.com/moetsi/Unity-DOTS-Multiplayer-XR-Sample/
git checkout 'Setting-up-a-Project-for-ECS'