using MalbersAnimations.Scriptables; using System.Collections; using UnityEngine; using UnityEngine.Events; using MalbersAnimations.Events; #if UNITY_EDITOR using UnityEditor; #endif namespace MalbersAnimations.Utilities { [DefaultExecutionOrder(15)] [SelectionBase] [AddComponentMenu("Malbers/Interaction/Interactable")] [HelpURL("https://malbersanimations.gitbook.io/animal-controller/global-components/interactable")] public class MInteract : UnityUtils, IInteractable { [Tooltip("Own Index. This is used to Identify each Interactable. (Used on UnityEvents)")] //[UnityEngine.Serialization.FormerlySerializedAs("m_ID")] public IntReference m_ID = new IntReference(0); [Tooltip("ID for the Interactor. Makes this Interactable to interact only with Interactors with this ID Value\n" + "By default its -1, which means that can be activated by anyone")] [UnityEngine.Serialization.FormerlySerializedAs("m_InteracterID")] public IntReference m_InteractorID = new IntReference(-1); [Tooltip("If the Interactor has this Interactable focused, it will interact with it automatically.\n" + "It also is used by the AI Animals. If the Animal Reaches this gameobject to Interact with it this needs to be set to true")] [SerializeField] private BoolReference m_Auto = new BoolReference(false); [Tooltip("Interact Once, after that it cannot longer work, unlest the Interactable is Restarted. Disable the component")] [SerializeField] private BoolReference m_singleInteraction = new BoolReference(false); [Tooltip("Delay time to activate the events on the Interactable")] public FloatReference m_Delay = new FloatReference(0); [Tooltip("CoolDown between Interactions when the Interactable is NOT a Single/One time interaction")] public FloatReference m_CoolDown = new FloatReference(0); [Tooltip("When an Interaction is executed these events will be invoked." + "\n\nOnInteractWithGO(GameObject) -> will have the *INTERACTER* gameObject as parameter" + "\n\nOnInteractWith(Int) -> will have the *INTERACTER* ID as parameter")] public InteractionEvents events = new InteractionEvents(); public GameObjectEvent OnFocused = new GameObjectEvent(); public GameObjectEvent OnUnfocused = new GameObjectEvent(); public int Index => m_ID; public bool Active { get => enabled && !InCooldown; set => enabled = value; } public bool SingleInteraction { get => m_singleInteraction.Value; set => m_singleInteraction.Value = value; } public bool Auto { get => m_Auto.Value; set => m_Auto.Value = value; } // public bool Active { get =>enabled; set => enabled = value; } /// Delay time to Activate the Interaction on the Interactable public float Delay { get => m_Delay.Value; set => m_Delay.Value = value; } /// CoolDown Between Interactions public float Cooldown { get => m_CoolDown.Value; set => m_CoolDown.Value = value; } /// Is the Interactable in CoolDown? public bool InCooldown => !MTools.ElapsedTime(CurrentActivationTime, Cooldown); public IInteractor CurrentInteractor { get; set; } private bool focused; public bool Focused { get => focused; set { if (focused != value) { focused = value; if (focused) { OnFocused.Invoke(CurrentInteractor != null ? CurrentInteractor.Owner : null); } else { OnUnfocused.Invoke(CurrentInteractor != null ? CurrentInteractor.Owner : null); } } } } public GameObject Owner => gameObject; private float CurrentActivationTime; public string Description = "Invoke events when an Interactor interacts with it"; [HideInInspector] public bool ShowDescription = true; [ContextMenu("Show Description")] internal void EditDescription() => ShowDescription ^= true; private void OnEnable() { CurrentActivationTime = -Cooldown; } private void OnDisable() { focused = false; CurrentInteractor?.UnFocus(this); //Clean the Current Focused item } /// Receive an Interaction from the Interacter /// ID of the Interacter /// Interacter's GameObject public bool Interact(int InteracterID, GameObject interacter) { if (Active) { if (m_InteractorID <= 0 || m_InteractorID == InteracterID) //Check for Interactor ID { CurrentActivationTime = Time.time; this.Delay_Action(Delay, () => { events.OnInteractWithGO.Invoke(interacter); events.OnInteractWith.Invoke(InteracterID); } ); if (SingleInteraction) { Focused = false; Active = false; } return true; } return false; } return false; } /// Receive an Interaction from an gameObject /// ID of the Interacter /// Interacter's GameObject public bool Interact(IInteractor interacter) { if (interacter != null) return Interact(interacter.ID, interacter.Owner.gameObject); return false; } public void Interact() => Interact(-1, null); public virtual void Restart() { Focused = false; Active = true; CurrentActivationTime = -Cooldown; } [SerializeField] private int Editor_Tabs1; } #if UNITY_EDITOR [UnityEditor.CustomEditor(typeof(MInteract)),CanEditMultipleObjects] public class MInteractEditor : UnityEditor.Editor { SerializedProperty m_ID, m_InteractorID, m_Auto, m_singleInteraction, m_Delay, m_CoolDown, events, OnFocused, OnUnfocused, Editor_Tabs1, Description, ShowDescription; protected string[] Tabs1 = new string[] { "General", "Events" }; MInteract M; public static GUIStyle StyleBlue => MTools.Style(new Color(0, 0.5f, 1f, 0.3f)); private GUIStyle style; private void OnEnable() { M = (MInteract)target; m_ID = serializedObject.FindProperty("m_ID"); m_InteractorID = serializedObject.FindProperty("m_InteractorID"); m_Auto = serializedObject.FindProperty("m_Auto"); m_singleInteraction = serializedObject.FindProperty("m_singleInteraction"); m_Delay = serializedObject.FindProperty("m_Delay"); m_CoolDown = serializedObject.FindProperty("m_CoolDown"); events = serializedObject.FindProperty("events"); OnFocused = serializedObject.FindProperty("OnFocused"); OnUnfocused = serializedObject.FindProperty("OnUnfocused"); Editor_Tabs1 = serializedObject.FindProperty("Editor_Tabs1"); ShowDescription = serializedObject.FindProperty("ShowDescription"); Description = serializedObject.FindProperty("Description"); } public override void OnInspectorGUI() { serializedObject.Update(); if (ShowDescription.boolValue) { if (style == null) { style = new GUIStyle(StyleBlue) { fontSize = 12, fontStyle = FontStyle.Bold, alignment = TextAnchor.MiddleLeft, stretchWidth = true }; } style.normal.textColor = EditorStyles.label.normal.textColor; Description.stringValue = UnityEditor.EditorGUILayout.TextArea(Description.stringValue, style); } //MalbersEditor.DrawDescription("Interactable Element that invoke events when an Interactor interact with it"); Editor_Tabs1.intValue = GUILayout.Toolbar(Editor_Tabs1.intValue, Tabs1); if (Editor_Tabs1.intValue == 0) DrawGeneral(); else DrawEvents(); if (Application.isPlaying) { EditorGUI.BeginDisabledGroup(true); EditorGUILayout.ObjectField("Interactor", M.CurrentInteractor != null ? M.CurrentInteractor.Owner : null, typeof(GameObject), false); EditorGUI.EndDisabledGroup(); } serializedObject.ApplyModifiedProperties(); } private void DrawGeneral() { EditorGUILayout.BeginVertical(EditorStyles.helpBox); { EditorGUILayout.PropertyField(m_InteractorID, new GUIContent("Interactor ID")); EditorGUILayout.PropertyField(m_ID, new GUIContent("Index")); EditorGUILayout.PropertyField(m_Auto,new GUIContent("Auto Interact")); EditorGUILayout.PropertyField(m_singleInteraction, new GUIContent("Single Interaction")); EditorGUILayout.PropertyField(m_Delay); if (!M.SingleInteraction) EditorGUILayout.PropertyField(m_CoolDown, new GUIContent("Cooldown")); } EditorGUILayout.EndVertical(); EditorGUIUtility.labelWidth = 0; } private void DrawEvents() { EditorGUILayout.PropertyField(events, true); if (events.isExpanded) { EditorGUILayout.PropertyField(OnFocused); EditorGUILayout.PropertyField(OnUnfocused); } } } #endif }