This document is about: QUANTUM 3
SWITCH TO

Entity View

Introduction

QuantumEntityViews are linked to Entities via the Quantum View component. It contains an AssetRef to the GameObject which represents the view and should be instantiated for a specific entity. When configuring an Entity Prototype prefab or scene object with a QuantumEntityView in Unity, the Quantum View component is automatically filled into the prototype.

The QuantumEntityViewUpdater is responsible for handling the view side of all entities in Unity such as destroying, creating and updating the view game objects of associated entities, based on data from the simulation. The QuantumEntityViewUpdater script needs to be added to all scenes that contain a QuantumMap.

QuantumEntityViewComponents can be used to add view related features to individual EntityViews. See the Entity View Component section.

Pooling

By default, the QuantumEntityViewUpdater creates new instances of the QuantumEntityView prefabs whenever an entity gets created and destroys the view GameObjects respectively.

To enable pooling of entity views add the QuantumEntityViewPool script to the QuantumEntityViewUpdater game object. The pool works seamlessly with the EVU and can be replaced by a custom implementation by using the IQuantumEntityViewPool interface.

HidePooledObjectsInHierarchy Toggle on to set HideFlags.HideInHierarchy on pooled objects
ResetGameObjectScale Toggle on to reset the local scale of objects to one
Precache Items Object will be instantiated during Awake() and made available in the pool

EntityViews that subscribe to Quantum callbacks or events must make sure to either:

  • Unsubscribe before the game objects are returned to the pool
  • Must enable the onlyIfActiveAndEnabled parameter as shown below

C#

QuantumEvent.Subscribe<EventPlayerKilled>(this, OnKilled, onlyIfActiveAndEnabled: true);

Bind Behaviour

The QuantumEntityView script in Unity has a property called Bind Behaviour which can be set to either:

  • Non Verified: the view Game Object can be created in Predicted frames
  • Verified: the view Game Object can only be created in Verified frames

Using Non Verified is usually better for the views of entities which are instantiated in high frequency and/or they need to show up as quickly as possible on the player screen due to gameplay reaction time mechanics and such. For example, creating projectiles in a fast paced shooting game should be done using this alternative.

Using Verified on the other hand is mostly useful for views of entities which does not need to show up immediately and can afford the small delay of waiting for a Verified frame. This can be useful to avoid creating/destructing view objects during mispredictions. A good example of when to use this is for the creation of playable character entities.

Manual Disposal

If the Manual Disposal property is toggled on the destruction methods in the QuantumEntityViewUpdater are skipped. This allows for manual destruction using the OnEntityDestroyed callback of the QuantumEntityView or to destroy them via custom destroy events.

View Flags

The view flags configure smaller details and allows performance tweaks on the entity views.

DisableUpdateView QuantumEntityView.UpdateView() and QuantumEntityView.LateUpdateView() are not processed and forwarded to entity view components.
DisableUpdatePosition Will completely disable updating the entity view positions.
UseCachedTransform Use cached transforms to improve the performance by not calling Transform properties.
DisableEntityRefNaming By default, the entity game object is named to resemble its EntityRef value. Set this flag to disable this behaviour.
DisableSearchChildrenForEntityViewComponents Disable searching the entity view game object children for entity view components.

Prediction Error Correction

Fine tune the error correction settings for an entity view. Each parameter has a detailed description in the Unity inspector.

Events

Add Unity events to the creation (also from the pool) and destruction of entity views. It uses UnityEvent<QuantumGame>

Teleporting Entities

The QuantumEntityView script interpolates the entity GameObject visuals by default. This adjusts for the difference in simulation rate, render rate and for error correction in terms of mis-prediction.

When moving an entity to a distant location in a single frame (i.e "teleporting" it), even though the entity data in the simulation snaps to the target position, the view interpolation will lerp it between the start and end positions over a few frames.
It can be noticeable and the view game object could be seen moving very fast on the screen, which is not desired.

In order to prevent this from happening, when an entity's Position should change so much (usually when respawning an entity or moving if the game has teleport features), use transform->Teleport(frame, newPosition);. This makes the Entity view component automatically apply non-lerped movement.

Finding Views

A very common use case is to find the view of a specific entity. Since the simulation side is not aware of QuantumEntityViews, EntityRefs must be passed to the view via events, or polled (read only) from the frames. The QuantumEnityViewUpdater has a GetView(EntityRef) function that can be used to find the view of a specific EntityRef. The views are cached in a dictionary, so the lookup is very efficient.

Events and Update Order

The OnObservedGameUpdated function on the QuantumEntityViewUpdater, which is responsible for creating, destroying and updating EntityViews, gets called before events get processed. This means that destroyed entities in an event might already had their views destroyed.

Custom Destroy Events

A common pattern is to destroy an entity but still wanting to execute an event with additional information about the destruction to the view. To prevent the QuantumEntityView from getting destroyed before the event gets processed set its Manual Disposal field to true.

This will keep the view alive instead of passing it into the QuantumEntityViewUpdater's DestroyEntityViewInstance function which by default destroys the GameObject.

With that the event handler can still find the view and execute the destroy event with the view present. The QuantumEntityView needs to be cleaned up manually by destroying it or returning it to the object pool.

AutoFindMapData

AutoFindMapData has to be enabled when using maps with QuantumEntityView on them. If enabled the view will search for the corresponding MapData object and match map entities with their views. Disable this if you are not using maps with entities to allow for having scenes without a MapData script present.

Customizations

The QuantumEntityViewUpdater gives the following possibilities to customize.

Overriding Create

To get the GameObjects from a pool instead of having them instantiated, override the CreateEntityViewInstance function. The function has a Quantum.EntityView parameter indicating which view to spawn. The QuantumEntityView.AssetGuid can be used as a key in a dictionary of pooled objects.

C#

protected override QuantumEntityView CreateEntityViewInstance(Quantum.EntityView asset, Vector3? position = null, Quaternion? rotation = null) {
    Debug.Assert(asset.View != null);

    // view pooling can also be customized by using IQuantumEntityViewPool
    EntityView view = _myObjectPool.GetInstance(asset);

    view.transform.position = position ?? default;
    view.transform.rotation = rotation ?? Quaternion.identity;

    return view;
}

The result of CreateEntityViewInstance() gets assigned to the Entity in OnEntityViewInstantiated(). This method is virtual as well and can be overridden but in most cases this is not necessary. When overriding it is important to keep the EntityRef assignment in place.

Overriding Destroy

To return views to the pool, instead of destroying them, override DestroyEntityViewInstance().

C#

protected virtual void DestroyEntityViewInstance(QuantumEntityView instance) {
    _myObjectPool.ReturnInstance(instance);
}

Map Entities

For map entities, ActivateMapEntityInstance() is responsible for activating the views and can be overridden for custom behavior if needed.

DisableMapEntityInstance() gets called which by default disables the GameObject. This function can be overridden for custom behavior as well.

Back to top