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); } }
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; } }
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); }
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; }
override public void SetDefaultSettings(SplatterSettings settings) { defaultSettings = settings; }
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 }
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); }
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(); } }
override public void Spawn(SplatterSettings settings, Vector3 position, Vector3?direction, Color?color) { SplatterUtils.SpawnBranch(splatterBranchPrefab, transform, particles, settings, position, direction, color); }
override public void SetDefaultSettings(SplatterSettings settings) { defaultSettings = settings; particles.Configure(settings); }
public abstract void Spawn(SplatterSettings settings, Vector3 position, Vector3?direction, Color?color);
public abstract void SetDefaultSettings(SplatterSettings settings);