Impact Actions

Impact Actions are objects containing a OnImpact function. They are usually in a list called ImpactActionGroup and can be found on most usable items and on projectiles.

The ImpactAction is initialized by a character and a CharacterItemAction. Impact Actions are not limited to Items. Anything can trigger an ImpactAction as long as there is an ImpactCollisionData.

Inspected Fields

Enabled

If the ImpactAction is not enabled it will not be invoked.

Delay

The impact can be delayed, this uses the Scheduler for delaying the function call.

Allow Multi Hits

In some cases impacts can be called by physics cast that happen every frame. Preventing multi hits will ensure only one impact happens until the impact action is reset.

Impact Callback Context

The OnImpact function takes in a ImpactCallbackContext parameter. The ImpactCallbackContext contains two main objects: the ImpactCollisionData and the ImpactDamageData.

Impact Collision Data

The Impact Collision Data contains all the information about the collision.

It contains the following properties:

uint m_SourceID;
LayerMask m_LayerMask;
RaycastHit m_RaycastHit;
Vector3 m_ImpactPosition;
GameObject m_ImpactGameObject;
Rigidbody m_ImpactRigidbody;
Collider m_ImpactCollider;
Vector3 m_ImpactDirection;
float m_ImpactStrength;
IDamageTarget m_DamageTarget;
IDamageSource m_DamageSource;
Component m_SourceComponent;
GameObject m_SourceGameObject;
GameObject m_SourceOwner;
GameObject m_SourceRootOwner;
CharacterLocomotion m_SourceCharacterLocomotion;
int m_HitCount;
ListSlice<Collider> m_HitColliders;
UsableAction m_SourceItemAction;
SurfaceImpact m_SurfaceImpact;

It is usually initialized by a RaycastHit. In the example below the ShooterModule uses the ImpactCollisionData:

var impactData = m_ShootableImpactCallbackContext.ImpactCollisionData;
impactData.Reset();
impactData.Initialize();
impactData.SetRaycast(closestRaycastHit);
impactData.SetImpactSource(ShootableAction);
{
    impactData.ImpactDirection = fireDirection;
    impactData.ImpactStrength = strength;
}
ShootableAction.OnFireImpact(m_ShootableImpactCallbackContext);

It can also be initialized manually. The example below is from the ImpactZone demo script:

var impactCollisionData = m_ImpactCallbackContext.ImpactCollisionData;
impactCollisionData.Reset();
impactCollisionData.Initialize();
impactCollisionData.SetImpactSource(gameObject,null);
impactCollisionData.SetImpactTarget(collider);
impactCollisionData.ImpactDirection = Vector3.zero;
impactCollisionData.ImpactPosition = collider.transform.position + Random.insideUnitSphere;
impactCollisionData.ImpactStrength = 1;
impactCollisionData.SurfaceImpact = m_SurfaceImpact;
Impact Damage Data

The ImpactDamageData is optional. It contains additional information about the impact which can be used by certain ImpactActions. It is often used in items to change the damage without changing the ImpactAction. It contains the following properties:

/// <summary>
/// An interface that contains information about the damage caused by an impact.
/// </summary>
public interface IImpactDamageData
{
    LayerMask LayerMask { get; set; }
    DamageProcessor DamageProcessor { get; set; }
    float DamageAmount { get; set; }
    float ImpactForce { get; set; }
    int ImpactForceFrames { get; set; }
    float ImpactRadius { get; set; }
    string ImpactStateName { get; set; }
    float ImpactStateDisableTimer { get; set; }
    SurfaceImpact SurfaceImpact { get; set; }
}
The DamageProcessor allows you to deal with the damage computation inside a ScriptableObject. This is a great way to predefine certain types of damage processing that can be reused in multiple places.

Impact Action Group Object

If you wish to reuse the same ImpactActions across multiple objects or simply want to use ImpactActions in your own custom scripts without writing custom inspectors, the ImpactActionGroupObject is a great solution.

A simple ScriptableObject that contains an ImpactActionGroup with a simple DoImpact function. Create the object using right-click context menu: Create -> Opsive -> Ultimate Character Controller -> Impact -> Impact Action Group Object.

Custom Impact Actions

Making a custom Impact Action is very easy. Simply override the OnImpactInternal function and use the data within the Context

[Serializable]
public class MyImpactAction : ImpactAction
{
    /// <summary>
    /// Internal method which performs the impact action.
    /// </summary>
    /// <param name="ctx">Context about the hit.</param>
    protected override void OnImpactInternal(ImpactCallbackContext ctx)
    {
        Debug.Log(ctx);
        // The ImpacCollisionData should never be null.
        Debug.Log(ctx.ImpactCollisionData.ImpactCollider);
        // The Damage Data is optional so it can be null.
        if (ctx.ImpactDamageData != null) {
            Debug.Log(ctx.ImpactDamageData?.DamageAmount);
        }
    }
}
Don’t forget the [Serializable] attribute above the class other you serialized values won’t show up or save in the inspector.

Built-in Impact Actions

There are a lot of Impact Actions and more will be added as time goes on.

To find a full list of the built-in ImpactActions use your IDE of choice (such as Visual Studio) and look for all classes inheriting the ImpactAction class.

DebugImpactContext

The impact isn’t working as you would like? Try to debug it using this action that logs the data within the ImpactContext.

Add Force

Add a force to the impacted object.

Add Torque

Add torque to the impacted object.

State Impact

Set a state object that was impacted.

Use Impact Action Object

Call the DoImpact function on a ImpactActionObject that can be used across multiple objects.

Spawn Surface Effect

Use the surface system to spawn surface effects.

Simple Damage

Deal damage to the impacted object. It can optionally use the ImpactDamageData such that the object calling the impact can set the damage rather than being constant. Use the DamageProcessor if you wish to have even more control over the damage.

Heal

The impacted object can be healed.