b. GameObject setup

Basic camera script

We want the spheres to spawn all around the player, so it seems like a good time to add a camera script that lets players use their mouse to see what’s around the player. Fortunately for you, here’s a FollowPlayerCamera script we made earlier!

using Improbable;
using Improbable.Gdk.Subscriptions;
using UnityEngine;

namespace Scripts.Camera
    public class FollowPlayerCamera : MonoBehaviour
        [Require] private PositionWriter positionWriter;

        // The min/max distance from camera to the player.
        private const float MinCameraDistance = 2.0f;
        private const float MaxCameraDistance = 10.0f;
        private const float ZoomScale = 10.0f;

        // The min/max vertical angles for the camera (so you can't clip through the floor).
        private const float MinYAngle = 10.0f;
        private const float MaxYAngle = 80.0f;

        // Origin offset to make camera orbit character's head rather than their feet.
        private static readonly Vector3 TargetOffset = new Vector3(0, 1, 0);

        // Keep track of the last recorded mouse input
        private float inputX;
        private float inputY;
        private float inputDistance;

        // Cache the main camera's transform
        private Transform mainCameraTransform;

        private void OnEnable()
            inputY = 40f;
            inputDistance = 5f;

            mainCameraTransform = UnityEngine.Camera.main.transform;
            Cursor.lockState = CursorLockMode.Locked;

        private void OnDisable()
            Cursor.lockState = CursorLockMode.None;

        private void Update()

        private void UpdateCameraInput()
            var x = inputX + Input.GetAxis("Mouse X");
            var y = inputY - Input.GetAxis("Mouse Y");
            var distance = inputDistance + Input.GetAxis("Mouse ScrollWheel") * ZoomScale;

            inputX = x % 360;
            inputY = Mathf.Clamp(y, MinYAngle, MaxYAngle);
            inputDistance = Mathf.Clamp(distance, MinCameraDistance, MaxCameraDistance);

        private void UpdateCameraTransform(Vector3 targetPosition)
            var dir = new Vector3(0, 0, -inputDistance);
            var orbitRotation = Quaternion.Euler(inputY, inputX, 0);
            var position = targetPosition + TargetOffset + orbitRotation * dir;
            var rotation = Quaternion.LookRotation(targetPosition + TargetOffset - position);

            mainCameraTransform.position = position;
            mainCameraTransform.rotation = rotation;

You might notice the following strange line at the top of the script:

[Require] private PositionWriter positionWriter;

We’ll explain what this means on the next page, but all you need to know for now is that this ensures the script only runs on authoritative Player objects. This is important because when we want to ensure that when there are multiple other players in the scene, a client only follows their own player’s GameObject.

Add the FollowPlayerCamera script to the Player prefab in the Assets/Prefabs/Entities/UnityClient folder.

Relaunch spatial

Now that the snapshot has been regenerated, we need to launch a new deployment to pick up the changes to our default snapshot. Make sure you have closed any open deployments, then hit Ctrl+L on Windows or Cmd+L on Mac to launch a new local deployment.

When your local instance of SpatialOS is ready, you should see the following message in the window:

SpatialOS ready. (6.2s)
Access the Inspector at http://localhost:21000/inspector
Access the new modular Inspector at http://localhost:21000/inspector-v2

Once the deployment is ready, open the DevelopmentScene found in the Assets/Scenes/ folder and select the Play button.

You should notice that no spheres show up in-game. However, if you open the SpatialOS Inspector you can see the spheres are in fact there in the SpatialOS world.

The reason spheres don’t show up in the game is because we haven’t actually told the GDK how to represent sphere entities yet. To do this, we’re going to create a “Sphere” Prefab and reference it in the client and server Entity Representation Mappings.

How the default GameObject Creator works

The default GameObject creator is the GameObjectCreatorFromMetadata class, which instantiates the Prefab as defined in a provided EntityRepresentationMapping asset, at the location defined by the entity’s Position component.

The EntityRepresentationMapping asset describes a mapping between an entity type and a resolver. The resolver describes how a worker chooses a GameObject for the given entity type. The GDK provides two types of resolvers:

Resolver type


A basic 1-to-1 mapping of an entity type to a prefab.


A resolver which picks one of two prefabs based on the worker ID specified in the OwningWorker component provided by the Player Lifecycle module.

The example below is an EntityRepresentationMapping asset for a client-worker containing both types of resolver.

Create and map a Sphere Prefab

Stop the development scene and create a sphere Prefab inside the Assets/Prefabs/Entities directory. Because the entity type to Prefab mapping will be explicitly defined, you do not need their names to match. Nonetheless we have named everything "Sphere" for simplicity.

To make the sphere standout from the level and other players, change the material in the mesh renderer to Stripe. When you’re done, the Prefab’s preview should look something like this:

Now that we have a “Sphere” Prefab, update the ClientPrefabMapping and GamelogicPrefabMapping assets inside the Assets/Config folder.

As we want all “Sphere” entities to be represented by a “Sphere” Prefab, we can use a SimpleEntityResolver to map “Sphere” entities to the “Sphere” Prefab. With the mapping asset open, select “New Entity Type”, choose “SimpleEntityResolver” from the selection and fill in the required details.

Once you’re done with both assets, they should look like this:

Since these changes don’t affect the snapshot, you don’t need to close and relaunch a local deployment. Just hit play in the Editor and notice that, at last, there are spheres in your world!

Notice how the client-worker and server-work have their own GameObject representations for the “Player” and “Sphere” entities, with their workers offsets correctly being applied to each object. This is because the default GameObject creator accounts for worker offsets when instantiating GameObjects.

Updated about a year ago

b. GameObject setup

Suggested Edits are limited on API Reference Pages

You can only suggest edits to Markdown body content, but not to the API spec.