Exemple #1
0
        void OnEnable()
        {
            Foliage2D foliage = (Foliage2D)target;

            if (foliage.GetComponent <MeshFilter>().sharedMesh == null)
            {
                foliage.RebuildMesh();
            }
        }
Exemple #2
0
        static void AddGrassPatch()
        {
            GameObject obj  = new GameObject("New Foliage2D_Object");
            Foliage2D  path = obj.AddComponent <Foliage2D>();

            obj.AddComponent <Foliage2D_Animation>();

            path.SetDefaultMaterial();
            path.RebuildMesh();

            obj.transform.position = GetSpawnPos();

            Selection.activeGameObject = obj;
            EditorGUIUtility.PingObject(obj);
        }
Exemple #3
0
        void Start()
        {
            animator         = GetComponent <Animator>();
            foliage2D        = GetComponent <Foliage2D>();
            meshFilter       = GetComponent <MeshFilter>().sharedMesh;
            initialVertexPos = meshFilter.vertices;
            horizontalVerts  = foliage2D.widthSegments + 1;
            finalVertexPos   = meshFilter.vertices;
            collider2DObject = new List <Collider2D>();
            collider3DObject = new List <Collider>();
            enterOffset      = new List <float>();
            anglesInDeg      = new float[foliage2D.heightSegments + 1];
            posOffset        = new Vector3[foliage2D.heightSegments + 1];
            centerLinePoints = new Vector2[foliage2D.heightSegments + 1];

            // We change the default speed of the animation and then reset it
            // back so that the motion of different foliage objects isn't synchronized.
            // This will produce a more realistic behaviour.
            if (animator != null && changeAnimationSpeed)
            {
                StartCoroutine(SetAnimationSpeed());
            }

            // This is a safeguard to eliminate the "Index out of Range Exception" errors
            // that may be generated when the object in the scene is a prefab instance
            // and the user forgot to save the changes he made to it.
            if (offsetFactor.Count != foliage2D.heightSegments + 1)
            {
                offsetFactor.Clear();
                int   len    = foliage2D.heightSegments + 1;
                float offset = 1f / foliage2D.heightSegments;

                for (int i = 0; i < len; i++)
                {
                    offsetFactor.Add(offset * i);
                }
            }
        }
Exemple #4
0
        private void CustomInspector(Foliage2D_Animation anim)
        {
            Undo.RecordObject(target, "Modified Inspector");

            showProperties = EditorGUILayout.Foldout(showProperties, "Animation");

            if (showProperties)
            {
                EditorGUI.indentLevel = 1;
                InspectorBox(10, () =>
                {
                    anim.foliageBending = (Foliage2D_MeshBending)EditorGUILayout.EnumPopup(new GUIContent("Mesh Bending ", "Describes the type of bending that should be applied to the foliage mesh."), anim.foliageBending);

                    anim.changeAnimationSpeed = EditorGUILayout.Toggle(new GUIContent("Asynchronous Anim Start", "When set to true, the speed of the animation is changed for a short period of time. "
                                                                                      + "This change takes place only once at the start of the game. This is useful if you don't want the foliage objects to have synchronous animations."), anim.changeAnimationSpeed);
                    if (anim.changeAnimationSpeed)
                    {
                        anim.minSpeed = EditorGUILayout.FloatField(new GUIContent("Min Speed", "The min value for a random number used to change the playback speed of an animation."), anim.minSpeed);
                        anim.maxSpeed = EditorGUILayout.FloatField(new GUIContent("Max Speed", "The max value for a random number used to change the playback speed of an animation."), anim.maxSpeed);

                        anim.minSeconds = EditorGUILayout.FloatField(new GUIContent("Min Seconds", "The min value for a random number. The value of this "
                                                                                    + "number determines how many seconds should the animation speed offset last."), anim.minSeconds);
                        anim.maxSeconds = EditorGUILayout.FloatField(new GUIContent("Max Seconds", "The max value for a random number. The value of this "
                                                                                    + " number determines how many seconds should the animation speed be offset."), anim.maxSeconds);
                    }
                });
            }
            EditorGUI.indentLevel = 0;

            showOffsetFactors = EditorGUILayout.Foldout(showOffsetFactors, "Offset Factors");

            if (showOffsetFactors)
            {
                EditorGUI.indentLevel = 1;
                InspectorBox(10, () =>
                {
                    Foliage2D foliage2D = anim.GetComponent <Foliage2D>();

                    if (anim.offsetFactor.Count != foliage2D.heightSegments + 1)
                    {
                        anim.offsetFactor.Clear();

                        int len      = foliage2D.heightSegments + 1;
                        float offset = 1f / foliage2D.heightSegments;

                        for (int i = 0; i < len; i++)
                        {
                            anim.offsetFactor.Add(offset * i);
                        }
                    }


                    for (int i = anim.offsetFactor.Count - 1; i >= 0; i--)
                    {
                        anim.offsetFactor[i] = EditorGUILayout.Slider(new GUIContent("Offset " + i, "Determines which part of the animated variable "
                                                                                     + " 'offset' will be used to calculate the new vertex position."), anim.offsetFactor[i], 0, 1);
                    }
                });
            }

            EditorGUI.indentLevel = 0;
        }
Exemple #5
0
        /// <summary>
        /// Custom inspector.
        /// </summary>
        private void CustomInspector(Foliage2D foliage2D)
        {
            Undo.RecordObject(target, "Modified Inspector");
            showVisuals = EditorGUILayout.Foldout(showVisuals, "Visual Properties");

            if (showVisuals)
            {
                EditorGUI.indentLevel = 1;
                InspectorBox(10, () =>
                {
                    foliage2D.pixelsPerUnit  = Mathf.Clamp(EditorGUILayout.FloatField(new GUIContent("Pixels To Units", "The number of pixels in 1 Unity unit."), foliage2D.pixelsPerUnit), 1, 768);
                    foliage2D.widthSegments  = Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("With Segments", "The number of columns the mesh has."), foliage2D.widthSegments), 1, 100);
                    foliage2D.heightSegments = Mathf.Clamp(EditorGUILayout.IntField(new GUIContent("Height Segments", "The number of rows the mesh has."), foliage2D.heightSegments), 1, 100);

                    Type utility = Type.GetType("UnityEditorInternal.InternalEditorUtility, UnityEditor");
                    if (utility != null)
                    {
                        PropertyInfo sortingLayerNames = utility.GetProperty("sortingLayerNames", BindingFlags.Static | BindingFlags.NonPublic);
                        if (sortingLayerNames != null)
                        {
                            string[] layerNames = sortingLayerNames.GetValue(null, null) as string[];
                            string currName     = foliage2D.GetComponent <Renderer>().sortingLayerName == "" ? "Default" : foliage2D.GetComponent <Renderer>().sortingLayerName;
                            int nameID          = EditorGUILayout.Popup("Sorting Layer", Array.IndexOf(layerNames, currName), layerNames);

                            foliage2D.GetComponent <Renderer>().sortingLayerName = layerNames[nameID];
                        }
                        else
                        {
                            foliage2D.GetComponent <Renderer>().sortingLayerID = EditorGUILayout.IntField("Sorting Layer", foliage2D.GetComponent <Renderer>().sortingLayerID);
                        }
                    }
                    else
                    {
                        foliage2D.GetComponent <Renderer>().sortingLayerID = EditorGUILayout.IntField("Sorting Layer", foliage2D.GetComponent <Renderer>().sortingLayerID);
                    }
                    foliage2D.GetComponent <Renderer>().sortingOrder = EditorGUILayout.IntField("Order in Layer", foliage2D.GetComponent <Renderer>().sortingOrder);
                });
            }
            EditorGUI.indentLevel = 0;

            if (GUILayout.Button("Rebuild Mesh"))
            {
                foliage2D.RebuildMesh();
            }

            if (GUI.changed)
            {
                EditorUtility.SetDirty(target);
                foliage2D.RebuildMesh();
            }

            if (Event.current.type == EventType.ValidateCommand)
            {
                switch (Event.current.commandName)
                {
                case "UndoRedoPerformed":
                    foliage2D.RebuildMesh();
                    break;
                }
            }
        }
Exemple #6
0
        // Inspector Fields
        public override void OnInspectorGUI()
        {
            Foliage2D foliage2D = (Foliage2D)target;

            CustomInspector(foliage2D);
        }
Exemple #7
0
        /// <summary>
        /// Fills the foliage path with objects.
        /// </summary>
        public void RecreateFoliage()
        {
            foliageCount          = foliageOnPath.Count;
            distanceFromStart     = 0;
            prevDistanceFromStart = 0;
            maxCount = 0;
            float ZAxisOffset = zOffset;

            List <GameObject> foliageP = new List <GameObject>();
            int len = foliagePrefabs.Count;

            foliageP.Clear();
            // The foliage prefabs are placed in a new list to make sure that there are no null fields.
            for (int k = 0; k < len; k++)
            {
                if (foliagePrefabs[k] != null)
                {
                    foliageP.Add(foliagePrefabs[k]);
                }
            }
            maxCount = foliageP.Count;

            // If the prefab list is empty return.
            if (maxCount == 0)
            {
                return;
            }
            objectIndex = 1;

            // Foliage objects are placed on the line described by the path nodes.
            for (int i = 0; i < handlesPosition.Count - 1; i++)
            {
                line       = handlesPosition[i + 1] - handlesPosition[i];
                angleInRad = Mathf.Atan2(line.y, line.x);
                angleInDeg = angleInRad * Mathf.Rad2Deg;
                lineLength = line.magnitude;
                // The vector is normalized so that we can calculate its normal correctly.
                line.Normalize();
                lineNormal            = new Vector2(-line.y, line.x);
                distanceFromStart     = 0;
                prevDistanceFromStart = 0;

                // This loop is executed until the distance between the start of the line and a
                // foliage object is smaller than the length of the line.
                while (true)
                {
                    updatedPrefabIndex = false;

                    // If a new object must be instantiated, updates the "prefabIndex" value.
                    // The value of "prefabIndex" determines which prefab will be instantiated
                    // in the current iteration.
                    if (foliageCount < objectIndex)
                    {
                        if (foliagePattern == Foliage2D_Pattern.Random)
                        {
                            // Get a random index.
                            prefabIndex = Random.Range(0, maxCount);
                        }
                        else
                        {
                            // The value of "prefabIndex" is incremented by 1 so that new objects are instantiated consecutively.
                            prefabIndex++;
                            // If the value of "prefab Index" is bigger than "maxCount" or smaller than 0, we reset it to 0.
                            if (prefabIndex >= maxCount || prefabIndex < 0)
                            {
                                prefabIndex = 0;
                            }
                        }

                        updatedPrefabIndex = true;
                        // We get the Foliage2D component of the prefab with the index of "prefabIndex"
                        // so that we have access to the width of the correct foliage object when we
                        // calculate the distance from the start of the line where this object will be placed.
                        foliage2D = foliageP[prefabIndex].GetComponent <Foliage2D>();
                        DistanceFromStart();
                    }
                    else
                    {
                        foliage2D = foliageOnPath[objectIndex - 1].GetComponent <Foliage2D>();
                        DistanceFromStart();
                    }

                    // If the distance from the start of the line where the last object was placed is
                    // bigger than the line length, the position of the object is reset and the execution
                    // of the while loop is terminated.
                    if (distanceFromStart > lineLength)
                    {
                        foliage2D         = foliageOnPath[prevIndex].GetComponent <Foliage2D>();
                        distanceFromStart = lineLength - foliage2D.width / 2f + lastObjectOffset;

                        if (foliagePathType == Foliage2D_PathType.Smooth)
                        {
                            SmoothPath(i);
                        }
                        else
                        {
                            pointOnTheLine = Vector2.Lerp(handlesPosition[i], handlesPosition[i + 1], distanceFromStart / lineLength);
                        }

                        posOffset = lineNormal * (foliage2D.height / 2f);
                        foliageOnPath[prevIndex].transform.position = transform.TransformPoint(new Vector3(pointOnTheLine.x + posOffset.x, pointOnTheLine.y + posOffset.y, ZAxisOffset));

                        if (updatedPrefabIndex && foliagePattern == Foliage2D_Pattern.Consecutive)
                        {
                            RestorePrefabIndex();
                        }

                        break;
                    }

                    if (foliagePathType == Foliage2D_PathType.Smooth)
                    {
                        SmoothPath(i);
                    }
                    else
                    {
                        pointOnTheLine = Vector2.Lerp(handlesPosition[i], handlesPosition[i + 1], distanceFromStart / lineLength);
                    }

                    if (foliageCount < objectIndex)
                    {
                        // If the index of the current object is bigger than the total number of
                        // instantiated objects, a new object is instantiated.
                        ZAxisOffset *= -1;
                        Vector3 pos = pointOnTheLine + posOffset;
                        pos.z = zOffset;
                        GameObject obj = Instantiate(foliageP[prefabIndex], transform.TransformPoint(pos), Quaternion.Euler(new Vector3(0, 0, angleInDeg))) as GameObject;
                        obj.transform.parent = transform;
                        foliageOnPath.Add(obj);
                        prevIndex    = foliageOnPath.Count - 1;
                        foliageCount = foliageOnPath.Count;
                        Foliage2D objFoliage = obj.GetComponent <Foliage2D>();
                        // The object mesh is recreated so that we don't have 2 objects with the same mesh instance.
                        objFoliage.RebuildMesh();
                        objectIndex++;
                    }
                    else
                    {
                        ZAxisOffset *= -1;
                        prevIndex    = objectIndex - 1;
                        foliageOnPath[objectIndex - 1].transform.position = transform.TransformPoint(new Vector3(pointOnTheLine.x + posOffset.x, pointOnTheLine.y + posOffset.y, ZAxisOffset));
                        foliageOnPath[objectIndex - 1].transform.rotation = Quaternion.Euler(new Vector3(0, 0, angleInDeg));
                        objectIndex++;
                    }
                }
            }

            // If the path shrinked and there is an excess of foliage objects, delete them.
            if (foliageCount + 1 > objectIndex)
            {
                int lenD = foliageCount + 1 - objectIndex;

                for (int i = 0; i < lenD; i++)
                {
                    int last = foliageOnPath.Count - 1;
                    DestroyImmediate(foliageOnPath[last]);
                    foliageOnPath.RemoveAt(last);

                    if (foliagePattern == Foliage2D_Pattern.Consecutive)
                    {
                        RestorePrefabIndex();
                    }
                }
            }
        }