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.

983 lines
39 KiB
C#

using System.Collections.Generic;
using UnityEngine;
using MalbersAnimations.Scriptables;
using UnityEngine.Events;
using UnityEngine.Serialization;
#if UNITY_EDITOR
using UnityEditor;
#endif
namespace MalbersAnimations.Controller
{
/// <summary>When an animal Enter a Zone this will activate a new State or a new Mode </summary>
[AddComponentMenu("Malbers/Animal Controller/Zone")]
public class Zone : MonoBehaviour
{
public bool debug;
[Tooltip("As soon as the animal enters the zone it will execute the logic. If False then Call the Method Zone.Activate()")]
public bool automatic;
[Tooltip("Disable the Zone after it was used")]
/// <summary>Disable the Zone after it was used</summary>
public bool DisableAfterUsed;
[FormerlySerializedAs("HeadOnly")]
/// <summary>Use the Trigger for Heads only</summary>
public bool BoneOnly;
/// <summary>Limit the Activation of the Zone of an angle from the Animal</summary>
[Range(0, 360), Tooltip("Limit the Activation of the Zone of an angle from the Animal")]
public float Angle = 360;
[Range(0, 1), Tooltip("Probability to Activate the Zone")]
public float Weight = 1;
[Tooltip("The Zone can be used in both sides")]
public bool DoubleSide = false;
[Tooltip("Flip the Angle")]
public bool Flip = false;
[FormerlySerializedAs("HeadName")]
public string BoneName = "Head";
[Tooltip("Choose between a Mode, State or Stance for the Zone")]
public ZoneType zoneType = ZoneType.Mode;
public StateAction stateAction = StateAction.Activate;
public StanceAction stanceAction = StanceAction.Enter;
[Tooltip("Layer to detect the Animal")]
public LayerReference Layer = new LayerReference(1048576); //Animal Layer
[Tooltip("State Status. If is set to [-1] the Status will be ignored")]
public IntReference stateStatus = new IntReference(0);
[SerializeField] private List<Tag> tags;
public ModeID modeID;
public StateID stateID;
public StanceID stanceID;
public MAction ActionID;
/// <summary> Mode Index Value</summary>
[SerializeField] private IntReference modeIndex = new IntReference(-99);
/// <summary>Mode Ability Index</summary>
public int ModeAbilityIndex => modeID.ID == 4 ? ActionID.ID : modeIndex.Value;
/// <summary>ID of the Zone regarding the Type of Zone(State,Stance,Mode) </summary>
public int ZoneID;
[Tooltip("Value of the Ability Status")]
public AbilityStatus m_abilityStatus = AbilityStatus.PlayOneTime;
[Tooltip("Time of Ability Activation")]
public float AbilityTime = 3f;
[Tooltip("Amount of Force that will be applied to the Animal")]
public FloatReference Force = new FloatReference(10);
[Tooltip("Aceleration to applied the Force when the Animal enters the zone")]
[FormerlySerializedAs("EnterDrag")]
public FloatReference EnterAceleration = new FloatReference(2);
[Tooltip("Exit Drag to decrease the Force when the Animal exits the zone")]
public FloatReference ExitDrag = new FloatReference(4);
[Tooltip("Limit the Current Force the animal may have")]
[FormerlySerializedAs("Bounce")]
public FloatReference LimitForce = new FloatReference(8);
[Tooltip("Change if the Animal is Grounded when entering the Force Zone")]
public BoolReference ForceGrounded = new BoolReference();
[Tooltip("Can the Animal be controller while on the Air?")]
public BoolReference ForceAirControl = new BoolReference(true);
/// <summary>Currents Animals using the zone</summary>
public List<MAnimal> CurrentAnimals { get; internal set; }
public MAnimal JustExitAnimal;
/// <summary>First Animal is Using the zone</summary>
public MAnimal CurrentAnimal => CurrentAnimals.Count > 0 ? CurrentAnimals[0] : null;
/// <summary>List of all collliders entering the Zone</summary>
internal List<Collider> m_Colliders = new List<Collider>();
[Tooltip("Value Assigned to the Mode Float Value when using the Mode Zone")]
[Min(0)] public float ModeFloat = 0;
public bool RemoveAnimalOnActive = false;
public AnimalEvent OnEnter = new AnimalEvent();
public AnimalEvent OnExit = new AnimalEvent();
public AnimalEvent OnZoneActivation = new AnimalEvent();
public AnimalEvent OnZoneFailed = new AnimalEvent();
[Tooltip("Collider for the Zone. If is not set, it will find the first collider attached to this gameobject")]
[RequiredField] public Collider ZoneCollider;
/// <summary>Keep a Track of all the Zones on the Scene </summary>
public static List<Zone> Zones;
private int GetID
{
get
{
switch (zoneType)
{
case ZoneType.Mode:
return modeID;
case ZoneType.State:
return stateID;
case ZoneType.Stance:
return stanceID;
case ZoneType.Force:
return 100;
default:
return 0;
}
}
}
/// <summary>Is the zone a Mode Zone</summary>
public bool IsMode => zoneType == ZoneType.Mode;
/// <summary>Is the zone a Mode Zone</summary>
public bool IsState => zoneType == ZoneType.State;
/// <summary>Is the zone a Mode Zone</summary>
public bool IsStance => zoneType == ZoneType.Stance;
public List<Tag> Tags { get => tags; set => tags = value; }
void OnEnable()
{
if (Zones == null)
Zones = new List<Zone>();
if (ZoneCollider == null)
ZoneCollider = GetComponent<Collider>(); //Get the reference for the collider
if (ZoneCollider)
{
ZoneCollider.isTrigger = true; //Force Trigger
ZoneCollider.enabled = true;
}
Zones.Add(this); //Save the the Action Zones on the global Action Zone list
if (ZoneID == 0) ZoneID = GetID;
CurrentAnimals = new List<MAnimal>(); //Get the reference for the collider
//ModeListeners = new Dictionary<MAnimal, UnityAction>();
}
void OnDisable()
{
Zones.Remove(this); //Remove the the Action Zones on the global Action Zone list
foreach (var animal in CurrentAnimals)
{
ResetStoredAnimal(animal);
OnExit.Invoke(animal);
}
CurrentAnimals = new List<MAnimal>(); //Get the reference for the collider
if (ZoneCollider) ZoneCollider.enabled = false;
m_Colliders = new List<Collider>();
JustExitAnimal = null;
}
//private void CheckMissingColliders()
//{
// for (var i = m_Colliders.Count - 1; i > -1; i--)
// {
// if (m_Colliders[i] == null) m_Colliders.RemoveAt(i);
// }
// if (m_Colliders.Count == 0) CurrentAnimals = new List<MAnimal>();
//}
void OnTriggerEnter(Collider other)
{
if (IgnoreCollider(other)) return; //If the collider does not fill the requirements skip
if (Tags != null && Tags.Count > 0) //Check if we are using Tags and if the entering animal does not have that tag the this zone is not for that animal
{
bool hasTag = false;
foreach (var t in tags)
{
if (t != null && other.transform.HasMalbersTagInParent(t))
{
hasTag = true;
break;
}
}
if (!hasTag)
{
if (debug)
Debug.LogWarning($"The Zone:<B>[{name}]</B> cannot be activated by <B>[{other.transform.root.name}]</B>. The Zone is using Tags and <B>[{other.transform.root.name}]</B> does not have any.");
return;
}
}
MAnimal animal = other.GetComponentInParent<MAnimal>(); //Get the animal on the entering collider
if (!animal || animal.Sleep || !animal.enabled) return; //If there's no animal, or is Sleep or disabled do nothing
if (animal == JustExitAnimal) return; //Do not activate the animal that just exit
if (!m_Colliders.Contains(other))
{
if (debug) Debug.Log($"<b>{name}</b> [Entering Collider] -> [{other.name}]",this);
m_Colliders.Add(other); //if the entering collider is not already on the list add it
}
else return; //The Collider was already there //Kinematic Activation.
if (CurrentAnimals.Contains(animal)) return; //if the animal is already on the list do nothing
else
{
// animal.IsOnZone = true; //Let know the animal is on a zone
animal.Zone = this; //Let know the animal is on a zone
CurrentAnimals.Add(animal); //Set a new Animal
OnEnter.Invoke(animal);
if (automatic)
{
ActivateZone(animal);
}
else
{
PrepareZone(animal);
}
}
}
void OnTriggerExit(Collider other)
{
// if (other.attachedRigidbody.isKinematic) return; //Ignore Kinematic Exiting Bodies
if (IgnoreCollider(other)) return; //If the collider does not fill the requirements skip
MAnimal animal = other.GetComponentInParent<MAnimal>();
if (animal == null) return; //If there's no animal script found skip all
if (m_Colliders != null && m_Colliders.Contains(other))
{
if (debug) Debug.Log($"<b>{name}</b> [Exit Collider] -> [{other.name}]",this);
m_Colliders.Remove(other); //Remove the collider from the list that is exiting the zone.
}
//CheckMissingColliders();
if (CurrentAnimals.Contains(animal)) //Means that the Entering animal still exist on the zone
{
if (!m_Colliders.Exists(x => x != null && x.transform.root == animal.transform)) //Check if the Collider was removed
{
OnExit.Invoke(animal); //Invoke On Exit when all animal's colliders has exited the Zone
ResetStoredAnimal(animal);
CurrentAnimals.Remove(animal);
if (automatic)
{
JustExitAnimal = animal;
this.Delay_Action(() => JustExitAnimal = null);
}
//animal.IsOnZone = true; //Let know the animal Not On the Zone anymore
animal.Zone = null; //Let know the animal Not On the Zone anymore
}
}
}
private bool IgnoreCollider(Collider other) =>
!isActiveAndEnabled || //Check if the Zone is Active
other.isTrigger || //No Triggers
other.transform.root == transform.root || //Triggers in the same hierarchy
!MTools.CollidersLayer(other, Layer.Value) || //Just accept animal layer only
BoneOnly && !other.name.ToLower().Contains(BoneName.ToLower()); //If is Head Only and no head was found Skip
/// <summary>Activate the Zone depending the Zone Type</summary>
/// <param name="forced"></param>
public virtual void ActivateZone(MAnimal animal)
{
var prob = Random.Range(0, 1);
if (Weight != 1 && Weight < prob)
{
if (debug) Debug.Log($"<b>{name}</b> [Zone Failed to activate] -> <b>[{prob:F2}]</b>",this);
return; //Do not Activate the Zone with low Probability.
}
var flip = (Flip ? 1 : -1);
var EntrySideAngle = Vector3.Angle(transform.forward * flip, animal.Forward) * 2;
var OtherSideAngle = EntrySideAngle;
if (DoubleSide) OtherSideAngle = Vector3.Angle(-transform.forward * flip, animal.Forward) * 2;
var side = Vector3.Dot((animal.transform.position - transform.position).normalized, transform.forward)*-1; //Calculate the correct side
if (Angle == 360 || (EntrySideAngle < Angle && side < 0) || (OtherSideAngle < Angle && side > 0))
{
var isZoneActive = false;
//animal.IsOnZone = true; //Let know the animal is on a zone
animal.Zone = this; //Let know the animal is on a zone
switch (zoneType)
{
case ZoneType.Mode:
isZoneActive = ActivateModeZone(animal);
break;
case ZoneType.State:
isZoneActive = ActivateStateZone(animal); //State Zones does not require to be delay or prepared to be activated Check if it can be activated
break;
case ZoneType.Stance:
isZoneActive = ActivateStanceZone(animal); //State Zones does not require to be delay or prepared to be activated
break;
case ZoneType.Force:
isZoneActive = SetForceZone(animal, true); //State Zones does not require to be delay or prepared to be activated
break;
}
if (isZoneActive)
{
if (debug) Debug.Log($"<b>{name}</b> [Zone Activate] -> <b>[{animal.name}]</b>",this);
OnZoneActive(animal);
}
}
}
public virtual void ActivateZone()
{
foreach (var animal in CurrentAnimals) ActivateZone(animal);
}
protected virtual void PrepareZone(MAnimal animal)
{
switch (zoneType)
{
case ZoneType.Mode:
var PreMode = animal.Mode_Get(ZoneID);
if (PreMode == null || !PreMode.HasAbilityIndex(ModeAbilityIndex)) //If the Animal does not have that mode or that Ability Index exti
{
OnZoneFailed.Invoke(animal);
Debug.LogWarning($"<B>[{name}]</B> cannot be activated by <B>[{animal.name}]</B>." +
$" It does not have The <B>[Mode {modeID.name}]</B> with <B>[Ability {ModeAbilityIndex}]</B>",this);
return;
}
PreMode.SetAbilityIndex(ModeAbilityIndex); //Set the Current Ability
break;
case ZoneType.State:
var PreState = animal.State_Get(ZoneID);
if (!PreState) OnZoneFailed.Invoke(animal);
break;
case ZoneType.Stance:
break;
case ZoneType.Force:
break;
}
}
/// <summary>Enables the Zone using the State</summary>
private bool ActivateStateZone(MAnimal animal)
{
var Succesful = false;
switch (stateAction)
{
case StateAction.Activate:
if (animal.ActiveStateID != ZoneID)
{
animal.State_Activate(ZoneID);
if (stateStatus != -1) animal.State_SetStatus(stateStatus);
Succesful = true;
}
break;
case StateAction.AllowExit:
if (animal.ActiveStateID == ZoneID)
{
animal.ActiveState.AllowExit();
Succesful = true;
}
break;
case StateAction.ForceActivate:
animal.State_Force(ZoneID);
if (stateStatus != -1) animal.State_SetStatus(stateStatus);
Succesful = true;
break;
case StateAction.Enable:
animal.State_Enable(ZoneID);
Succesful = true;
break;
case StateAction.Disable:
animal.State_Disable(ZoneID);
Succesful = true;
break;
//case StateAction.ChangeEnterStatus:
// if (animal.ActiveStateID == ZoneID)
// {
// animal.State_SetStatus(stateStatus);
// Succesful = true;
// }
// break;
case StateAction.SetExitStatus:
if (animal.ActiveStateID == stateID)
{
animal.State_SetExitStatus(stateStatus);
Succesful = true;
}
break;
default:
break;
}
return Succesful;
}
/// <summary>Enables the Zone using the Modes</summary>
private bool ActivateModeZone(MAnimal animal)
{
if (!animal.IsPlayingMode)
{
animal.Mode_SetPower(ModeFloat); //Set the correct height for the Animal Animation
return animal.Mode_TryActivate(ZoneID, ModeAbilityIndex, m_abilityStatus);
}
return false;
}
/// <summary>Enables the Zone using the Stance</summary>
private bool ActivateStanceZone(MAnimal animal)
{
switch (stanceAction)
{
case StanceAction.Enter:
animal.Stance_Set(stanceID);
break;
case StanceAction.Exit:
animal.Stance_Reset();
break;
case StanceAction.Toggle:
animal.Stance_Toggle(stanceID);
break;
case StanceAction.Stay:
animal.Stance_Set(stanceID);
break;
case StanceAction.SetDefault:
animal.DefaultStance = (stanceID);
break;
default:
break;
}
return true;
}
/// <summary>Enables the Zone using External Forces</summary>
private bool SetForceZone(MAnimal animal, bool ON)
{
if (ON) //ENTERING THE FORCE ZONE!!!
{
var StartExtForce = animal.CurrentExternalForce + animal.GravityStoredVelocity; //Calculate the Starting force
if (StartExtForce.magnitude > LimitForce)
{
StartExtForce = StartExtForce.normalized * LimitForce; //Add the Bounce
}
animal.CurrentExternalForce = StartExtForce;
animal.ExternalForce = transform.up * Force;
animal.ExternalForceAcel = EnterAceleration;
if (animal.ActiveState.ID == StateEnum.Fall) //If we enter to a zone from the Fall state.. Reset the Fall Current Distance
{
var fall = animal.ActiveState as Fall;
fall.FallCurrentDistance = 0;
// fall.UpImpulse = Vector3.Project(animal.DeltaPos, animal.UpVector); //Clean the Vector from Forward and Horizontal Influence
// animal.CalculateTargetSpeed(); //Important needs to calculate the Target Speed again
// animal.InertiaPositionSpeed = animal.TargetSpeed; //Set the Target speed to the Fall Speed so there's no Lerping when the speed changes
}
animal.GravityTime = 0;
animal.Grounded = ForceGrounded.Value;
animal.ExternalForceAirControl = ForceAirControl.Value;
}
else
{
if (animal.ActiveState.ID == StateEnum.Fall) animal.UseGravity = true; //If we are on the Fall State -- Reactivate the Gravity
if (ExitDrag > 0)
{
animal.ExternalForceAcel = ExitDrag;
animal.ExternalForce = Vector3.zero;
}
}
return ON;
}
internal void OnZoneActive(MAnimal animal)
{
OnZoneActivation.Invoke(animal);
if (RemoveAnimalOnActive)
{
ResetStoredAnimal(animal);
CurrentAnimals.Remove(animal);
}
if (DisableAfterUsed) enabled = false;
}
public void TargetArrived(GameObject go)
{
var animal = go.FindComponent<MAnimal>();
ActivateZone(animal);
}
public virtual void ResetStoredAnimal(MAnimal animal)
{
if (animal)
{
animal.Zone = null; //Tell the Animal is no longer on a Zone
switch (zoneType)
{
case ZoneType.Mode:
var mode = animal.Mode_Get(ZoneID);
if (mode != null) //Means we found the current Active mode
{
if (mode.AbilityIndex == ModeAbilityIndex) mode.ResetAbilityIndex(); //Only reset when it has the same Index... works for zones near eachother
//if (ModeListeners.TryGetValue(animal, out UnityAction action))
//{
// mode.OnEnterMode.RemoveListener(action);
// ModeListeners.Remove(animal); //Remove the Premode
//}
}
break;
case ZoneType.State:
break;
case ZoneType.Stance:
if (stanceAction == StanceAction.Stay && animal.Stance == stanceID.ID) animal.Stance_Reset();
break;
case ZoneType.Force:
SetForceZone(animal, false);
break;
default:
break;
}
}
}
[HideInInspector] public int Editor_Tabs1 = 0;
#if UNITY_EDITOR
[ContextMenu("Connect to Align")]
void TryAlign()
{
var method = this.GetUnityAction<MAnimal>("Aligner", "Align");
if (method != null) UnityEditor.Events.UnityEventTools.AddPersistentListener(OnZoneActivation, method);
MTools.SetDirty(this);
}
private void OnDrawGizmos()
{
if (Application.isPlaying && CurrentAnimals !=null)
{
foreach (var animal in CurrentAnimals)
{
var flip = (Flip ? 1 : -1);
var EntrySideAngle = Vector3.Angle(transform.forward * flip, animal.Forward) * 2;
var OtherSideAngle = EntrySideAngle;
if (DoubleSide) OtherSideAngle = Vector3.Angle(-transform.forward * flip, animal.Forward) * 2;
var DColor = Color.red;
var side = Vector3.Dot((animal.transform.position - transform.position).normalized, transform.forward)*-1;
if (Angle == 360 || (EntrySideAngle < Angle && side < 0) || (OtherSideAngle < Angle && side > 0 ))
{
DColor = Color.green;
}
MTools.Draw_Arrow(animal.transform.position + Vector3.up*0.05f, animal.Forward, DColor);
}
}
}
#endif
}
public enum StateAction
{
/// <summary>Tries to Activate the State of the Zone</summary>
Activate,
/// <summary>If the Animal is already on the state of the zone it will allow to exit and activate states below the Active one</summary>
AllowExit,
/// <summary>Force the State of the Zone to be enable even if it cannot be activate at the moment</summary>
ForceActivate,
/// <summary>Enable a Disabled State </summary>
Enable,
/// <summary>Disable State </summary>
Disable,
///// <summary>Set a State Status on a State</summary>
//ChangeEnterStatus,
/// <summary>Set a State Status on a State</summary>
SetExitStatus,
}
public enum StanceAction
{
/// <summary>Enters a Stance</summary>
Enter,
/// <summary>Exits a Stance</summary>
Exit,
/// <summary>Toggle a Stance</summary>
Toggle,
/// <summary>While the Animal is inside the collider the Animal will stay on the Stance</summary>
Stay,
/// <summary>While the Animal is inside the collider the Animal will stay on the Stance</summary>
SetDefault,
}
public enum ZoneType
{
Mode,
State,
Stance ,
Force,
}
#if UNITY_EDITOR
[CustomEditor(typeof(Zone))/*, CanEditMultipleObjects*/]
public class ZoneEditor : Editor
{
private Zone m;
protected string[] Tabs1 = new string[] { "General", "Events" };
SerializedProperty
HeadOnly, stateAction, HeadName, zoneType, stateID, modeID, modeIndex, ActionID, auto, DisableAfterUsed,
debug, m_abilityStatus, AbilityTime, Editor_Tabs1,
OnZoneActivation, OnExit, OnEnter, ForceGrounded, OnZoneFailed, Angle, DoubleSide, Weight, Flip, ForceAirControl, ZoneCollider,
stanceAction, layer, stanceID, RemoveAnimalOnActive, m_tag, ModeFloat, Force, EnterAceleration, ExitAceleration, stateStatus, Bounce;
//MonoScript script;
private void OnEnable()
{
m = ((Zone)target);
//script = MonoScript.FromMonoBehaviour((MonoBehaviour)target);
HeadOnly = serializedObject.FindProperty("BoneOnly");
HeadName = serializedObject.FindProperty("BoneName");
RemoveAnimalOnActive = serializedObject.FindProperty("RemoveAnimalOnActive");
layer = serializedObject.FindProperty("Layer");
Flip = serializedObject.FindProperty("Flip");
stateStatus = serializedObject.FindProperty("stateStatus");
OnZoneFailed = serializedObject.FindProperty("OnZoneFailed");
DisableAfterUsed = serializedObject.FindProperty("DisableAfterUsed");
Force = serializedObject.FindProperty("Force");
EnterAceleration = serializedObject.FindProperty("EnterAceleration");
ExitAceleration = serializedObject.FindProperty("ExitDrag");
Bounce = serializedObject.FindProperty("LimitForce");
ForceGrounded = serializedObject.FindProperty("ForceGrounded");
ForceAirControl = serializedObject.FindProperty("ForceAirControl");
m_abilityStatus = serializedObject.FindProperty("m_abilityStatus");
AbilityTime = serializedObject.FindProperty("AbilityTime");
Angle = serializedObject.FindProperty("Angle");
Weight = serializedObject.FindProperty("Weight");
DoubleSide = serializedObject.FindProperty("DoubleSide");
m_tag = serializedObject.FindProperty("tags");
ModeFloat = serializedObject.FindProperty("ModeFloat");
zoneType = serializedObject.FindProperty("zoneType");
stateID = serializedObject.FindProperty("stateID");
stateAction = serializedObject.FindProperty("stateAction");
stanceAction = serializedObject.FindProperty("stanceAction");
modeID = serializedObject.FindProperty("modeID");
stanceID = serializedObject.FindProperty("stanceID");
modeIndex = serializedObject.FindProperty("modeIndex");
ActionID = serializedObject.FindProperty("ActionID");
auto = serializedObject.FindProperty("automatic");
debug = serializedObject.FindProperty("debug");
ZoneCollider = serializedObject.FindProperty("ZoneCollider");
Editor_Tabs1 = serializedObject.FindProperty("Editor_Tabs1");
OnEnter = serializedObject.FindProperty("OnEnter");
OnExit = serializedObject.FindProperty("OnExit");
OnZoneActivation = serializedObject.FindProperty("OnZoneActivation");
if (ZoneCollider.objectReferenceValue == null)
{
ZoneCollider.objectReferenceValue = m.GetComponent<Collider>();
serializedObject.ApplyModifiedProperties();
}
}
public override void OnInspectorGUI()
{
serializedObject.Update();
MalbersEditor.DrawDescription("Area to modify States, Stances or Modes on an Animal");
EditorGUILayout.BeginVertical(MalbersEditor.StyleGray);
{
EditorGUILayout.BeginHorizontal();
Editor_Tabs1.intValue = GUILayout.Toolbar(Editor_Tabs1.intValue, Tabs1);
MalbersEditor.DrawDebugIcon(debug);
EditorGUILayout.EndHorizontal();
EditorGUI.BeginChangeCheck();
if (Editor_Tabs1.intValue == 0)
{
DrawGeneral();
}
else
{
DrawEvents();
}
if (EditorGUI.EndChangeCheck())
{
Undo.RecordObject(target, "Zone Changed");
EditorUtility.SetDirty(target);
}
if (Application.isPlaying && debug.boolValue)
{
EditorGUI.BeginDisabledGroup(true);
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.LabelField("Debug", EditorStyles.boldLabel);
if (m.ZoneCollider) EditorGUILayout.ObjectField("Zone Collider", m.ZoneCollider, typeof(Collider), false);
EditorGUILayout.LabelField("Current Animals (" + m.CurrentAnimals.Count + ")", EditorStyles.boldLabel);
foreach (var item in m.CurrentAnimals)
{
EditorGUILayout.ObjectField(item.name, item, typeof(MAnimal), false);
}
EditorGUILayout.LabelField("Current Colliders (" + m.m_Colliders.Count + ")", EditorStyles.boldLabel);
foreach (var item in m.m_Colliders)
{
EditorGUILayout.ObjectField(item.name, item, typeof(Collider), false);
}
EditorGUILayout.EndVertical();
Repaint();
EditorGUI.EndDisabledGroup();
}
}
EditorGUILayout.EndVertical();
serializedObject.ApplyModifiedProperties();
}
private void DrawGeneral()
{
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
EditorGUILayout.PropertyField(auto, new GUIContent("Automatic"));
EditorGUILayout.PropertyField(DisableAfterUsed);
EditorGUILayout.PropertyField(ZoneCollider, new GUIContent("Trigger"));
EditorGUILayout.PropertyField(layer);
EditorGUILayout.PropertyField(zoneType);
ZoneType zone = (ZoneType)zoneType.intValue;
switch (zone)
{
case ZoneType.Mode:
EditorGUILayout.PropertyField(modeID,
new GUIContent("Mode ID: [" + (m.modeID ? m.modeID.ID.ToString() : "") + "]", "Which Mode to Set when entering the Zone"));
serializedObject.ApplyModifiedProperties();
if (m.modeID != null && m.modeID == 4)
{
EditorGUILayout.PropertyField(ActionID,
new GUIContent("Action Index: [" + (m.ActionID ? m.ActionID.ID.ToString() : "") + "]", "Which Action to Set when entering the Zone"));
if (ActionID.objectReferenceValue == null)
{
EditorGUILayout.HelpBox("Please Select an Action ID", MessageType.Error);
}
}
else
{
EditorGUILayout.PropertyField(modeIndex, new GUIContent("Ability Index", "Which Ability to Set when entering the Zone"));
}
EditorGUILayout.PropertyField(m_abilityStatus, new GUIContent("Status", "Mode Ability Status"));
if (m_abilityStatus.intValue == (int)AbilityStatus.ActiveByTime)
{
EditorGUILayout.PropertyField(AbilityTime);
}
EditorGUILayout.PropertyField(ModeFloat, new GUIContent("Mode Power"));
break;
case ZoneType.State:
EditorGUILayout.PropertyField(stateID, new GUIContent("State ID", "Which State will Activate when entering the Zone"));
EditorGUILayout.PropertyField(stateAction, new GUIContent("Option", "Execute a State logic when the animal enters the zone"));
int stateaction = stateAction.intValue;
if (MTools.CompareOR(stateaction, (int)StateAction.Activate, (int)StateAction.ForceActivate, (int)StateAction.SetExitStatus))
{
EditorGUILayout.PropertyField(stateStatus, new GUIContent("State Status"));
}
if (stateID.objectReferenceValue == null)
{
EditorGUILayout.HelpBox("Please Select an State ID", MessageType.Error);
}
break;
case ZoneType.Stance:
EditorGUILayout.PropertyField(stanceID, new GUIContent("Stance ID", "Which Stance will Activate when entering the Zone"));
EditorGUILayout.PropertyField(stanceAction, new GUIContent("Status", "Execute a Stance logic when the animal enters the zone"));
if (stanceID.objectReferenceValue == null)
{
EditorGUILayout.HelpBox("Please Select an Stance ID", MessageType.Error);
}
break;
case ZoneType.Force:
EditorGUILayout.PropertyField(Force);
EditorGUILayout.PropertyField(EnterAceleration);
EditorGUILayout.PropertyField(ExitAceleration);
EditorGUILayout.PropertyField(Bounce);
EditorGUILayout.PropertyField(ForceAirControl, new GUIContent("Air Control"));
EditorGUILayout.PropertyField(ForceGrounded, new GUIContent("Grounded? "));
break;
default:
break;
}
EditorGUILayout.EndVertical();
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
{
EditorGUILayout.PropertyField(Weight);
EditorGUILayout.PropertyField(Angle);
if (Angle.floatValue != 360)
{
EditorGUILayout.PropertyField(DoubleSide);
EditorGUILayout.PropertyField(Flip);
}
EditorGUILayout.PropertyField(RemoveAnimalOnActive,
new GUIContent("Reset on Active", "Remove the stored Animal on the Zone when the Zones gets Active, Reseting it to its default state"));
EditorGUI.indentLevel++;
EditorGUILayout.PropertyField(m_tag,
new GUIContent("Tags", "Set this parameter if you want the zone to Interact only with gameObject with that tag"));
EditorGUI.indentLevel--;
EditorGUILayout.PropertyField(HeadOnly,
new GUIContent("Bone Only", "Activate when a bone enter the Zone.\nThat Bone needs a collider!!"));
if (HeadOnly.boolValue)
EditorGUILayout.PropertyField(HeadName,
new GUIContent("Bone Name", "Name for the Bone you need to check if it has enter the zone"));
}
EditorGUILayout.EndVertical();
}
private void DrawEvents()
{
EditorGUILayout.BeginVertical(EditorStyles.helpBox);
{
EditorGUILayout.PropertyField(OnEnter, new GUIContent("On Animal Enter Zone"));
EditorGUILayout.PropertyField(OnExit, new GUIContent("On Animal Exit Zone"));
EditorGUILayout.PropertyField(OnZoneActivation, new GUIContent("On Zone Active"));
EditorGUILayout.PropertyField(OnZoneFailed, new GUIContent("On Zone Failed"));
}
EditorGUILayout.EndVertical();
}
private void OnSceneGUI()
{
var angle = Angle.floatValue;
if (angle != 360)
{
angle /= 2;
var Direction = m.transform.forward * (Flip.boolValue ? -1 : 1);
Handles.color = new Color(0, 1, 0, 0.1f);
Handles.DrawSolidArc(m.transform.position, m.transform.up, Quaternion.Euler(0, -angle, 0) * Direction, angle * 2, m.transform.localScale.y);
Handles.color = Color.green;
Handles.DrawWireArc(m.transform.position, m.transform.up, Quaternion.Euler(0, -angle, 0) * Direction, angle * 2, m.transform.localScale.y);
if (DoubleSide.boolValue)
{
Handles.color = new Color(0, 1, 0, 0.1f);
Handles.DrawSolidArc(m.transform.position, m.transform.up, Quaternion.Euler(0, -angle, 0) * -Direction, angle * 2, m.transform.localScale.y);
Handles.color = Color.green;
Handles.DrawWireArc(m.transform.position, m.transform.up, Quaternion.Euler(0, -angle, 0) * -Direction, angle * 2, m.transform.localScale.y);
}
}
}
}
#endif
}