- Home /
Why are all the particles in my particle system disappearing when it's off screen?
I am developing a 2D space game where the stars in the background are generated by multiple shuriken particle systems. I'll try to explain this as clearly as possible.
The way I do it is that I have multiple "layers" of stars all at different z positions and I use a custom x-y parallax scroll script to move the "layers" of stars at different speeds to give an illusion of depth. These layers are all game objects with a particle system component attached to them.
I use a script to generate all the stars in a layer that works by starting from a centre point and then, using the Random.insideUnitCircle function, I generate all the stars for that layer.
Unfortunately, whenever the centre point of any layer moves off screen, all the particles in that layer completely disappear. When it comes back on screen, they all reappear. It's incredibly frustrating because it's a really cool effect when it works. Is there anybody who can help figure out the issue?
I have looked everywhere for an answer and nobody has a solution that works for me. None of the following works:
Setting the simulation space from local to global is not possible because I need it to be local in order to move each layer appropriately
Changing the scale, it's always been set to 1.
Enabling subemitters
I have done all my work in 4.5 and now the 4.6 beta, where the particles still all disappear. If you need some more specifics, please let me know.
Thanks.
Setting the simulation space from local to global is not possible because I need it to be local in order to move each layer appropriately
One solution is to make the space global then move the particles yourself directly in the particles array.
Here is another solution. I wrote the core to display particles in an answer to this question:
http://answers.unity3d.com/questions/770219/large-numbers-of-gameobjectsitems.html#answer-771769
A simple change to make the meshes it creates children of a game object would allow you to parent the quads to a layer.
How will moving each particle individually affect performance though? I have thousands of stars that are generated, I feel like moving each particle's transform would be quite taxing on performance.
I feel like moving each particle's transform would be quite taxing on performance.
Individual particles don't have transforms. They are Quads in a mesh, though moving the quad will involve having the ParticleSystem change the mesh. You'll have to test it. Do a setup and then keep pushing layers until you see a performance drop (ideally in a build, not in the editor).
If you have issues, you can use the code I provided. Once the mesh is built, all you have to do is move the game object.
I'll give it a try when I have some more time. I will get back to you.
Answer by robertbu · Aug 28, 2014 at 03:09 AM
If you don't get your particle system working, I have an alternate solution for you. From your description, what you need is a way to build a static mesh of quads. That mesh will belong to a game object, so you can move the whole mesh by moving the game object. Below is some code. You attach it to an empty game object, add a material, and then in a separate script set the properties for an array of quads...a maximum of 16380 per mesh. For each quad you can specify:
local position
2D (i.e. 'z') rotation
size
spritesheet frame (starting in the lower left corner and working by rows up
using UnityEngine; using System.Collections;
public class QuadDisplay : MonoBehaviour { public Camera camera; // Camera to use for rotation public Material material; // Material for quads public float defaultquadsize = 0.2f; public int spriteRows = 4;
public int spriteCols = 4;public struct Quad { public Vector3 position; public float rotation; public float size; public int frame; } private int quadCount = 1000; public Quad[] quads; private float spriteCellWidth; private float spriteCellHeight; private int spriteSheetCellCount; private const int maxQuads = 16380; private Mesh mesh; private Transform camTrans; void Awake() { if (camera == null) camera = Camera.main; if (camera != null) camTrans = camera.transform; MeshFilter mf = GetComponent<MeshFilter>(); if (mf == null) { mf = gameObject.AddComponent<MeshFilter>(); } mesh = new Mesh(); mf.mesh = mesh; mesh.MarkDynamic (); Renderer rend = gameObject.AddComponent<MeshRenderer>(); rend.material = material; if (quadCount > maxQuads) { Debug.Log ("Maximum of 16380 Quads"); } quadCount = Mathf.Clamp (quadCount, 0, maxQuads); spriteCellWidth = 1.0f / spriteCols; spriteCellHeight = 1.0f / spriteRows; spriteSheetCellCount = spriteRows * spriteCols; quads = new Quad[maxQuads]; for (int i = 0; i < quadCount; i++) { quads[i].size = defaultquadsize; } } public void Apply(int count) { if (count <= 0) return; quadCount = count; Vector3[] vertices = new Vector3[4 * quadCount]; Vector2[] uvs = new Vector2[vertices.Length]; Vector3 fwd = camTrans.forward; Quaternion qCam = camTrans.rotation; for (int j = 0; j < vertices.Length / 4; j++) { Quad quad = quads[j]; float l = quad.size / 2.0f; Vector3 v0 = new Vector3(-l, l, 0); Vector3 v1 = new Vector3(-l,-l, 0); Vector3 v2 = new Vector3( l,-l, 0); Vector3 v3 = new Vector3( l, l, 0); Quaternion q = Quaternion.AngleAxis(quad.rotation, fwd) * qCam; vertices[j * 4] = quad.position + q * v0; vertices[j * 4 + 1] = quad.position + q * v1; vertices[j * 4 + 2] = quad.position + q * v2; vertices[j * 4 + 3] = quad.position + q * v3; int frame = quad.frame % spriteSheetCellCount; float x = quad.frame % spriteCols * spriteCellWidth; float y = quad.frame / spriteRows * spriteCellHeight; uvs[j * 4] = new Vector2(x + 0.01f, y + spriteCellWidth - 0.01f); uvs[j * 4 + 1] = new Vector2(x + 0.01f, y + 0.01f); uvs[j * 4 + 2] = new Vector2(x + spriteCellWidth - 0.01f, y + 0.01f); uvs[j * 4 + 3] = new Vector2(x + spriteCellWidth - 0.01f, y + spriteCellHeight - 0.01f); } mesh.triangles = null; mesh.vertices = vertices; mesh.uv = uvs; int[] triangles = new int[mesh.vertices.Length / 2 * 3]; for (int j = 0; j < vertices.Length / 4; j++) { triangles[j * 6 + 0] = j * 4 + 0; // 0_ 3 0 ___ 3 triangles[j * 6 + 1] = j * 4 + 3; // | / | /| triangles[j * 6 + 2] = j * 4 + 1; // 1|/ 1|/__|2 triangles[j * 6 + 3] = j * 4 + 3; // 3 triangles[j * 6 + 4] = j * 4 + 2; // /| triangles[j * 6 + 5] = j * 4 + 1; // 1/_|2 } mesh.triangles = triangles; } }
Here is a demonstration script on how to drive it. The following script will generate a different star field each time the space bar is pressed:
using UnityEngine;
using System.Collections;
public class StarDriver : MonoBehaviour {
void Start() {
BuildStars();
}
void Update() {
if (Input.GetKeyDown (KeyCode.Space)) {
BuildStars();
}
}
void BuildStars () {
QuadDisplay qd = GetComponent<QuadDisplay>();
int count = Random.Range(3000, 10000);
for (int i = 0; i < count; i++) {
qd.quads[i].position = new Vector3(Random.Range (-8.0f, 8.0f), Random.Range (-6.0f, 6.0f), 0.0f);
qd.quads[i].frame = Random.Range (0,16);
qd.quads[i].size = Random.Range (0.1f, 0.3f);
}
qd.Apply(count);
}
}
Here is the spritesheet I used for my test:
I made the texture 'Truecolor' and used in a material with Unlit/Transparent as the shader. Here is a sample result:
Not bad. More work on the spritesheet and perhaps a layout that did more clumping would produce a more realistic result.
This is absolutely incredible. I'm going to try and implement this solution asap and let you know how it goes! Thanks for being tremendously helpful.
I put a sample package here:
http://www.laughingloops.com/Stars.unitypackage
The scene is Assets/_Project/Scenes/$$anonymous$$ain
Your answer
Follow this Question
Related Questions
Separate particle systems rendered together with a single sorting mode? 0 Answers
Shuriken particle system useWorldSpace? 1 Answer
How do you access a Shuriken particle system through javascript? 1 Answer
[Shuriken] How to avoid clipping? 2 Answers
How to make particles react to movement of particle system 4 Answers