using NextMind.Examples.Steps; using NextMind.NeuroTags; using System.Collections; using System.Collections.Generic; using UnityEngine; namespace NextMind.Examples.Discovery { public class CutPasteStep : AbstractStep { /// /// The zones where to paste the cut objects. /// [SerializeField] private List availablePositions = null; /// /// The objects to cut and paste. /// [SerializeField] private List interactibleObjects = null; /// /// The currently selected object. /// private NeuroTag selectedObject; #region AbstractStep implementation public override void OnEnterStep() { base.OnEnterStep(); // Place the objects on the first positions. for (int i = 0; i < interactibleObjects.Count; i++) { selectedObject = interactibleObjects[i].GetComponent(); OnTriggerPosition(availablePositions[i]); } // Disactivate the positions. SetPositionsActive(false); } #endregion #region NeuroTag events /// /// Called when a user focus on an object to cut it. /// /// The focused object public void OnTriggerObject(NeuroTag neuroTag) { // Store the object. selectedObject = neuroTag; // Activate the zones so the user can paste the cut object. SetPositionsActive(true); // Make the object disappear by scaling it smoothly to zero. StartCoroutine(SmoothScale(false,selectedObject.transform)); // Disactive all the objects NeuroTags. foreach (var c in interactibleObjects) { c.GetComponent().enabled = false; } } /// /// Called when used focus on a zone, to paste the object he just cut. /// /// The focused zone public void OnTriggerPosition(PasteContainer zone) { // If we did not cut an object, leave the function. if (selectedObject == null) { return; } // Remove from old position. for (int i = 0; i < availablePositions.Count; i++) { if (availablePositions[i].containedGameObject == selectedObject.gameObject) { availablePositions[i].OnChangeContent(null); break; } } // Link the object to the chosen zone. zone.OnChangeContent(selectedObject.gameObject); // Disactivate all the zones. SetPositionsActive(false); // Make the pasted object reappear smoothly by scaling it up. StartCoroutine(SmoothScale(true, selectedObject.transform)); // Active all the objects neurotags foreach (var c in interactibleObjects) { NeuroTag tag = c.GetComponent(); if (tag != selectedObject) { tag.enabled = true; } } // Active the NeuroTag on the pasted object after a few second. // If it is reactivated directly, it can happen than the user focus on it and trigger it too quickly. StartCoroutine(DelayedActivation(selectedObject)); selectedObject = null; } #endregion /// /// Set the position active or inactive regarding their content. /// If true, activate only the free zones, which are not the one where we just cut object. /// /// private void SetPositionsActive(bool active) { for (int i = 0; i < availablePositions.Count; i++) { PasteContainer pos = availablePositions[i]; pos.gameObject.SetActive(active && (pos.IsFree || (selectedObject!=null && pos.containedGameObject == selectedObject.gameObject))); } } /// /// Smoothly scale up or down the passed in parameter. /// /// Scale up if true, scale down otherwise /// The transform to scale private IEnumerator SmoothScale(bool scaleUp, Transform target) { float duration = 0.3f; float timer = 0; float t = 0; AnimationCurve curve = AnimationCurve.EaseInOut(0, 0, 1, 1); Vector3 startScale = target.localScale; Vector3 targetScale = scaleUp ? 0.5f * Vector3.one : Vector3.zero; while (t < 1) { target.localScale = Vector3.Lerp(startScale,targetScale, curve.Evaluate(t)); timer += Time.deltaTime; t = timer / duration; yield return null; } target.localScale = targetScale; } /// /// Active the tag passed in parameters after a fixed delay. /// /// The tag to activate. private IEnumerator DelayedActivation(NeuroTag tag) { yield return new WaitForSeconds(2f); // Reactivate the NeuroTag only if there are no other selected object. if (selectedObject == null) { tag.enabled = true; } } } }