Extending Dani AI

Each node can be extended and custom coded to fit your AI’s design.

Observers

To create an Observer, derive from GenericObserver<T>, where T is your desired output type (e.g. float, int, bool, etc). The functions to override within the GenericObserver<T> are listed below in the following table.

Function to Override Description
OnStart() Like MonoBehaviour’s Start() function, all initializations go here
T OnObserverUpdate() Like MonoBehaviour’s Update() function, but it must return the variable output of type T

Here’s an example of creating a custom Observer that measures the speed of a rigidbody:

using InitialPrefabs.DaniAI;
using UnityEngine;

public class SpeedObserver : GenericObserver<float> {

    private Rigidbody rigidbody;

    // Use this for initialization, like Unity's Start() call
    public override void OnStart() {
        rigidbody = GetComponent<Rigidbody>();
    }

    // Like Unity's Update() call
    public override float OnObserverUpdate() {
        return rigidbody.velocity.magnitude;
    }
}

Decisions

We will support overriding Decisions at a future date.

Conditions

To create a new Condition, derive from the GenericCondition<T> class, where T is the type of output for the Condition.

Function to Override Description
CalculateLocalWeight() Processes the output from the observer and returns a 0 if the condition is false and 1 if the condition is true.
using InitialPrefabs.DaniAI;
using UnityEngine;

public class VelocityCondition : GenericCondition<Vector3> {
    public enum MoveType { Idle, IsMoving }
    public MoveType comparison;
 
    // Override this method to validate the observer's output.
    public override float CalculateLocalWeight () {
        var value = observer.Output;
  
        if (comparison == MoveType.Idle) {
            // If the magnitude is 0, return a 1, otherwise return a 0
            return value.magnitude == 0 ? 1 : 0;
        }
        else {
            // If the magnitude is greater than 0, return a 1, otherwise     
            // return a 0
            return value.magnitude > 0 ? 1 : 0;
        }
    }
}

Actions

To create a custom Action, derive from the Action class. See the table below to see which functions to override.

Function to Override Description
OnStart() Like MonoBehaviour’s Start() function, all initializations go here
OnActionStart() Called on the first frame that the Action is running.
OnActionUpdate() Called every frame while the Action is running. Returns ActionState.Running, ActionState.Fail, or ActionState.Success.
OnActionEnd(ActionState state) Called at the very last frame when Action finishes successfully or unsuccessfully. The state variable contains the info that the Action was a success or failure.

Here’s an example of an Action script that moves a GameObject containing a NavMeshAgent.

using InitialPrefabs.DaniAI;
using UnityEngine;
using UnityEngine.AI;

public class Move : Action {
    public Vector3 destination;
    private NavMeshAgent agent;

    // Use this for initialization, like Unity's Start() call
    public override void OnStart() {
        agent = GetComponent<NavMeshAgent>();
    }

    // Runs at the first frame the Action is active
    public override void OnActionStart() {
        agent.destination = destination;
        agent.isStopped = false;
    }

    // Runs every frame after OnActionStart()
    public override ActionState OnActionUpdate() {
        if (agent.remainingDistance <= agent.stoppingDistance) {
            return ActionState.Success;
        } else {
            return ActionState.Running;
        }
    }

    // Runs at the very last frame before the Action is disabled
    public override void OnActionEnd(ActionState state) {
        if (state == ActionState.Success) {
            Debug.Log("I've arrived!");
            agent.isStopped = true;
            agent.ResetPath();
        } else {
            Debug.Log("Couldn't reach my destination.");
        }
    }
}

Variables

To create a Variable of any type, simply create a class that derives from GenericVariable<T>, where T is the desired type you need. See the example below.

using InitialPrefabs.DaniAI;
using UnityEngine;
using UnityEngine.AI;

public class Vector3Variable : GenericVariable<Vector3> {
    // That's it!
}