Spawning Actors at Runtime (Unreal Engine)

Normally in Unreal, if you wish to spawn a Actor at runtime, you would simply call “Spawn Actor From Class” in Blueprint, or UWorld::SpawnActor from C++, to make a new instance of it.

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

  1. The object spawned isn’t synchronized for everyone, so only your local client 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 CavrnusFunctionLibrary 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 the unique journal identifier for the spawned instance.

Setting up a Prefab to be Spawnable

To make your prefab spawnable, you need to add it to the list of actor classes in the CavrnusSpatialConnector in your level, with a unique name as the key.

SpawnPrefabs1.png

 

This unique string key 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 key name doesn’t change, old journal operations will now spawn the new prefab.)

Spawning your Prefab

Now, let’s create an object in the local map that will be able to create one or more Cavrnus objects:

 

Spawner1.png
In-World Appearance

 

 

As you can see, we’re simply passing in that unique string ID 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 its 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 Cavrnus Properties Container’s 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 no Container Name defined:

 

Now let’s look at the runtime instance that we got from the SpawnObject call. Notice that the Unique Container Name on the root has been completely replaced with the new ID.

 

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

public void SpawnPrefab() { // SpaceConnection here would be a class member of type FCavrnusSpaceConnection, that would be set on Space joined if (SpaceConnection == null) return; // SpawnedObjectArrived here would be a delegate class member of type FCavrnusSpawnedObjectArrived, that would be bound to a callback during setup FString InstanceContainerName = UCavrnusFunctionLibrary::SpawnObject(SpaceConnection, "PerfTestSphere", SpawnedObjectArrived); UCavrnusFunctionLibrary::PostBoolPropertyUpdate(SpaceConnection, InstanceContainerName, "Visibility", true); }

Deleting Spawned Objects

When deleting a spawned object, a FCavrnusSpawnedObject is provided. This can be saved off when FCavrnusSpawnedObjectArrived is called, or it can be retrieved from the SpawnedObjectsManager by calling UCavrnusFunctionLibrary::GetIfIsSpawnedObject. Once you have it, simply call DestroyObject on it.

 

 

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).