Creating Custom Combat Actions Through Code

Note: It is expected that you have C# coding knowledge before proceeding.

Combat Actions are created through the EmeraldAction class and allows users to create their own custom Combat Actions through a derived class. This is done through Scriptable Objects.

Each Combat Action has a derived UpdateAction function is updated through the Combat Component. Users can override this function to trigger their own functionality. All of the included Combat Actions were created using this method. Feel free to use or build upon these included examples.

For creating your first Combat Action, start off with the example below. This monitors the Enter Conditions to see if the Execute function can be called. When it can, start a coroutine that sets the action to true, debug logs a random number to the Unity Console, wait 1 second, do the same thing, and reset the cooldown and action state.

Each function is instanced to the AI that is passed through the UpdateAction function, however, this does not allow the usage of local variables. The ActionsClass contains helpful variables that users can use as local variables. You can see the Blocking, Strafing, and Dodging Combat Actions for examples utilizing this.

Coroutines can be used through ScriptableObjects by using the MonoBehavior of the passed EmeraldComponent. This also allows users to use local variables within the Coroutine.

Note: This example action script is included with Emerald AI 2024.

using UnityEngine;
using System.Collections;

namespace EmeraldAI
{
    /// <summary>
    /// An example Combat Action that Debug Logs a random number to the Unity Console.
    /// </summary>
    [CreateAssetMenu(fileName = "Example Action", menuName = "Emerald AI/Combat Action/Example Action")]
    public class ExampleActionUpdated : EmeraldAction
    {
        /// <summary>
        /// Continiously updates the EmeraldAction. This acts like an Update function that can run 
        /// within this action using the information from the passed EmeraldComponent and its ActionClass.
        /// </summary>
        public override void UpdateAction(EmeraldSystem EmeraldComponent, ActionsClass ActionClass)
        {
            if (!CanExecute(EmeraldComponent, ActionClass))
                return;

            Execute(EmeraldComponent, ActionClass);
        }

        /// <summary>
        /// Conditions required for the EmeraldAction to execute.
        /// </summary>
        bool CanExecute(EmeraldSystem EmeraldComponent, ActionsClass ActionClass)
        {
            var Conditions = (((int)EnterConditions) & ((int)EmeraldComponent.AnimationComponent.CurrentAnimationState)) != 0;
            return ActionClass.CooldownLengthTimer >= CooldownLength && Conditions && !ActionClass.IsActive;
        }

        /// <summary>
        /// Executes the Action because all conditions from CanExecute have been met.
        /// </summary>
        void Execute(EmeraldSystem EmeraldComponent, ActionsClass ActionClass)
        {
            //Use the monobehavior from EmeraldComponent to create an individual coroutine. This can allow localized variables if needed.
            EmeraldComponent.GetComponent<MonoBehaviour>().StartCoroutine(cAction(EmeraldComponent, ActionClass));
        }

        IEnumerator cAction(EmeraldSystem EmeraldComponent, ActionsClass ActionClass)
        {
            //Set the Action as active
            ActionClass.IsActive = true;

            //Debug log a random number using a local variable from the passed EmeraldComponent's MonoBehaviour.
            int LocalVariableExample = Random.Range(0, 256);
            Debug.Log(EmeraldComponent.gameObject.name + "  " + LocalVariableExample);

            //Wait 1 second
            yield return new WaitForSeconds(1);

            //After waiting a second, do the same thing.
            LocalVariableExample = Random.Range(0, 256);
            Debug.Log(EmeraldComponent.gameObject.name + "  " + LocalVariableExample);

            //Reset the cooldown timer and set the IsActive to false
            ActionClass.CooldownLengthTimer = 0;
            ActionClass.IsActive = false;
        }
    }
}

Last updated