WDTUTORIALS
menu
Django - The Easy Way Django - The Easy Way
Samuli Natri 2018.06.02
Entrepreneur. Software developer since the 90's. He attended Helsinki University Of Technology (Computer Science) and Helsinki University (Social Sciences).

Unity - ECS Tutorial - Move A Cube (and Quad)

How to instantiate and move a cube (and quad) using a prototype object.

In the Previous Tutorial we subclassed MonoBehaviour and attached the Bootstrap.cs script to the Bootstrap GameObject. This time we will not attach the Bootstrap.cs script to any object. Instead we create a helper gameobject PlayerProtoType and use its Mesh Instance Render Component to give a look to our Player Entity.

Create A New Project

1) See Unity ECS & Job System - Create A New Project  on how to create a new project.

Create A PlayerProtoType GameObject

1) Create an empty object and call it PlayerProtoType:

2) Add a Mesh Instance Renderer Component to it:

Create A Custom Material

1) Create a new material in the Assets folder (right-click the Assets folder) and call it PlayerMaterial:

2) Choose a color for the PlayerMaterial:

3) Select Enable GPU Instancing for the PlayerMaterial:

4) Select the PlayerProtoType GameObject and set Mesh as Cube and drag the PlayerMaterial to the Material slot:

Create A Bootstrap Script

1) Right-click the Assets folder and create a C# script called Bootstrap.cs:

2) Double-click the Bootstrap.cs file in the Assets window to open it and put these lines in it:

using Unity.Entities;
using Unity.Rendering;
using Unity.Transforms;
using UnityEngine;

// We don't use MonoBehaviour here because we are not attaching this script to any object.
public class Bootstrap
{
	// But because we are not using MonoBehaviour and attaching it to anything, 
	// we can't use the Start() method and except it to run automatically.
	// Instead we add the RuntimeInitializeOnLoadMethod attribute to run the method.
	// Use any method name and make it static.
	[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
	public static void Init()
	{
		// Find a gameobject called "PlayerProtoType".
		var prototype = GameObject.Find("PlayerProtoType");
		// Grap its MeshInstanceRendererComponent for the Mesh and Material
		var playerLook = prototype.GetComponent<MeshInstanceRendererComponent>().Value;
		// We don't need the prototype anymore, so we delete it:
		Object.Destroy(prototype);

		// Manage entities and components with the EntityManager.
		// With its API you can for example create entities and add components.
		var entityManager = World.Active.GetOrCreateManager<EntityManager>();
        
		// EntityArchetype describes a set of components.
		// It's like a template (or prefab) that we can use when we instantiate entities.
		// You can think an entity as a collection of components.
		// All components listed below are provided by default and we are not creating custom
		// components in this tutorial.
		// You need to add at least these 3 for our example to work.
		var playerArchetype = entityManager.CreateArchetype(
			typeof(TransformMatrix),
			typeof(Position),
			typeof(MeshInstanceRenderer)
		);
        
		// Here we instantiate the player entity and use the playerArchetype
		// to add TransformMatrix, Position and MeshInstanceRenderer components to it.
		var player = entityManager.CreateEntity(playerArchetype);
		
		// And finally we add the playerLook we grabbed from the PlayerProtoType GameObject
		// to the player entity.
		entityManager.SetSharedComponentData(player, playerLook);
			
	}

}

3) Hit Cmd+P to Run the program and you should see a Cube:

Move The Cube

1) Add PlayerMovementSystem.cs to the Assets folder:

2) Fill it with this code:

using UnityEngine;
using Unity.Entities;
using Unity.Mathematics;
using Unity.Transforms;

public class PlayerMovementSystem : ComponentSystem
{
	// First we create a ComponentGroup.
	// This PlayerGroup struct defines that we want to gather together
	// all entities that has the Position component.
	// In our case we just have one entity, the Player entity.
	public struct PlayerGroup
	{
		// With ComponentDataArray we can access the position data for each entity.
		public ComponentDataArray<Position> PlayerPosition;
		// Length is the number of entities that we can use for the loop below.
		public int Length;
	}

	// Here we create the ComponentGroup _player that we can use to access the player positions.
	[Inject] PlayerGroup _player;
	
	// If we would have multiple players, we could access
	// the position of the FIRST player like this:
	// _player.PlayerPosition[0]
	// and the position of the SECOND player like this:
	// _player.PlayerPosition[1]
		
	// A variable to manipulate movement speed.
	private float speed = 5;

	protected override void OnUpdate()
	{
		// We use deltatime to make the movement independent of the framerate.
		// This means that now we move x 'units' per SECOND, not x 'units' per frame. 
		float dt = Time.deltaTime;

		// Loop through the _player ComponentGroup.
		for (int i = 0; i < _player.Length; i++)
		{
			// Grap the position by using the i as [index].
			var pos = _player.PlayerPosition[i];

			// Create a new position by reading the user input.
			pos.Value += new float3(
				Input.GetAxis("Horizontal") * speed * dt,
				0,
				Input.GetAxis("Vertical") * speed * dt
			);

			// Update the player position with the new position.
			_player.PlayerPosition[i] = pos;
		}
	}
}

3) Now you should be able to move the cube with arrow keys:

2D Movement With Quad

1) Change the PlayerProtoType Mesh to Quad:

2) Change the OnUpdate method in PlayerMovementSystem.cs:

  pos.Value += new float3(
                Input.GetAxis("Horizontal") * speed * dt,
                Input.GetAxis("Vertical") * speed * dt,
                0
            );

3) Select the Main Camera GameObject and change Skybox to Solid Color:

4) Now you should be able to move the quad in 2d with arrow keys:

Summary

- PlayerProtoType GameObject is just used to provide a look (mesh + material) for the player.

- Bootstrap.cs instantiates the player entity. Entity is just an ID. It doesn't have any logic or data. The movement logic is in the PlayerMovementSystem.cs. The data (user position) is in the Position component.

- PlayerMovementSystem.cs reads the user input ja updates the player entity Position component. This makes the player move.