/// <summary>
        /// Sets up a new scene for pattern creation. This method will set up a capsule with a body coordinate system, a line
        /// renderer for the haptic points, and the GUI and listeners needed to manage the new pattern.
        /// </summary>
        /// <param name="previousSceneName">The string of the scene that the user needs to return to when the leave this Scene UI</param>
        public void SetupCapsuleScene(string previousSceneName)
        {
            previousScene = previousSceneName;

            // Don't allow playmode to be entered while in this scene
            EditorApplication.playModeStateChanged += EditorApplication_playModeStateChanged;

            // Hook into mouse events from the scene
            hitListener              = new BodyHitListener();
            hitListener.BodyPartHit += HitListener_BodyPartHit;

            // Set up the In-Scene GUI
            hapticSceneView = new HapticSceneViewGUI
            {
                patternWindow = this
            };

            // Connect to the OnGUI event cycle
            SceneView.onSceneGUIDelegate += OnGUIDelegate;

            // Set up the capsule
            capsuleGO = GameObject.CreatePrimitive(PrimitiveType.Capsule);
            capsuleGO.GetComponent <Renderer>().material = capsuleMaterial;
            capsuleGO.hideFlags   = HideFlags.HideInInspector;
            capsuleBodyCoordinate = capsuleGO.AddComponent <BodyCoordinate>();
            capsuleBodyCoordinate.drawGizmoUnselected = true;

            // Set up the line render for the active curve line
            GameObject lineHolder = new GameObject("Line Holder", typeof(LineRenderer));

            lineHolder.transform.parent = capsuleGO.transform;
            lineHolder.hideFlags        = HideFlags.HideInHierarchy;

            currentCurveLineRenderer = lineHolder.GetComponent <LineRenderer>();

            currentCurveLineRenderer.widthMultiplier           = lineRendererData.widthMultiplier;
            currentCurveLineRenderer.numCornerVertices         = lineRendererData.numCornerVertices;
            currentCurveLineRenderer.numCapVertices            = lineRendererData.numCapVertices;
            currentCurveLineRenderer.material                  = lineRendererData.lineMaterial;
            currentCurveLineRenderer.receiveShadows            = lineRendererData.receiveShadows;
            currentCurveLineRenderer.allowOcclusionWhenDynamic = lineRendererData.allowOcclusionWhenDynamic;
            currentCurveLineRenderer.startColor                = lineRendererData.lineStartColor;
            currentCurveLineRenderer.endColor                  = lineRendererData.lineEndColor;

            // Start with 0 points in the line
            currentCurveLineRenderer.positionCount = 0;

            // Focus the camera on the capsule
            Selection.activeGameObject = capsuleGO;
            SceneView.lastActiveSceneView.FrameSelected();

            // Start work on the haptic pattern
            currentPattern = ScriptableObject.CreateInstance <ScriptableHapticPattern>();
            AddNewCurve("Default");

            // Don't need the event listener for a new scene anymore, wait for when this scene closes
            setupComplete = true;
        }
        protected void ResetHapticPattern()
        {
            if (patternPlaying != null)
            {
                patternPlaying.hitOffset = new BodyCoordinateHit();
            }

            patternTime    = 0;
            patternPlaying = null;
        }
        /// <summary>
        /// Starts playing a pattern on a given bodypart
        /// </summary>
        /// <param name="bodyLocation">The body part to play the pattern on</param>
        /// <param name="pattern">The haptic pattern to play</param>
        public void PlayPattern(HumanBodyBones bodyLocation, ScriptableHapticPattern pattern)
        {
            patternPlaying = pattern;
            bodyPartHit    = bodyLocation;
            patternTime    = 0.0f;

            if (patternPlaying.playbackTiming == PlaybackTiming.Custom)
            {
                StartCoroutine(Play());
            }
        }
        private void ResetPattern()
        {
            // Go through each GameObject and destroy it
            foreach (var bodyHitList in bodyHitsPerCurve)
            {
                for (int n = 0; n < bodyHitList.Value.Count; n++)
                {
                    DestroyImmediate(bodyHitList.Value[n].gameObject);
                }
            }

            // Empty the dictionary of all the values
            bodyHitsPerCurve.Clear();

            // Reset the index to 0
            CurveIndex = 0;

            currentPattern = null;
        }
        /// <summary>
        /// Load a saved haptic pattern and set it to be the active pattern to work on
        /// </summary>
        /// <param name="loadedPattern">The pattern to load</param>
        public void LoadPattern(ScriptableHapticPattern loadedPattern)
        {
            ResetPattern();

            currentPattern = loadedPattern;

            // Load each curve information from the pattern
            for (int n = 0; n < loadedPattern.curveList.Count; n++)
            {
                bodyHitsPerCurve.Add(n, new List <BodyHitUI>());

                AddCurveToDictionary(n, loadedPattern.curveList[n]);

                UpdateCurveKeyFrameVisualization(n, false);
            }

            // Make the first curve active
            UpdateCurveKeyFrameVisualization(0, true);
        }
예제 #6
0
        /// <summary>
        /// Plays a specified haptic pattern on a specific body part. Use this method if one
        /// simply needs to give a notification to a body part through scripting.
        /// </summary>
        /// <param name="bodyLocation">The body part to notify</param>
        /// <param name="pattern">The haptic pattern to play</param>
        public void PlayPattern(HumanBodyBones bodyLocation, ScriptableHapticPattern pattern)
        {
            // Check to make sure this body part isn't ignored
            if (ignoreBoneSet.Contains(bodyLocation))
            {
                return;
            }

            if (bodyAffectedByDevice.ContainsKey(bodyLocation))
            {
                // Tell every device that has this body part to play the pattern
                for (int n = 0; n < bodyAffectedByDevice[bodyLocation].Count; n++)
                {
                    // Check to make sure this haptic device isn't ignored
                    if (ignoreHapticDevices.Contains(bodyAffectedByDevice[bodyLocation][n]))
                    {
                        return;
                    }

                    bodyAffectedByDevice[bodyLocation][n].PlayPattern(bodyLocation, pattern);
                }
            }
        }
예제 #7
0
        /// <summary>
        /// Checks to see if the given body part that was hit has a device that should be triggered. If it does,
        /// it tells that device to play their haptic for that hit location.
        /// </summary>
        /// <param name="bodyLocation">The body part that was hit</param>
        /// <param name="hitLocation">The height/angle of the hit on the body part</param>
        public void BodyPartHit(HumanBodyBones bodyLocation, BodyCoordinateHit hitLocation, ScriptableHapticPattern hapticPattern = null)
        {
            // Check to make sure this body part isn't ignored
            if (ignoreBoneSet.Contains(bodyLocation))
            {
                return;
            }

            if (bodyAffectedByDevice.ContainsKey(bodyLocation))
            {
                // Tell every device that has this body part to trigger the haptics at the given location
                for (int n = 0; n < bodyAffectedByDevice[bodyLocation].Count; n++)
                {
                    // Check to make sure this haptic device isn't ignored
                    if (ignoreHapticDevices.Contains(bodyAffectedByDevice[bodyLocation][n]))
                    {
                        return;
                    }

                    if (hapticPattern == null)
                    {
                        bodyAffectedByDevice[bodyLocation][n].TriggerDevice(bodyLocation, hitLocation, 0.5f);
                    }
                    else
                    {
                        bodyAffectedByDevice[bodyLocation][n].TriggerDevice(bodyLocation, hitLocation, hapticPattern);
                    }
                }
            }
        }
 /// <summary>
 /// Updates the selected pattern from a dropdown menu
 /// </summary>
 /// <param name="target">The dropdown menu that has the list of available patterns</param>
 public void DropdownPatternSelection(Dropdown target)
 {
     selectedPattern = availablePatterns[target.value];
 }
        /// <summary>
        /// Plays a pattern that is triggered by an object hitting a body part that has been
        /// set up to recieve haptic events.
        /// </summary>
        /// <param name="bodyPart">The body part of the hit</param>
        /// <param name="hitLocation">The body coordinate system hit</param>
        /// <param name="hapticPattern">The haptic pattern</param>
        public void TriggerDevice(HumanBodyBones bodyPart, BodyCoordinateHit hitLocation, ScriptableHapticPattern hapticPattern)
        {
            if (bodyPart == affectedBodyPart.affectableBodyParts)
            {
                hapticPattern.hitOffset = hitLocation;

                PlayPattern(bodyPart, hapticPattern);
            }
        }
예제 #10
0
        /// <summary>
        /// Handles how to render the actual elements of the UI
        /// </summary>
        public void RenderSceneGUI(SceneView sceneview)
        {
            Handles.BeginGUI();

            // Make a canvas that spans the entire height of the scene and a portion of the width
            Rect canvasRect = new Rect(0, 0, Screen.width / UI_SCREEN_WIDTH, Screen.height);

            GUILayout.BeginArea(canvasRect);

            // Make the area behind the GUI a gray, slightly transparent canvas
            EditorGUI.DrawRect(canvasRect, new Color(0.5f, 0.5f, 0.5f, 0.5f));

            Rect verticleLayoutBox = EditorGUILayout.BeginVertical();

            GUI.Box(verticleLayoutBox, GUIContent.none);

            // Add header for loading/saving patterns
            EditorGUILayout.Space();
            EditorGUILayout.HelpBox("Pattern Management", MessageType.None);

            // Load a saved pattern
            EditorGUILayout.LabelField("Load Saved Pattern:", textLabelStyle);
            patternToLoad = EditorGUILayout.ObjectField(patternToLoad, typeof(ScriptableHapticPattern), false) as ScriptableHapticPattern;

            if (patternToLoad != null)
            {
                if (GUILayout.Button("Load Pattern"))
                {
                    LoadPattern();

                    patternToLoad = null;
                }
            }

            // Save changes and return to previous scene
            if (GUILayout.Button("Save and return"))
            {
                patternWindow.SavePattern(patternName, selectedCollisionResolution, collisionResolutionIndex, selectedPlaybackTiming, customPlaybackTiming, selectedOffsetUse, selectedHeightOvershoot, selectedAngleOvershoot);
            }

            // Save the background color to temporarily change the discard background to red to indicate the negative nature of the button
            Color oldColor = GUI.backgroundColor;

            GUI.backgroundColor = Color.red;

            // Discard all the changes and return to previous scene
            if (GUILayout.Button("Discard changes"))
            {
                bool discardResult = EditorUtility.DisplayDialog("Discard changes?",
                                                                 "Are you sure you want to discard all changes made to this pattern?",
                                                                 "Yes",
                                                                 "Cancel");

                if (discardResult)
                {
                    patternWindow.DiscardChanges();
                }
            }

            GUI.backgroundColor = oldColor;

            // Add header for pattern settings
            EditorGUILayout.Space();
            EditorGUILayout.HelpBox("Pattern Settings", MessageType.None);

            // Prompt for pattern name which will become the file name
            EditorGUILayout.LabelField("Pattern Name:", textLabelStyle);
            patternName = EditorGUILayout.TextField(patternName);

            // Prompt for how to handle intensity collisions
            EditorGUILayout.LabelField("Collision Resolution:", textLabelStyle);
            selectedCollisionResolution = (PatternCollisionResolution)EditorGUILayout.EnumPopup(selectedCollisionResolution);

            // Prompt for the index of the curve to use if the resolution is set to CurvePriority
            if (selectedCollisionResolution == PatternCollisionResolution.CurvePriority)
            {
                EditorGUILayout.LabelField("Curve Index:", textLabelStyle);
                collisionResolutionIndex = EditorGUILayout.IntField(collisionResolutionIndex);
            }

            // Prompt for the playback timing on the pattern
            EditorGUILayout.LabelField("Playback Timing:", textLabelStyle);
            selectedPlaybackTiming = (PlaybackTiming)EditorGUILayout.EnumPopup(selectedPlaybackTiming);

            // Prompt for custom playback timing if they have selected CustomPlayback as the option
            if (selectedPlaybackTiming == PlaybackTiming.Custom)
            {
                EditorGUILayout.LabelField("Custom Playback Time:", textLabelStyle);
                customPlaybackTiming = EditorGUILayout.FloatField(customPlaybackTiming);
            }

            // Prompt for offset use
            EditorGUILayout.LabelField("Offset Use:", textLabelStyle);
            selectedOffsetUse = (OffsetUse)EditorGUILayout.EnumPopup(selectedOffsetUse);

            // Prompt for height overshoot
            EditorGUILayout.LabelField("Height Overshoot Resolution:", textLabelStyle);
            selectedHeightOvershoot = (PatternOvershootResolution)EditorGUILayout.EnumPopup(selectedHeightOvershoot);

            // Prompt for angle overshoot
            EditorGUILayout.LabelField("Angle Overshoot Resolution:", textLabelStyle);
            selectedAngleOvershoot = (PatternOvershootResolution)EditorGUILayout.EnumPopup(selectedAngleOvershoot);

            // Header for management curves
            EditorGUILayout.Space();
            EditorGUILayout.HelpBox("Curve Management", MessageType.None);

            // Build string list of attached curves
            string[] curveNames = new string[patternWindow.HapticPattern.curveList.Count];

            for (int n = 0; n < patternWindow.HapticPattern.curveList.Count; n++)
            {
                curveNames[n] = patternWindow.HapticPattern.curveList[n].ToString();
            }

            // Show list of curves on the pattern for the user to select
            EditorGUILayout.LabelField("Current curve:", textLabelStyle);
            patternWindow.CurveIndex = EditorGUILayout.Popup(patternWindow.CurveIndex, curveNames);

            // Allow the user to add a new curve
            if (GUILayout.Button("Add New Curve"))
            {
                patternWindow.AddNewCurve("Default");
            }

            if (GUILayout.Button("Remove Current Curve"))
            {
                patternWindow.RemoveCurrentCurve();
            }

            // Add selected curve to pattern button
            EditorGUILayout.LabelField("Add Saved Curve:", textLabelStyle);
            curveToAdd = EditorGUILayout.ObjectField(curveToAdd, typeof(ScriptableHapticCurve), false) as ScriptableHapticCurve;

            if (curveToAdd != null)
            {
                if (GUILayout.Button("Add Curve"))
                {
                    patternWindow.AddSavedCurve(curveToAdd);

                    curveToAdd = null;
                }
            }

            EditorGUILayout.EndVertical();
            GUILayout.EndArea();
            Handles.EndGUI();
        }