Getting Started
Package Types
Scene Setup
Custom Collision, Layers, and Tags
Key Differences from Standard Unity3D development
Economy
Scripting
C# Scripting
Visual Scripting
Sync and Multiplayer
Components
Environment Settings Overrides
Render Pipeline Settings Overrides
Guidelines
Supported Features and Limitations
Support
Unity Packages with C# code require some changes to work with the Spatial Creator Toolkit, and there are some important limitations.
.asmdef
), those need to be removed and any missing references must be resolved. Assemblies in an Editor
folder do not need to be removed.Editor
folder, or that you use a #if UNITY_EDITOR
directive.You can find a list of third-party packages with porting instructions here, including packages such as tweening and car control packages.
Spatial does not provide access to Camera.Main
; instead i provides its own camera API. For more details on this, and on using Cinemachine, see the Camera documentation.
Spatial does not support PlayerPrefs
. Instead we have a cloud-save system we call the DataStore
.
Saving to the DataStore creates a server request so we rate limit writes. This means inside your game-loop you should be reading/writing your save data to an intermediary C# object which you periodically write to the DataStore.
For more information view the DataStore API Reference.
A common technique for referencing assets in Unity is to drop them all inside a /Resources
folder then load them at runtime with Resources.Load(...
. Unfortunately, Unity3D does not allow Asset Bundles to add contents to Resources, so Spatial does not allow Creator Toolkit projects to use Resources
.
Instead, you can re-create the Resources.Load
workflow with ScriptableObjects. Create an object that holds a collection of UnityEngine.Object
s and then add the assets you want to reference to it.
[CreateAssetMenu(fileName = "NewAssetCollection", menuName = "AssetCollection")]
public class AssetCollection : ScriptableObject
{
public UnityEngine.Object[] assets;
}
You can then search through the AssetCollection.assets
by object name similar to Resources.Load
.
<aside>
<img src="/icons/light-bulb_red.svg" alt="/icons/light-bulb_red.svg" width="40px" /> Remember that packages uploaded only contains the dependencies of a scene. If your AssetCollection
is not directly referenced by a GameObject in the scene it will not be included.
</aside>
A key limitation of Spatial Creator Toolkit projects is they can only have one scene. This means that if you’re used to creating several scenes for different levels, or even reloading the same scene to reset the game, you’ll have to design around this limitation.
Here are some useful strategies that we’ve used internally and with teams that help work around this limitation:
For Buddy Blitz we used this strategy, and the levels were loaded and unloaded via scripting. While on development, we actually had different scenes with the prefab we wanted to test.
As you can see, using this strategy you will be able to subdivide your content and load/unload it accordingly.
Group your “scenes” as a top level game objects and create a SceneManager script that handles loading/unloading. This is similar to the first strategy, but you could potentially have everything on the scene. In the following sample, the Scene script was just created to recreate the scene object when the Restart()
function is called.
When you load your space on Spatial, you will notice that Spatial already provides an avatar controller that allows users to control their character from any of our provided platforms. However, there are times where we want to be able to control how the Spatial avatar moves, where it moves, how it looks, or how it animates. Unlike a direct Unity project, Spatial doesn’t provide direct access to the avatar controller game object, but rather it exposes key functionality thru the use of Spatial Services. All of these services are part of our SpatialBridge and we’ll go thru them:
Sometimes you want the be able to hide the user avatars for different reasons. For example, hide the avatar when riding a vehicle, or a cutscene where you want the other avatars on the space to disappear while you show it. We can do this using the avatar’s visibleLocally
and visibleRemotely
variables. These variables will allow you to control how your avatar is presented on your device, on other user’s devices, and how other user’s avatars look on your device.
visibleLocally
hides the avatar on your device. You can set this for any actor’s avatar, including localActor.visibleRemotely
hides the avatar for everyone. Only available on localActor’s avatar.public void ToggleRemoteVisibility()
{
// Change visibility on my avatar to everyone's client
SpatialBridge.actorService.localActor.avatar.visibleRemotely = !SpatialBridge.actorService.localActor.avatar.visibleRemotely;
}
public void ToggleLocalVisibility()
{
// Change visibility of my avatar only on my client
SpatialBridge.actorService.localActor.avatar.visibleLocally = !SpatialBridge.actorService.localActor.avatar.visibleLocally;
}
public void ToggleLocalVisibilityOtherAvatars()
{
// Change visibility of other avatars on my client
foreach (var actor in SpatialBridge.actorService.actors.Values)
{
if (actor != SpatialBridge.actorService.localActor)
{
actor.avatar.visibleLocally = !actor.avatar.visibleLocally;
}
}
}
To control the local avatar’s visuals, you can use the local avatar’s SetAvatarBody
function (see https://cs.spatial.io/reference/SpatialSys.UnitySDK.IAvatar.SetAvatarBody). This function allows you to change the avatar to a SpatialAvatar that’s either uploaded to your spatial world as a separate package, or change it to a SpatialAvatar embedded within your space package.
public void ChangeAvatarBody()
{
// Change the user's avatar to an embedded asset avatar
SpatialBridge.actorService.localActor.avatar.SetAvatarBody(AssetType.EmbeddedAsset, "OgreAvatar");
// Change the user's avatar to a Spatial Studio avatar
SpatialBridge.actorService.localActor.avatar.SetAvatarBody(AssetType.Package, "ITEM_ID_FROM_SPATIAL_STUDIO");
// Reset the user's avatar to the default
SpatialBridge.actorService.localActor.avatar.ResetAvatarBody();
}
As you can see, there are multiple ways of creating the body. See https://docs.spatial.io/components/custom-avatars to understand how to create a custom avatar.
Sometimes you’d like to change the avatar’s animation. You can do this using the PlayEmote
and StopEmote
functions on your local avatar (see https://cs.spatial.io/reference/SpatialSys.UnitySDK.IAvatar.PlayEmote).
<aside> 💡 Note: Spatial Avatars don’t support custom animator controllers for the time being, so you can only control animations via PlayEmote and StopEmote. Ideally sometime in the future we have more advanced avatar controller support that’s you can properly sync between clients.
</aside>
public void StartSwimming()
{
// Play the swim animation on the local actor's avatar
SpatialBridge.actorService.localActor.avatar.PlayEmote(AssetType.EmbeddedAsset, "SwimAnimation", immediately: true, loop: true);
}
public void StopSwimming()
{
SpatialBridge.actorService.localActor.avatar.StopEmote();
}