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!
}