Artificial Intelligence (AI)

The Ultimate Character Controller is focused on being a great character controller so it does not include any built-in AI implementations. AI is an extremely large topic so instead of including an implementation that would likely be replaced past the prototype stage the controller is instead structured so it can work with existing AI implementations. Behavior Designer is a behavior tree implementation and is cleanly integrated with the Ultimate Character Controller.

API

If you are scripting your own AI some common functions that you may need to perform are listed below. Ensure you have setup your character as an AI agent so the character will not use the camera.

Damage

An Ultimate Character Controller character can be damaged by getting a reference to the Health component and then calling the Damage method.

using UnityEngine;
using Opsive.UltimateCharacterController.Traits;

public class MyAIAgent : MonoBehaviour
{
    [Tooltip("A reference to the Ultimate Character Controller character.")]
    [SerializeField] protected GameObject m_Character;

    /// <summary>
    /// Damages the character.
    /// </summary>
    private void Start ()
    {
        var health = m_Character.GetComponent<Health>();
        if (health != null) {
            health.Damage(50); // Inflict 50 damage on the character.
        }
    }
}
Use Item

An item can be used by starting the Use Item Ability:

using UnityEngine;
using Opsive.UltimateCharacterController.Character;
using Opsive.UltimateCharacterController.Character.Abilities.Items;

public class MyAIAgent : MonoBehaviour
{
    [Tooltip("A reference to the Ultimate Character Controller character.")]
    [SerializeField] protected GameObject m_Character;

    /// <summary>
    /// Uses the item.
    /// </summary>
    private void Start ()
    {
        var characterLocomotion = m_Character.GetComponent<UltimateCharacterLocomotion>();
        if (characterLocomotion != null) {
            // Get the Use ability.
            var useAbility = characterLocomotion.GetAbility<Use>();
            if (useAbility != null) {
                // Try to start the use ability. If the ability is started it will use the currently equipped item.
                characterLocomotion.TryStartAbility(useAbility);
            }
        }
    }
}
Equipping

In order to equip or unequip an item an item ability should be started. In the example below the ability will equip the next item, and then it will equip a specific item index.

using UnityEngine;
using Opsive.UltimateCharacterController.Character;
using Opsive.UltimateCharacterController.Character.Abilities.Items;

public class MyAIAgent : MonoBehaviour
{
    [Tooltip("A reference to the Ultimate Character Controller character.")]
    [SerializeField] protected GameObject m_Character;

    /// <summary>
    /// Equips the item.
    /// </summary>
    private void Start ()
    {
        var characterLocomotion = m_Character.GetComponent<UltimateCharacterLocomotion>();
        if (characterLocomotion != null) {
            // Get the EquipNext ability and start it. The next item within the ItemSetManager will be equipped.
            var equipNext = characterLocomotion.GetAbility<EquipNext>();
            if (equipNext != null) {
                characterLocomotion.TryStartAbility(equipNext);
            }

            // Equip a specific index within the ItemSetManager with the EquipUnequip ability.
            var equipUnequip = characterLocomotion.GetAbility<EquipUnequip>();
            if (equipUnequip != null) {
                // Equip the ItemSet at index 2 within the ItemSetManager.
                equipUnequip.StartEquipUnequip(2);
            }
        }
    }
}
Move

If you’d like to move your character a certain direction you can call the Move method on the UltimateCharacterLocomotion component.

using UnityEngine;
using Opsive.UltimateCharacterController.Character;
using Opsive.UltimateCharacterController.Game;

public class MyAIAgent : MonoBehaviour
{
    [Tooltip("A reference to the Ultimate Character Controller character.")]
    [SerializeField] private GameObject m_Character;

    private UltimateCharacterLocomotion m_CharacterLocomotion;

    /// <summary>
    /// Initializes the default values.
    /// </summary>
    private void Start()
    {
        m_CharacterLocomotion = m_Character.GetComponent<UltimateCharacterLocomotion>();
    }

    /// <summary>
    /// Move the character in the forward direction with a slight turn.
    /// </summary>
    private void Update()
    {
        m_CharacterLocomotion.Move(0, 1, 5);
    }
}

Impact Callback

When a weapon collides with another object the “OnObjectImpact” event will be sent from the built-in Event System. A corresponding Unity event will also be sent. This event allows you to add new functionality when the impact occurs without having to change the class at all. The following example will subscribe to this event from a new component:

using UnityEngine;
using Opsive.Shared.Events;
using Opsive.UltimateCharacterController.Items.Actions.Impact;

public class MyObject : MonoBehaviour
{
    /// <summary>
    /// Initialize the default values.
    /// </summary>
    public void Awake()
    {
        EventHandler.RegisterEvent<ImpactCallbackContext>(gameObject, "OnObjectImpact", OnImpact);
    }

    /// <summary>
    /// The object has been impacted with another object.
    /// </summary>
    /// <param name="ctx">The context of the impact.</param>
    private void OnImpact(ImpactCallbackContext ctx)
    {
        Debug.Log("Event received " + name + " impacted by " + ctx.ImpactCollisionData.SourceGameObject + " on collider " + ctx.ImpactCollisionData.ImpactCollider + ".");
    }

    /// <summary>
    /// The GameObject has been destroyed.
    /// </summary>
    public void OnDestroy()
    {
        EventHandler.UnregisterEvent<ImpactCallbackContext>(gameObject, "OnObjectImpact", OnImpact);
    }
}

Performance

If you are noticing performance bottlenecks within Animators.OnAnimatorsAnimatorMove there are a few different things that you can try to reduce the performance cost:

  • If you are using a pathfinding agent you can disable the Detect Horizontal Collisions and Detect Vertical Collisions toggle on the Ultimate Character Locomotion component.
  • Disable CharacterIK for your AI agents.
  • Use instancing on your character. Our community has had success with GPU Instancer and Mesh Animator.