This document is about: FUSION 2
SWITCH TO

Interactions

Interactions

Interaction includes detecting, registering, unregistering and updating an object that affects the KCC in some way.

KCC supports two interaction types:

  • Collision
    • Physics based interaction.
    • Triggered when KCC starts/stops colliding with a scene object (can be a regular collider or a trigger).
  • Modifier
    • Manually registered interaction via KCC.AddModifier() and KCC.RemoveModifier().
    • The colliding game object can be a scene object or a prefab.

In either case, the colliding game object must meet following requirements:

  • It must have NetworkObject component.
  • It must have a component which implements IKCCInteractionProvider or any derived interface.

Interface IKCCInteractionProvider declares two important methods:

bool CanStartInteraction() => true;

  • Controls start of an interaction
  • The interaction can be deferred until certain conditions are met (it is not registered within KCC until true is returned)
  • For example when the player enters an area and gets a speed buff at full health only

bool CanStopInteraction() => true;

  • Controls end of an interaction
  • Stopping interaction can be deferred until certain conditions are met (it keeps registered in KCC until true is returned)
  • For example when the player enters an area and gets slowdown debuff, removal is deferred until the player is at full health (no matter if the player still stands within the area or not)

Typically interactions provide a KCC Processor to inject custom movement logic, but they are not limited to this. Objects the KCC interacts with can also be iterated from the gameplay code.

Let's have a world zone with increased gravity (defined by a box collider - trigger). The game object has a special GravityProcessor which modifies gravity in KCC calculations. This component also implements an IUIMapProvider interface which provides a name for the current location. A UI script executes following code to update the text on screen:

C#

public void Update()
{
    foreach (IUIMapProvider mapProvider in _kcc.GetInteractions<IUIMapProvider>())
    {
        // Set location name in UI to first location provided by KCC.
        _location.text = mapProvider.LocationName;
        break;
    }
}

In general these iterations are very efficient because they reuse results from KCC physics query.

Processors

Processors are special objects which KCC interacts with (the interaction provides a processor to the KCC). They are designed to allow mixing various movement effects on top of basic logic in a clean way.

Main Entry Points

IKCCProcessor

  • Base interface for all processors.
  • Used to execute enter/exit callbacks and update methods.
  • Any scripts that implements IKCCProcessor can be linked to Processors in KCC settings.
  • Execution of methods declared by IKCCProcessor is supported on
    • ✅ Prefabs
    • ✅ Instances spawned with Runner.Spawn()
    • ✅ Instances spawned with GameObject.Instantiate()

C#

public partial interface IKCCProcessor
{
    float GetPriority(KCC kcc) => default;       // Processors with higher priority are executed first.

    void OnEnter(KCC kcc, KCCData data)       {} // Called when a KCC starts interacting with the processor.
    void OnExit(KCC kcc, KCCData data)        {} // Called when a KCC stops interacting with the processor.
    void OnStay(KCC kcc, KCCData data)        {} // Called when a KCC interacts with the processor and the movement is fully predicted or extrapolated.
    void OnInterpolate(KCC kcc, KCCData data) {} // Called when a KCC interacts with the processor and the movement is interpolated.
}

IKCCProcessorProvider

  • Derived from IKCCInteractionProvider
  • Base interface for all interactions providing an instance of IKCCProcessor

Base Processor Types


C#

public abstract partial class KCCProcessor : MonoBehaviour, IKCCProcessor, IKCCProcessorProvider
  • ❗ Requires NetworkObject component
  • ✅ Can be directly linked to Processors in KCC settings
  • ❌ No support for [Networked] properties

C#

public abstract partial class NetworkKCCProcessor : NetworkBehaviour, IKCCProcessor, IKCCProcessorProvider
  • ❗ Requires NetworkObject component
  • ✅ Can be directly linked to Processors in KCC settings
  • ✅ Supports [Networked] properties for spawned objects

C#

public abstract partial class NetworkTRSPProcessor : NetworkTRSP, IKCCProcessor, IKCCProcessorProvider
  • ❗ Requires NetworkObject component
  • ✅ Can be directly linked to Processors in KCC settings
  • ✅ Supports [Networked] properties for spawned objects
  • ✅ Position provider for Area of Interest with custom transform sychronization (advanced)

C#

public abstract partial class ScriptableKCCProcessor : ScriptableObject, IKCCProcessor
  • ✅ All benefits of ScriptableObject
  • ✅ Can be directly linked to Processors in KCC settings
  • ❌ No support for [Networked] properties
  • ❗ At runtime the processor must be added to KCC via an IKCCProcessorProvider instance

Common Usage

There are some common patterns how KCC processors are used:

  1. State-less processor with general logic, linked as prefab - for example an Environment Processor.
  2. State-full processor spawned in scene, for example a Damage Area.
  3. State-full processor spawned for each player as child object, for example a Jetpack.

Execution

Following diagram shows an example with execution order of multiple KCC processors. Some stages are omitted for simplicity.

Execution order of multiple KCC processors.
  1. The KCC caches all processors and backs up as a snapshot.
  2. The processor list is reseted back to the snapshot and sorted by priority on the beginning of every stage. Suppressing a processor in one stage doesn’t affect its execution in other stages.
  3. The IPrepareData stage is executed. In this case it is implemented by Environment Processor which sets a default value to KCCData.KinematicSpeed.
  4. EnvironmentProcessor executes a custom ISetKinematicSpeed stage by calling KCC.ExecuteStage<ISetKinematicSpeed>(). This stage is dedicated to calculate KCCData.KinematicSpeed property and is implemented by Mud Processor and Sprint Processor.
  5. Execute(ISetKinematicSpeed) is executed on the Mud Processor first. It multiplies KCCData.KinematicSpeed by 50% (simulating slower speed in mud) and suppresses execution of other processors by calling KCC.SuppressProcessors<IKCCProcessor>().
  6. The Sprint Processor is suppressed and Execute(ISetKinematicSpeed) won’t be executed in this case.
  7. KCC calculates position delta based on properties in KCC Data and moves.

Suppressing other processors

  • Pending execution of a processor(s) can be suppressed in any active stage
  • KCC.SuppressProcessors(IKCCProcessor processor) - suppresses a specific processor instance
  • KCC.SuppressProcessors<T>() - suppresses all processors of type T, using interfaces to logically split processors into groups is valid approach
  • Calling these methods without active stage will throw exception

Post-processing

  • KCC supports stage post-processing - executing a method at the end of the active stage
  • This is a very lightweight alternative to a processor with lowest priority (for example to clamp final value in KCCData)
  • KCC.EnqueuePostProcess(Action<KCC, KCCData> callback)
  • Calling this method without active stage will throw exception

Stages

Stage is a sequence of specific method calls executed on processors. It is uniquely identified by a type (usually interface) derived from IKCCStage<T> interface.

How stages work

  1. A stage is executed by calling KCC.ExecuteStage<T>() where T is the stage type.
  2. All processors which implement T are cached in a temporary list and sorted by processor Priority from highest to lowest.
  3. Method T.Execute(T stage, KCC kcc, KCCData data) is executed sequentially on all processors in the list.
  4. Currently executed processor can suppress any pending processors from stage execution by calling KCC.SuppressProcessor(IKCCProcessor processor) / KCC.SuppressProcessors<T>(). These processors get removed from the temporary list, effectively skipping their execution.
  5. It is possible to query list of already executed processors or pending processors.

To compare stage methods and default processor callbacks - OnStay / OnInterpolate are guaranteed to execute on all tracked processors once per fixed/render update and their execution cannot be suppressed.

Generally stages can be executed at any time. It is also possible to execute a stage from within another stage, making the execution nested.

⚠️ Suppressing processors is always in the context of the currently executed stage.

Built-in stage types

KCC supports these stages executed during fixed/render update:

  • IBeginMove - executed at the beginning of a fully predicted or extrapolated move. Used to configure KCC, enable/disable features, add forces, …
  • IPrepareData - executed before calculating position delta. This stage is executed only if pending delta time is greater than extrapolation threshold => running full prediction. This is usually the best place to execute custom stage hierarchy to calculate velocity.
  • IAfterMoveStep - executed after each move step (physics query + depenetration from colliders) and before updating collision hits and firing OnEnter()/OnExit() callbacks. Used for minor position corrections, vector projections, … This stage is executed only if running full prediction (pending delta time is greater than extrapolation threshold). This method can be called multiple times in a row if the KCC moves too fast (CCD is applied).
  • IEndMove - executed on the end of fully predicted or extrapolated move. Use to apply any post processing.

Stage examples

  1. Definition of a custom stage

C#

public interface ICustomStage : IKCCStage<ICustomStage>
{
}
  1. Implementation of the custom stage.

C#

public class ExampleProcessor : KCCProcessor, ICustomStage
{
    public void Execute(ICustomStage stage, KCC kcc, KCCData data)
    {
        // Implementation of the custom stage.
    }
}
  1. Execution of the custom stage.

C#

public override void FixedUpdateNetwork()
{
    _kcc.ExecuteStage<ICustomStage>();
}
  1. Real example of custom stages from Environment Processor.

C#

public interface ISetGravity            : IKCCStage<ISetGravity>            {} // Dedicated stage to set KCCData.Gravity property.
public interface ISetDynamicVelocity    : IKCCStage<ISetDynamicVelocity>    {} // Dedicated stage to set KCCData.DynamicVelocity property.
public interface ISetKinematicDirection : IKCCStage<ISetKinematicDirection> {} // Dedicated stage to set KCCData.KinematicDirection property.
public interface ISetKinematicTangent   : IKCCStage<ISetKinematicTangent>   {} // Dedicated stage to set KCCData.KinematicTangent property.
public interface ISetKinematicSpeed     : IKCCStage<ISetKinematicSpeed>     {} // Dedicated stage to set KCCData.KinematicSpeed property.
public interface ISetKinematicVelocity  : IKCCStage<ISetKinematicVelocity>  {} // Dedicated stage to set KCCData.KinematicVelocity property.

public partial class EnvironmentProcessor : KCCProcessor, IPrepareData
{
    // IPrepareData INTERFACE

    public virtual void Execute(PrepareData stage, KCC kcc, KCCData data)
    {
        // Execute custom set of stages defined above.
        kcc.ExecuteStage<ISetGravity>();
        kcc.ExecuteStage<ISetDynamicVelocity>();
        kcc.ExecuteStage<ISetKinematicDirection>();
        kcc.ExecuteStage<ISetKinematicTangent>();
        kcc.ExecuteStage<ISetKinematicSpeed>();
        kcc.ExecuteStage<ISetKinematicVelocity>();

        // Suppress other processors for this stage.
        SuppressOtherEnvironmentProcessors(kcc);
    }
}

Execution order of processors can also be inspected at runtime, for more info please check Runtime Info.

Stage objects

Stages are not limited to movement logic, it is possible to pass a special stage object and use it for other gameplay mechanics.

  1. Definition of the stage.

C#

public interface IDamageBoost : IKCCStage<DamageBoost> {}
  1. Definition of the stage object.

C#

public sealed class DamageBoost : IDamageBoost
{
    public float MaxValue { get; private set; }

    public void Execute(DamageBoost stage, KCC kcc, KCCData data) {}

    public void ProcessDamageBoost(float damageBoost)
    {
        MaxValue = Mathf.Max(MaxValue, damageBoost);
    }

    public void Reset()
    {
        MaxValue = default;
    }
}
  1. Implementing IDamageBoost stage on a processor.

C#

public class DamageBoostArea : KCCProcessor, IDamageBoost
{
    public float DamageBoost = 4.0f;

    public void Execute(DamageBoost stage, KCC kcc, KCCData data)
    {
        stage.ProcessDamageBoost(DamageBoost);
    }
}
  1. Execution of stage object.

C#

public class Player : NetworkBehaviour
{
    public KCC KCC;

    // The stage is used like a player "attribute".
    private DamageBoost _damageBoost = new DamageBoost();

    public override void FixedUpdateNetwork()
    {
        _damageBoost.Reset();

        KCC.ExecuteStage(_damageBoost);

        float damageMultiplier = _damageBoost.MaxValue;

        // Firing from weapon...
        // The damage multiplier can be combined with base projectile damage.
    }
}

Stage objects can also implement IBeforeStage and IAfterStage interfaces.

C#

public sealed class CustomStageObject : ICustomStage, IBeforeStage, IAfterStage
{
    public void Execute(CustomStageObject stage, KCC kcc, KCCData data)
    {
    }

    // IBeforeStage is optional and executed on stage objects only.
    // It is typically used to reset members to default values before stage is executed.
    void IBeforeStage.BeforeStage(KCC kcc, KCCData data)
    {
    }

    // IAfterStage is optional and executed on stage objects only.
    // It is typically used to iterate over collected information and calculate results on the end of the stage.
    void IAfterStage.AfterStage(KCC kcc, KCCData data)
    {
    }
}

Execution order

  1. IBeforeStage.BeforeStage() on stage object.
  2. IKCCStage<T>.Execute(T stage, KCC kcc, KCCData data) on all processors sorted by priority.
  3. IKCCStage<T>.Execute(T stage, KCC kcc, KCCData data) on stage object.
  4. Executed all post-processes queued with KCC.EnqueuePostProcess().
  5. IAfterStage.AfterStage() on stage object.

Execution order of stages can also be inspected at runtime, for more info please check Runtime Info.

Back to top