You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

305 lines
13 KiB
C#

using MalbersAnimations.Scriptables;
using UnityEngine;
namespace MalbersAnimations.Controller.AI
{
[CreateAssetMenu(menuName = "Malbers Animations/Pluggable AI/Tasks/Play Mode")]
public class PlayModeTask : MTask
{
public override string DisplayName => "Animal/Set|Play Mode";
public enum PlayWhen { PlayOnce, PlayForever, Interrupt }
[Tooltip("Mode you want to activate when the brain is using this task")]
public ModeID modeID;
[Tooltip("Ability ID for the Mode... if is set to -1 it will play a random Ability")]
public IntReference AbilityID = new IntReference(-99);
public FloatReference ModePower = new FloatReference();
[Tooltip("Play the mode only when the animal has arrived to the target")]
public bool near = false;
[Space, Tooltip("Apply the Task to the Animal(Self) or the Target(Target)")]
public Affected affect = Affected.Self;
[Tooltip("Play Once: it will play only at the start of the Task. Play Forever: will play forever using the Cooldown property")]
public PlayWhen Play = PlayWhen.PlayForever;
[Tooltip("Time elapsed to Play the Mode again and Again")]
public FloatReference CoolDown = new FloatReference(2f);
[Tooltip("Play the Mode if the Animal is Looking at the Target. Avoid playing modes while the target is behind the animal when this value is set to 180")]
[Range(0f, 360f)]
public float ModeAngle = 360f;
[Tooltip("Align with a Look At towards the Target when Playing a mode")]
public bool lookAtAlign = false;
[Tooltip("When the mode is said to Play Forever, it will ignore the first cooldown")]
public bool IgnoreFirstCoolDown = true;
[Tooltip("Align time to rotate towards the Target")]
public float alignTime = 0.3f;
public override void StartTask(MAnimalBrain brain, int index)
{
if (CoolDown <= 0)
{
if (Play == PlayWhen.PlayOnce)
{
if (near && !brain.AIControl.HasArrived) return; //Dont play if Play on target is true but we are not near the target.
if (PlayMode(brain))
{
brain.TasksVars[index].boolValue = true; //Store on the Bool Variable of the Decision that it has already play the mode
}
}
else if (Play == PlayWhen.Interrupt)
{
switch (affect)
{
case Affected.Self:
brain.Animal.Mode_Interrupt();
break;
case Affected.Target:
if (brain.TargetAnimal != null) brain.TargetAnimal.Mode_Interrupt();
break;
default:
break;
}
}
}
}
public override void UpdateTask(MAnimalBrain brain, int index)
{
if (near && !brain.AIControl.HasArrived)
{
// brain.TasksStartTime[index] = Time.time; //Reset the time to the Arrive time
return; //Dont play if Play on target is true but we are not near the target.
}
switch (Play)
{
case PlayWhen.PlayOnce:
if (!brain.TasksVars[index].boolValue) //Means the Mode has not played
{
if (MTools.ElapsedTime(brain.TasksStartTime[index], CoolDown) && PlayMode(brain))
{
brain.TasksVars[index].boolValue = true; //Set that te mode was Played Once!!
return; //Skip the code
}
return;
}
else
{
switch (affect)
{
case Affected.Self:
if (!brain.Animal.IsPlayingMode && !brain.Animal.IsPreparingMode) brain.TaskDone(index);
break;
case Affected.Target:
if (brain.TargetAnimal && !brain.TargetAnimal.IsPlayingMode && !brain.TargetAnimal.IsPreparingMode) brain.TaskDone(index);
break;
default:
break;
}
}
break;
case PlayWhen.PlayForever:
if (!brain.TasksVars[index].boolValue && IgnoreFirstCoolDown) //Means the Mode has not played
{
if (PlayMode(brain))
{
brain.TasksStartTime[index] = Time.time; // Reset the cooldown timer
brain.TasksVars[index].boolValue = true; //Set that te mode was Played Once!!
}
}
if (MTools.ElapsedTime(brain.TasksStartTime[index], CoolDown)) //If the animal is in range of the Target
{
if (PlayMode(brain))
{
brain.TasksStartTime[index] = Time.time; // Reset the cooldown timer
}
}
break;
case PlayWhen.Interrupt:
if (!brain.TasksVars[index].boolValue) //Means the Mode has not played
{
if (MTools.ElapsedTime(brain.TasksStartTime[index], CoolDown))
{
brain.TasksVars[index].boolValue = true; //Set that te mode was Played Once!!
switch (affect)
{
case Affected.Self:
brain.Animal.Mode_Interrupt();
break;
case Affected.Target:
if (brain.TargetAnimal != null) brain.TargetAnimal.Mode_Interrupt();
break;
default:
break;
}
brain.TaskDone(index);
}
return;
}
break;
default:
break;
}
}
private bool PlayMode(MAnimalBrain brain)
{
switch (affect)
{
case Affected.Self:
var Direction_to_Target = brain.Target != null ? (brain.Target.position - brain.Eyes.position) : brain.Animal.Forward;
var EyesForward = Vector3.ProjectOnPlane(brain.Eyes.forward, brain.Animal.UpVector);
if (ModeAngle == 360f || Vector3.Dot(Direction_to_Target.normalized, EyesForward) > Mathf.Cos(ModeAngle * 0.5f * Mathf.Deg2Rad)) //Mean is in Range:
{
if (brain.Animal.Mode_TryActivate(modeID, AbilityID))
{
if (lookAtAlign && brain.Target)
brain.StartCoroutine(MTools.AlignLookAtTransform(brain.Animal.transform, brain.AIControl.GetTargetPosition(), alignTime));
brain.Animal.Mode_SetPower(ModePower);
return true;
}
}
break;
case Affected.Target:
Direction_to_Target = brain.Eyes.position - brain.Target.position; //Reverse the Direction
EyesForward = Vector3.ProjectOnPlane(brain.Target.forward, brain.Animal.UpVector);
if (ModeAngle == 360f || Vector3.Dot(Direction_to_Target.normalized, EyesForward) > Mathf.Cos(ModeAngle * 0.5f * Mathf.Deg2Rad)) //Mean is in Range:
{
if (brain.TargetAnimal && brain.TargetAnimal.Mode_TryActivate(modeID, AbilityID))
{
if (lookAtAlign && brain.Target)
brain.StartCoroutine(MTools.AlignLookAtTransform(brain.TargetAnimal.transform, brain.transform, alignTime));
brain.TargetAnimal.Mode_SetPower(ModePower);
return true;
}
}
break;
default:
break;
}
return false;
}
#if UNITY_EDITOR
public override void DrawGizmos(MAnimalBrain brain)
{
var Eyes = brain.Eyes;
if (Eyes && brain.Animal && ModeAngle < 360)
{
Color c = (Color.green + Color.yellow) / 2;
c.a = 1f;
Vector3 EyesForward = Vector3.ProjectOnPlane(brain.Eyes.forward, brain.Animal.UpVector);
Vector3 rotatedForward = Quaternion.Euler(0, -ModeAngle * 0.5f, 0) * EyesForward;
UnityEditor.Handles.color = c;
UnityEditor.Handles.DrawWireArc(Eyes.position, Vector3.up, rotatedForward, ModeAngle, 2);
}
}
#endif
void Reset() { Description = "Plays a mode on the Animal(Self or the Target)"; }
}
#region Inspector
#if UNITY_EDITOR
[UnityEditor.CustomEditor(typeof(PlayModeTask))]
public class PlayModeTaksEditor : UnityEditor.Editor
{
UnityEditor.SerializedProperty Description, MessageID, CoolDown, modeID, AbilityID, near, affect, ModePower, UpdateInterval,
Play, ModeAngle, lookAtAlign, WaitForPreviousTask, alignTime, IgnoreFirstCoolDown;
private void OnEnable()
{
Description = serializedObject.FindProperty("Description");
MessageID = serializedObject.FindProperty("MessageID");
ModePower = serializedObject.FindProperty("ModePower");
modeID = serializedObject.FindProperty("modeID");
AbilityID = serializedObject.FindProperty("AbilityID");
near = serializedObject.FindProperty("near");
affect = serializedObject.FindProperty("affect");
Play = serializedObject.FindProperty("Play");
CoolDown = serializedObject.FindProperty("CoolDown");
ModeAngle = serializedObject.FindProperty("ModeAngle");
lookAtAlign = serializedObject.FindProperty("lookAtAlign");
alignTime = serializedObject.FindProperty("alignTime");
IgnoreFirstCoolDown = serializedObject.FindProperty("IgnoreFirstCoolDown");
WaitForPreviousTask = serializedObject.FindProperty("WaitForPreviousTask");
UpdateInterval = serializedObject.FindProperty("UpdateInterval");
}
public override void OnInspectorGUI()
{
// base.OnInspectorGUI();
serializedObject.Update();
UnityEditor.EditorGUILayout.PropertyField(Description);
UnityEditor.EditorGUILayout.PropertyField(MessageID);
UnityEditor.EditorGUILayout.PropertyField(WaitForPreviousTask);
UnityEditor.EditorGUILayout.PropertyField(UpdateInterval);
UnityEditor.EditorGUILayout.PropertyField(affect);
UnityEditor.EditorGUILayout.PropertyField(Play, new GUIContent("Action"));
var playtype = (PlayModeTask.PlayWhen)Play.intValue;
if (playtype != PlayModeTask.PlayWhen.Interrupt)
{
UnityEditor.EditorGUILayout.PropertyField(near);
var oldColor = GUI.color;
GUI.color = modeID.objectReferenceValue == null ? (new Color(1, 0.4f, 0.4f, 1)) : oldColor;
UnityEditor.EditorGUILayout.PropertyField(modeID);
GUI.color = oldColor;
UnityEditor.EditorGUILayout.PropertyField(AbilityID);
UnityEditor.EditorGUILayout.PropertyField(ModePower);
UnityEditor.EditorGUILayout.PropertyField(CoolDown);
if (Play.intValue == 1 ) UnityEditor.EditorGUILayout.PropertyField(IgnoreFirstCoolDown);
UnityEditor.EditorGUILayout.PropertyField(ModeAngle);
UnityEditor.EditorGUILayout.BeginHorizontal();
UnityEditor.EditorGUILayout.PropertyField(lookAtAlign, new GUIContent("Quick Align"));
UnityEditor.EditorGUILayout.Space();
if (lookAtAlign.boolValue)
{
UnityEditor.EditorGUIUtility.labelWidth = 33;
UnityEditor.EditorGUILayout.PropertyField(alignTime, new GUIContent("Time"));
UnityEditor.EditorGUIUtility.labelWidth = 0;
}
UnityEditor.EditorGUILayout.EndHorizontal();
}
serializedObject.ApplyModifiedProperties();
}
}
#endif
#endregion
}