Spawning Prefabs at Runtime (Unity)

Normally in Unity, if you wish to spawn a Prefab at runtime, you would simply call GameObject.Instantiate to make a new instance of it.

There are a couple of problems you run into when doing this in Cavrnus however.

  1. The spawn isn’t synchronized for everyone, so only you will see the new object.

  2. Even if it was synchronized, every instance would share the same property paths as the base prefab, so they couldn’t behave individually.

Both of these problems are solved using the API call SpawnObject.

What this does is it posts the object spawn to the journal and, in doing that, assigns it a new Property Path. Then when the object is Instantiated() it goes through all the PropertiesContainers and updates their property paths to reflect the spawned instance.

Setting up a Prefab to be Spawnable

To make your prefab spawnable, you need only right-click on it, and then select Cavrnus → Make Selection Spawnable.

image-20240325-184136.png

What this does under-the-hood is it adds that prefab to the Cavrnus Spatial Connector’s Spawnable Objects list. It also gives it a uniqueId (generally the name of the prefab, but we modify it slightly for duplicate names).

This UniqueId is what you will use to actually spawn the object. (Note that this means you can modify or change the prefab and, as long as the UniqueId doesn’t change, old journal operations will now spawn the new prefab.)

image-20240325-184414.png

Spawning your Prefab

Now, let’s write up a simple UI button script to spawn the object:

using CavrnusSdk.API; using UnityEngine; public class SpawnPrefabButton : MonoBehaviour { private CavrnusSpaceConnection spaceConn; private void Start() { CavrnusFunctionLibrary.AwaitAnySpaceConnection(spaceConn => this.spaceConn = spaceConn); } public void SpawnPrefab() { if (spaceConn == null) return; string instanceContainerName = spaceConn.SpawnObject("Cuby McCubeface"); } }

As you can see, we’re simply passing in that UniqueId from above. The value we get back, meanwhile, is the Container Name of the new Instance. So, when the new prefab is spawned, the Cavrnus Properties Container at it’s root will use this Container Name.

Properties on Spawned Objects

Spawned object property names are handled in a very similar way to Avatar Instances.

Essentially what happens is the initial root Container Name is replaced with the new spawned instance ID. Then, every sub-object that starts with the root Container Name swaps out that part of the string for new new Id.

To give an example, let’s look at the above prefab.

 

The Root has a Unique Container Name:

While the sub-parts have Container Names starting with that same root name:

Now let’s look at the runtime instance that we got from the SpawnObject call. As you can see, it has a unique name do distinguish it from other instances

 

Notice that the Unique Contain Name on the root has been completely replaced with the new ID.

Note: There is a Cavrnus Spawned Object Flag component also attached here. This will be needed later when we want to delete the object.

Meanwhile the Left Arm has replaced the first part of its Container Name only:

The new root Container Name is returned synchronously from the SpawnObject call, and can immediately be used to post properties. Alternatively, any ValueSync scripts on the object will function normally too.

public void SpawnPrefab() { if (spaceConn == null) return; string instanceContainerName = spaceConn.SpawnObject("Cuby McCubeface"); spaceConn.PostBoolPropertyUpdate(instanceContainerName, "Visibility", true); }

Deleting Spawned Objects

When deleting a spawned object, you will need to access the Cavrnus Spawned Object Flag attached to it. This can be done with a simple GetComponent call. Once you have it, simply call DestroyObject on it.

public void DestroySpawnedObject(GameObject objectToDestroy) { if(objectToDestroy.GetComponent<CavrnusSpawnedObjectFlag>() == null) { Debug.LogError($"{objectToDestroy} is not a Spawned Object!"); return; } GetComponent<CavrnusSpawnedObjectFlag>().SpawnedObject.DestroyObject(); }

 

The above system is a good way to spawn well-known prefabs. However, if you want to spawn more advanced or imported objects, you can read this guide here (TODO: LINK).