Example #1
0
        public static void SpawnBranch(GameObject splatterBranchPrefab, Transform branchParent,
                                       MonoBehaviour particleProvider, SplatterSettings settings, Vector3 position,
                                       Vector3?direction, Color?color)
        {
            float nbVar       = Random.Range(-settings.numBranchesVariance, settings.numBranchesVariance);
            int   numBranches = Mathf.RoundToInt(settings.numBranchesMean + nbVar);

            for (int i = 0; i < numBranches; i++)
            {
                Color   c   = SplatterUtils.GetRandomColor(settings, color);
                Vector3 dir = SplatterUtils.GetRandomDirection(settings, direction);
                float   centerDisplacement = Random.value * settings.centerPositionRange;
                Vector2 centerAngle        = Random.onUnitSphere;
                position.x += centerAngle.x * centerDisplacement;
                if (settings.orientation == OrientationMode.Vertical)
                {
                    position.y += centerAngle.y * centerDisplacement;
                }
                else
                {
                    position.z += centerAngle.y * centerDisplacement;
                }
                float scale = settings.scaleMean + Random.Range(-settings.scaleVariance, settings.scaleVariance);
                if (scale < 0f)
                {
                    scale = 0f;
                }

                var branchPrefab = SimplePool.Spawn(splatterBranchPrefab, Vector3.zero, Quaternion.identity);
                branchPrefab.transform.parent = branchParent;
                var branch = branchPrefab.GetComponent <BaseBranch>();
                branch.SetParticleProvider(particleProvider);
                branch.ResetAndStart(settings, position, scale, dir, c);
            }
        }
Example #2
0
        public override void OnInspectorGUI()
        {
            serializedObject.Update();
            EditorGUILayout.PropertyField(serializedObject.FindProperty("defaultSettings"), true);

            MeshSplatterManager sm = target as MeshSplatterManager;

            if (sm.defaultSettings == null)
            {
                if (GUILayout.Button("Create new settings"))
                {
                    SplatterSettings ss = CustomAssetMaker.CreateAsset <SplatterSettings>("New SplatterSettings");
                    sm.defaultSettings = ss;
                }
            }

            sm.advancedSettings = EditorGUILayout.Toggle("Advanced settings", sm.advancedSettings);
            var psObject = sm.gameObject.transform.FindChild("Particle System");

            if (psObject != null)
            {
                if (sm.advancedSettings && psObject.hideFlags == HideFlags.HideInHierarchy)
                {
                    psObject.hideFlags = HideFlags.None;
                    EditorApplication.RepaintHierarchyWindow();
                }
                if (!sm.advancedSettings && psObject.hideFlags != HideFlags.HideInHierarchy)
                {
                    psObject.hideFlags = HideFlags.HideInHierarchy;
                    EditorApplication.RepaintHierarchyWindow();
                }
            }

            serializedObject.ApplyModifiedProperties();
        }
        public void Configure(SplatterSettings settings)
        {
            system        = GetComponent <ParticleSystem>();
            this.settings = settings;

            system.maxParticles = settings.maxParticles;

            if (settings.removeParticles)
            {
#if UNITY_5_3_OR_NEWER
                ParticleSystem.SizeOverLifetimeModule solm = system.sizeOverLifetime;
                solm.enabled = true;
#endif
                system.startLifetime = settings.particleLifetime;
            }

            ParticleSystemRenderer particleRenderer = (ParticleSystemRenderer)system.GetComponent <Renderer>();
            if (particleRenderer != null)
            {
                if (settings.particleMode == ParticleMode.Circle)
                {
                    particleRenderer.material = (Material)Resources.Load(
                        settings.multiplyColor? "CircleParticleMultiply" : "CircleParticleAlphaBlend");
                }
                else if (settings.particleMode == ParticleMode.Square)
                {
                    particleRenderer.material = (Material)Resources.Load(
                        settings.multiplyColor? "SquareParticleMultiply" : "SquareParticleAlphaBlend");
                }
                else if (settings.particleMode == ParticleMode.CustomTexture)
                {
                    particleRenderer.material = (Material)Resources.Load(
                        settings.multiplyColor? "CustomParticleMultiply" : "CustomParticleAlphaBlend");
                    particleRenderer.material.SetTexture("_MainTex", settings.particleTexture);
                }
                else if (settings.particleMode == ParticleMode.CustomMaterial)
                {
                    particleRenderer.material = settings.particleMaterial;
                }
                if (particleRenderer.material == null)
                {
                    Debug.LogError("[SPLATTER SYSTEM] Can't find particle renderer material.");
                }

                particleRenderer.sortingLayerName = settings.sortingLayerName;

                particleRenderer.renderMode = settings.orientation == OrientationMode.Horizontal?
                                              ParticleSystemRenderMode.HorizontalBillboard : ParticleSystemRenderMode.VerticalBillboard;
            }
        }
Example #4
0
        override public void Spawn(SplatterSettings settings, Vector3 position, Vector3?direction, Color?color)
        {
            // Find SplatterArea at position.
            SplatterArea area = null;

            foreach (var a in areas)
            {
                if (a.rectTransform.rect.Contains(position - a.rectTransform.position))
                {
                    area = a;
                    break;
                }
            }
            // If no area found, return.
            if (area == null)
            {
                return;
            }

            SplatterUtils.SpawnBranch(splatterBranchPrefab, transform, area, settings, position, direction, color);
        }
Example #5
0
        public virtual void ResetAndStart(SplatterSettings settings, Vector3 position, float startScale,
                                          Vector3 moveDir, Color color)
        {
            this.settings   = settings;
            this.position   = position;
            this.startScale = startScale;
            this.moveDir    = moveDir;
            this.color      = color;

            float numChildVar = Random.Range(-settings.branchChildrenVariance, settings.branchChildrenVariance);

            numChildParticles = Mathf.RoundToInt(Mathf.Max(settings.branchChildrenMean + numChildVar, 1));
            moveSpeed         = settings.moveSpeedMean +
                                Random.Range(-settings.moveSpeedVariance, settings.moveSpeedVariance);
            progress = 1f - 1f / (numChildParticles + 1f);

            isSpawning    = true;
            nextSpawnTime = Time.time;

            minScale = settings.scaleMin;

            enabled = true;
        }
Example #6
0
 override public void SetDefaultSettings(SplatterSettings settings)
 {
     defaultSettings = settings;
 }
Example #7
0
        public static Color GetRandomColor(SplatterSettings settings, Color?color)
        {
            Color result = Color.white;

            if (!color.HasValue)
            {
                // Set color in HSV depending on mode.
                switch (settings.colorMode)
                {
                case ColorMode.Continuous:
                    result = new Color(SplatterSettings.currentHue, SplatterSettings.startColorHSV.g,
                                       SplatterSettings.startColorHSV.b);
                    const float hueSpeed = 0.005f;
                    SplatterSettings.currentHue = (SplatterSettings.currentHue + hueSpeed) % 1f;
                    break;

                default:
                case ColorMode.List:
                    if (settings.colors.Length == 0)
                    {
                        Debug.LogError("[SPLATTER SYSTEM] No colors are defined in the colors list.");
                        return(result);
                    }
                    int index = Random.Range(0, settings.colors.Length);
                    result = settings.colorsHSV[index];
                    break;
                }
            }
            else
            {
#if UNITY_5_3_OR_NEWER
                Color.RGBToHSV(color.Value, out result.r, out result.g, out result.b);
#else
                // TODO: convert to HSV.
                color = result;
#endif
            }

            if (settings.hueVariation > 0f)
            {
                float random = Random.Range(-settings.hueVariation, settings.hueVariation);
                result.r += random; // The color is in HSV here, so this is hue.
            }
            if (settings.saturationVariation > 0f)
            {
                float random = Random.Range(-settings.saturationVariation, settings.saturationVariation);
                result.g += random; // The color is in HSV here, so this is saturation.
            }
            if (settings.brightnessVariation > 0f)
            {
                float random = Random.Range(-settings.brightnessVariation, settings.brightnessVariation);
                result.b += random; // The color is in HSV here, so this is brightness.
            }

            // Color is defined, convert HSV to RGB.
#if UNITY_5_3_OR_NEWER
            return(Color.HSVToRGB(result.r, result.g, result.b));
#else
            // TODO: convert to RGB.
            return(result);
#endif
        }
Example #8
0
        public static Vector3 GetRandomDirection(SplatterSettings settings, Vector3?avgDir)
        {
            Vector3       moveDir = Vector3.zero;
            float         random;
            DirectionMode currentDirectionMode = avgDir.HasValue? DirectionMode.Vector : settings.directionMode;

            if (!avgDir.HasValue)
            {
                avgDir = settings.direction;
            }
            switch (currentDirectionMode)
            {
            case DirectionMode.Vector:
                random = Random.Range(-settings.spanAngle * 0.5f * Mathf.Deg2Rad,
                                      settings.spanAngle * 0.5f * Mathf.Deg2Rad);
                float movAngle = Mathf.Atan2(avgDir.Value.y, avgDir.Value.x);
                movAngle += random;
                if (settings.orientation == OrientationMode.Vertical)
                {
                    moveDir = new Vector3(Mathf.Cos(movAngle), Mathf.Sin(movAngle), 0f);
                }
                else
                {
                    moveDir = new Vector3(Mathf.Cos(movAngle), 0f, Mathf.Sin(movAngle));
                }
                break;

            case DirectionMode.Transform:
                if (settings.directionReference == null)
                {
                    Debug.LogError("[SPLATTER SYSTEM] Orientation reference is not set.");
                    return(Vector3.zero);
                }
                var angles = settings.directionReference.rotation.eulerAngles * Mathf.Deg2Rad;
                random = Random.Range(-settings.spanAngle * 0.5f * Mathf.Deg2Rad,
                                      settings.spanAngle * 0.5f * Mathf.Deg2Rad);
                angles.z += Mathf.Sin(random);
                if (settings.orientation == OrientationMode.Vertical)
                {
                    moveDir = new Vector3(Mathf.Cos(angles.z), Mathf.Sin(angles.z), 0f);
                }
                else
                {
                    moveDir = new Vector3(Mathf.Cos(angles.z), 0f, Mathf.Sin(angles.z));
                }
                break;

            default:
                moveDir = Random.onUnitSphere;
                if (settings.orientation == OrientationMode.Vertical)
                {
                    moveDir.z = 0;
                }
                else
                {
                    moveDir.y = 0;
                }
                break;
            }
            return(moveDir);
        }
Example #9
0
        public override void OnInspectorGUI()
        {
            serializedObject.Update();
            SplatterSettings s = target as SplatterSettings;

            Undo.RecordObject(s, "SplatterSettings_test1");
            EditorGUI.BeginChangeCheck();

            // Settings mode
            EditorGUILayout.LabelField("Splatter mode", EditorStyles.boldLabel);
            ShowHint("Bitmap and Mesh modes have different parameters, this shows which parameters are in use.");
            var style = new GUIStyle(EditorStyles.popup);

            style.alignment     = TextAnchor.MiddleCenter;
            style.fontSize      = 12;
            style.stretchHeight = true;
            style.fixedHeight   = 18;
            style.margin.bottom = 10;
            s.mode = (SettingsMode)EditorGUILayout.EnumPopup(s.mode, style);

            // Movement
            EditorGUILayout.LabelField("Movement", EditorStyles.boldLabel);
            EditorGUI.indentLevel++;
            ShowHint("Splatter direction can be defined in different ways. Click through options for more details.");
            s.directionMode = (DirectionMode)EditorGUILayout.EnumPopup("Mode", s.directionMode);
            EditorGUI.indentLevel++;
            if (s.directionMode != DirectionMode.AllDirections)
            {
                ShowHint("Radial angle of the splatter in degrees. A value of 180 means only one half of the space " +
                         "will be covered in splatter. Value of 360 means splatter goes in all directions.");
                s.spanAngle = EditorGUILayout.FloatField("Span angle", s.spanAngle);

                if (s.directionMode == DirectionMode.Transform)
                {
                    ShowHint("Splatter particles will go in the direction of the reference Transform.");
                    s.directionReference = EditorGUILayout.ObjectField("Direction reference", s.directionReference,
                                                                       typeof(Transform), true) as Transform;
                }

                if (s.directionMode == DirectionMode.Vector)
                {
                    ShowHint("Constant direction of splatter in world coordinates.");
                    s.direction = EditorGUILayout.Vector3Field("Direction", s.direction);
                }
            }
            else
            {
                ShowHint("Splatter is done in all 360 degrees.");
            }
            EditorGUI.indentLevel--;

            ShowHint("How random starting positions of branches are.");
            s.centerPositionRange = EditorGUILayout.Slider("Position variance", s.centerPositionRange, 0f, 1f);

            ShowHint("Distance between particles in a branch. Particles are placed on fixed timesteps, so this is " +
                     "also the mean speed of particles. This value is affected by the 'Step duration' setting.");
            s.moveSpeedMean = EditorGUILayout.Slider("Speed", s.moveSpeedMean, 0f, 2f);

            ShowHint("Time in seconds between spawning two particles in a branch.");
            s.stepDuration = EditorGUILayout.Slider("Step duration", s.stepDuration, 0.001f, 0.25f);

            showMovementAdvanced = EditorGUILayout.Foldout(showMovementAdvanced, "Advanced");
            if (showMovementAdvanced)
            {
                EditorGUI.indentLevel++;

                ShowHint("Damping to be applied to particle speed. Damping is a factor that gradually changes a the " +
                         "speed towards a zero over time. A value of zero here means the particle will move with " +
                         "constant speed. Higher damping looks cooler.");
                s.damping = EditorGUILayout.Slider("Damping", s.damping, 0f, 1f);

                ShowHint("Maximum possible deviation of move speed from the mean value above.");
                s.moveSpeedVariance = EditorGUILayout.Slider("Speed variance", s.moveSpeedVariance, 0f, 1f);

                ShowHint("Whether each particle should have a random angle when spawned.");
                s.randomRotation = EditorGUILayout.Toggle("Random rotation", s.randomRotation);

                EditorGUI.indentLevel--;
            }

            EditorGUI.indentLevel--;

            // Orientation
            if (s.mode == SettingsMode.Mesh)
            {
                EditorGUILayout.LabelField("Orientation", EditorStyles.boldLabel);
                ShowHint("The direction which the splatter faces. Vertical is suitable for splatter on walls and for 2D, " +
                         "whereas horizontal is suitable for floor splatter in 3D games.");
                EditorGUI.indentLevel++;
                s.orientation = (OrientationMode)EditorGUILayout.EnumPopup("Mode", s.orientation);
                EditorGUI.indentLevel--;
            }

            // Intensity
            EditorGUILayout.LabelField("Intensity", EditorStyles.boldLabel);
            EditorGUI.indentLevel++;

            ShowHint("Splatters consist of multiple branches (long lines of particles). This value is the mean " +
                     "number of branches in each spllatter.");
            s.numBranchesMean = EditorGUILayout.Slider("Branches", s.numBranchesMean, 1f, 20f);

            ShowHint("Mean number of particles in each branch.");
            s.branchChildrenMean = EditorGUILayout.Slider("Branch children", s.branchChildrenMean, 1f, 20f);

            ShowHint("Mean scale of particles at which each branch starts. Scale of particles in each branch is " +
                     "gradually reduced to zero.");
            s.scaleMean = EditorGUILayout.Slider("Branch scale", s.scaleMean, 0f, 3f);

            showIntencityAdvanced = EditorGUILayout.Foldout(showIntencityAdvanced, "Advanced");
            if (showIntencityAdvanced)
            {
                EditorGUI.indentLevel++;

                ShowHint("Maximum possible deviation of branch number from the mean value above.");
                EditorGUILayout.LabelField("Branches variance");
                s.numBranchesVariance = EditorGUILayout.Slider(s.numBranchesVariance, 0f, 5f);

                ShowHint("Maximum possible deviation of branch children from the mean value above.");
                EditorGUILayout.LabelField("Branch children variance");
                s.branchChildrenVariance = EditorGUILayout.Slider(s.branchChildrenVariance, 0f, 10f);

                ShowHint("Maximum possible deviation of children scale from the mean value above.");
                EditorGUILayout.LabelField("Branch scale variance");
                s.scaleVariance = EditorGUILayout.Slider(s.scaleVariance, 0f, 1f);

                ShowHint("Minimum size of particles at which branches stop spawning.");
                EditorGUILayout.LabelField("Minimum particle size");
                s.scaleMin = EditorGUILayout.Slider(s.scaleMin, 0f, 1f);

                EditorGUI.indentLevel--;
            }
            EditorGUI.indentLevel--;

            // Colors
            EditorGUILayout.LabelField("Colors", EditorStyles.boldLabel);
            EditorGUI.indentLevel++;

            ShowHint("The way colors of branches are picked.\n" +
                     "Continuous: aka Ranbow mode. In this mode colors are calculated from the HSV space, where hue " +
                     "continuously moves around the circle.\n" +
                     "List: colors for each branch are picked randomly from a list.");
            s.colorMode = (ColorMode)EditorGUILayout.EnumPopup("Mode", s.colorMode);
            EditorGUI.indentLevel++;
            switch (s.colorMode)
            {
            case ColorMode.Continuous:
                ShowHint("Color that will be used for the first branch spawned.");
                s.startColor = EditorGUILayout.ColorField("Start color", s.startColor);
                break;

            case ColorMode.List:
                EditorList.Show(serializedObject.FindProperty("colors"),
                                EditorListOption.Buttons | EditorListOption.ListLabel);
                break;
            }
            EditorGUI.indentLevel--;

            if (s.mode == SettingsMode.Mesh)
            {
                ShowHint("Multiply colors of overlapping colors instead of replacing them.");
                s.multiplyColor = EditorGUILayout.Toggle("Multily blending", s.multiplyColor);
            }

            showColorsAdvanced = EditorGUILayout.Foldout(showColorsAdvanced, "Advanced");
            if (showColorsAdvanced)
            {
                EditorGUI.indentLevel++;

                ShowHint("Maximum random value that will be added to brighness of branch color in HSV space.");
                EditorGUILayout.LabelField("Brightness variation");
                s.brightnessVariation = EditorGUILayout.Slider(s.brightnessVariation, 0f, 0.5f);

                ShowHint("Maximum random value that will be added to hue of branch color in HSV space.");
                EditorGUILayout.LabelField("Hue variation");
                s.hueVariation = EditorGUILayout.Slider(s.hueVariation, 0f, 0.5f);

                ShowHint("Maximum random value that will be added to saturation of branch color in HSV space.");
                EditorGUILayout.LabelField("Saturation variation");
                s.saturationVariation = EditorGUILayout.Slider(s.saturationVariation, 0f, 0.5f);

                EditorGUILayout.Separator();

                ShowHint("Whether particles in each branch should become transparent towards end.");
                s.fadeOutBranches = EditorGUILayout.Toggle("Fade out branches", s.fadeOutBranches);
                EditorGUI.indentLevel--;
            }

            EditorGUI.indentLevel--;

            // Particles
            EditorGUILayout.LabelField("Particles", EditorStyles.boldLabel);
            EditorGUI.indentLevel++;

            ShowHint("Shape of small particles that splatter consists of.");
            s.particleMode = (ParticleMode)EditorGUILayout.EnumPopup("Shape", s.particleMode);

            if (s.mode == SettingsMode.Bitmap && s.particleMode == ParticleMode.CustomTexture)
            {
                EditorGUILayout.HelpBox("Custom textures can't be used in Bitmap mode, please select other shape or " +
                                        "switch to Mesh mode", MessageType.Warning);
            }

            if (s.particleMode == ParticleMode.CustomMaterial)
            {
                s.particleMaterial =
                    (Material)EditorGUILayout.ObjectField(s.particleMaterial, typeof(Material), false);
            }

            if (s.mode == SettingsMode.Mesh)
            {
                if (s.particleMode == ParticleMode.CustomTexture)
                {
                    s.particleTexture =
                        (Texture2D)EditorGUILayout.ObjectField(s.particleTexture, typeof(Texture2D), false);
                }

                ShowHint("The maximum number of particles that can exist at the same time. When this number is " +
                         "exeeded the oldest particles are removed. This setting is very important for performance. " +
                         "Lower number means faster execution.");
                s.maxParticles = EditorGUILayout.IntSlider("Max quantity", s.maxParticles, 100, 20000);

                ShowHint("Whether the particles should be removed after some time.");
                s.removeParticles = EditorGUILayout.Toggle("Fade out", s.removeParticles);

                if (s.removeParticles)
                {
                    EditorGUI.indentLevel++;

                    ShowHint("Time in seconds between spawning and fading out a particle.");
                    s.particleLifetime = EditorGUILayout.FloatField("Lifetime", s.particleLifetime);

                    EditorGUI.indentLevel--;
                }

                ShowHint("The Sorting Layer that the splatter should draw to.");
                var sortingLayerNames = SortingLayer.layers.Select(l => l.name).ToArray();
                int currentIndex      = Array.IndexOf(sortingLayerNames, s.sortingLayerName);
                int newLayerIndex     = EditorGUILayout.Popup("Sorting Layer", currentIndex, sortingLayerNames);
                if (newLayerIndex < sortingLayerNames.Length && newLayerIndex >= 0)
                {
                    s.sortingLayerName = sortingLayerNames[newLayerIndex];
                }
            }

            EditorGUI.indentLevel--;

            // Utility
            EditorGUILayout.LabelField("Utility", EditorStyles.boldLabel);
            EditorGUI.indentLevel++;

            showHints = EditorGUILayout.Toggle("Show explanations", showHints);

            EditorGUILayout.BeginHorizontal();
            GUILayout.Space(16);
            if (GUILayout.Button(EditorGUIUtility.IconContent("_Help"),
                                 GUILayout.MinWidth(40), GUILayout.MinHeight(20)))
            {
                Application.OpenURL("http://dustyroom.com/splatter-system/manual/");
            }
            EditorGUILayout.EndHorizontal();

            EditorGUI.indentLevel--;

            if (EditorGUI.EndChangeCheck())
            {
                EditorUtility.SetDirty(target);
                serializedObject.ApplyModifiedProperties();
            }
        }
Example #10
0
 override public void Spawn(SplatterSettings settings, Vector3 position, Vector3?direction, Color?color)
 {
     SplatterUtils.SpawnBranch(splatterBranchPrefab, transform, particles, settings, position, direction, color);
 }
Example #11
0
 override public void SetDefaultSettings(SplatterSettings settings)
 {
     defaultSettings = settings;
     particles.Configure(settings);
 }
Example #12
0
 public abstract void Spawn(SplatterSettings settings, Vector3 position, Vector3?direction, Color?color);
Example #13
0
 public abstract void SetDefaultSettings(SplatterSettings settings);