示例#1
0
		/// <summary>
		/// Returns all current particles within a local manipulator (in form of an Event Particle, however no event will be needed).
		/// </summary>
		/// <returns>The manipulator particles.</returns>
		/// <param name="manipulator">Manipulator.</param>
		/// <param name="playgroundParticles">Playground particles.</param>
		public static List<PlaygroundEventParticle> GetManipulatorParticles (int manipulator, PlaygroundParticlesC playgroundParticles) {
			if (manipulator<0 || manipulator>=playgroundParticles.manipulators.Count) return null;
			List<PlaygroundEventParticle> particles = new List<PlaygroundEventParticle>();
			PlaygroundEventParticle particle = new PlaygroundEventParticle();
			for (int i = 0; i<playgroundParticles.particleCount; i++) {
				if (playgroundParticles.manipulators[manipulator].Contains(playgroundParticles.playgroundCache.position[i], playgroundParticles.manipulators[manipulator].transform.position)) {
					playgroundParticles.UpdateEventParticle(particle, i);
					particles.Add (particle.Clone());
				}
			}
			return particles;
		}
        /// <summary>
        /// Sends the death events.
        /// </summary>
        /// <param name="playgroundParticles">Playground particles.</param>
        /// <param name="p">Particle index.</param>
        public static void SendDeathEvents(PlaygroundParticlesC playgroundParticles, int p)
        {
            if ((playgroundParticles.playgroundCache.life[p]>0||playgroundParticles.playgroundCache.changedByPropertyDeath[p]) && !playgroundParticles.playgroundCache.isNonBirthed[p]) {
                if (playgroundParticles.loop || (!playgroundParticles.loop && playgroundParticles.playgroundCache.isFirstLoop[p])) {
                    playgroundParticles.SendEvent(EVENTTYPEC.Death, p);
                }
            }
            if (playgroundParticles.hasEventManipulatorLocal) {
                for (int i = 0; i<playgroundParticles.manipulators.Count; i++) {
                    if (playgroundParticles.manipulators[i].trackParticles &&
                        playgroundParticles.manipulators[i].RemoveParticle (playgroundParticles.particleSystemId, p)) {

                        if (playgroundParticles.manipulators[i].sendEventDeath) {
                            playgroundParticles.UpdateEventParticle(playgroundParticles.manipulators[i].manipulatorEventParticle, p);
                            playgroundParticles.manipulators[i].SendParticleEventDeath();
                        }
                    }
                }
            }
            if (playgroundParticles.hasEventManipulatorGlobal) {

                for (int i = 0; i<PlaygroundC.reference.manipulators.Count; i++) {
                    if (PlaygroundC.reference.manipulators[i].trackParticles &&
                        PlaygroundC.reference.manipulators[i].RemoveParticle (playgroundParticles.particleSystemId, p)) {

                        if (PlaygroundC.reference.manipulators[i].sendEventDeath) {
                            playgroundParticles.UpdateEventParticle(PlaygroundC.reference.manipulators[i].manipulatorEventParticle, p);
                            PlaygroundC.reference.manipulators[i].SendParticleEventDeath();
                        }
                    }
                }
            }
            playgroundParticles.playgroundCache.isNonBirthed[p] = true;
        }
        // Rebirth of a specified particle
        public static void Rebirth(PlaygroundParticlesC playgroundParticles, int p, System.Random random)
        {
            if (!playgroundParticles.hasActiveParticles) return;

            // Set initial values
            playgroundParticles.playgroundCache.rebirth[p] = playgroundParticles.source==SOURCEC.Script?true:(playgroundParticles.emit && (playgroundParticles.loop || playgroundParticles.playgroundCache.isNonBirthed[p]) && playgroundParticles.playgroundCache.emission[p]);
            playgroundParticles.playgroundCache.isFirstLoop[p] = playgroundParticles.playgroundCache.isNonBirthed[p];
            playgroundParticles.playgroundCache.isNonBirthed[p] = false;
            playgroundParticles.playgroundCache.life[p] = 0f;
            playgroundParticles.playgroundCache.birth[p] = playgroundParticles.playgroundCache.death[p];
            playgroundParticles.playgroundCache.death[p] += playgroundParticles.lifetime;
            playgroundParticles.playgroundCache.velocity[p] = Vector3.zero;
            playgroundParticles.playgroundCache.noForce[p] = false;

            // Reset manipulators influence
            playgroundParticles.playgroundCache.changedByProperty[p] = false;
            playgroundParticles.playgroundCache.changedByPropertyColor[p] = false;
            playgroundParticles.playgroundCache.changedByPropertyColorLerp[p] = false;
            playgroundParticles.playgroundCache.changedByPropertyColorKeepAlpha[p] = false;
            playgroundParticles.playgroundCache.changedByPropertySize[p] = false;
            playgroundParticles.playgroundCache.changedByPropertyTarget[p] = false;
            playgroundParticles.playgroundCache.changedByPropertyDeath[p] = false;
            playgroundParticles.playgroundCache.propertyTarget[p] = 0;
            playgroundParticles.playgroundCache.propertyId[p] = 0;
            playgroundParticles.playgroundCache.propertyColorId[p] = 0;
            playgroundParticles.playgroundCache.manipulatorId[p] = 0;

            // Set new random size
            if (playgroundParticles.applyRandomSizeOnRebirth)
                playgroundParticles.playgroundCache.initialSize[p] = RandomRange(random, playgroundParticles.sizeMin, playgroundParticles.sizeMax);

            // Initial velocity
            if (!playgroundParticles.onlySourcePositioning && !playgroundParticles.onlyLifetimePositioning) {

                // Initial global velocity
                if (playgroundParticles.applyInitialVelocity) {
                    if (playgroundParticles.applyRandomInitialVelocityOnRebirth) {
                        if (playgroundParticles.initialVelocityMethod==MINMAXVECTOR3METHOD.Spherical)
                            playgroundParticles.playgroundCache.initialVelocity[p] = RandomRangeSpherical(random, playgroundParticles.initialVelocityMin.x, playgroundParticles.initialVelocityMax.x);
                        else if (playgroundParticles.initialVelocityMethod==MINMAXVECTOR3METHOD.SphericalLinear)
                            playgroundParticles.playgroundCache.initialVelocity[p] = RandomRangeSpherical(random, playgroundParticles.initialVelocityMin.x, playgroundParticles.initialVelocityMax.x, (p*1f)/(playgroundParticles.particleCount*1f));
                        else if (playgroundParticles.initialVelocityMethod==MINMAXVECTOR3METHOD.RectangularLinear)
                            playgroundParticles.playgroundCache.initialVelocity[p] = Vector3.Lerp (playgroundParticles.initialVelocityMin, playgroundParticles.initialVelocityMax, (p*1f)/(playgroundParticles.particleCount*1f));
                        //else if (playgroundParticles.initialVelocityMethod==MINMAXVECTOR3METHOD.SphericalSector)
                        //	playgroundParticles.playgroundCache.initialVelocity[p] = RandomRangeSpherical(random, playgroundParticles.initialVelocityMin.x, playgroundParticles.initialVelocityMax.x, playgroundParticles.initialVelocityMin.y, playgroundParticles.initialVelocityMax.y);
                        //else if (playgroundParticles.initialVelocityMethod==MINMAXVECTOR3METHOD.SphericalSectorLinear)
                        //	playgroundParticles.playgroundCache.initialVelocity[p] = RandomRangeSpherical(random, playgroundParticles.initialVelocityMin.x, playgroundParticles.initialVelocityMax.x, playgroundParticles.initialVelocityMin.y, playgroundParticles.initialVelocityMax.y, (p*1f)/(playgroundParticles.particleCount*1f));
                        else playgroundParticles.playgroundCache.initialVelocity[p] = RandomRange(random, playgroundParticles.initialVelocityMin, playgroundParticles.initialVelocityMax);
                    }
                    playgroundParticles.playgroundCache.velocity[p] = playgroundParticles.playgroundCache.initialVelocity[p];

                    // Give this spawning particle its velocity shape
                    if (playgroundParticles.applyInitialVelocityShape)
                        playgroundParticles.playgroundCache.velocity[p] = Vector3.Scale(playgroundParticles.playgroundCache.velocity[p], playgroundParticles.initialVelocityShape.Evaluate((p*1f)/(playgroundParticles.particleCount*1f), playgroundParticles.initialVelocityShapeScale));
                }

                // Initial local velocity
                if (playgroundParticles.applyInitialLocalVelocity && playgroundParticles.source!=SOURCEC.Script) {
                    if (playgroundParticles.initialLocalVelocityMethod==MINMAXVECTOR3METHOD.Spherical)
                        playgroundParticles.playgroundCache.initialLocalVelocity[p] = RandomRangeSpherical(random, playgroundParticles.initialLocalVelocityMin.x, playgroundParticles.initialLocalVelocityMax.x);
                    else if (playgroundParticles.initialLocalVelocityMethod==MINMAXVECTOR3METHOD.SphericalLinear)
                        playgroundParticles.playgroundCache.initialLocalVelocity[p] = RandomRangeSpherical(random, playgroundParticles.initialLocalVelocityMin.x, playgroundParticles.initialLocalVelocityMax.x, (p*1f)/(playgroundParticles.particleCount*1f));
                    else if (playgroundParticles.initialLocalVelocityMethod==MINMAXVECTOR3METHOD.RectangularLinear)
                        playgroundParticles.playgroundCache.initialLocalVelocity[p] = Vector3.Lerp (playgroundParticles.initialLocalVelocityMin, playgroundParticles.initialLocalVelocityMax, (p*1f)/(playgroundParticles.particleCount*1f));
                    //else if (playgroundParticles.initialLocalVelocityMethod==MINMAXVECTOR3METHOD.SphericalSector)
                    //	playgroundParticles.playgroundCache.initialLocalVelocity[p] = RandomRangeSpherical(random, playgroundParticles.initialLocalVelocityMin.x, playgroundParticles.initialLocalVelocityMax.x, playgroundParticles.initialLocalVelocityMin.y, playgroundParticles.initialLocalVelocityMax.y);
                    //else if (playgroundParticles.initialLocalVelocityMethod==MINMAXVECTOR3METHOD.SphericalSectorLinear)
                    //	playgroundParticles.playgroundCache.initialLocalVelocity[p] = RandomRangeSpherical(random, playgroundParticles.initialLocalVelocityMin.x, playgroundParticles.initialLocalVelocityMax.x, playgroundParticles.initialLocalVelocityMin.y, playgroundParticles.initialLocalVelocityMax.y, (p*1f)/(playgroundParticles.particleCount*1f));
                    else playgroundParticles.playgroundCache.initialLocalVelocity[p] = RandomRange(random, playgroundParticles.initialLocalVelocityMin, playgroundParticles.initialLocalVelocityMax);
                    playgroundParticles.playgroundCache.velocity[p] += playgroundParticles.playgroundCache.targetDirection[p];

                    // Give this spawning particle its local velocity shape
                    if (playgroundParticles.applyInitialVelocityShape)
                        playgroundParticles.playgroundCache.velocity[p] = Vector3.Scale(playgroundParticles.playgroundCache.velocity[p], playgroundParticles.initialVelocityShape.Evaluate((p*1f)/(playgroundParticles.particleCount*1f), playgroundParticles.initialVelocityShapeScale));
                }

                // Initial stretch
                playgroundParticles.particleCache[p].velocity = playgroundParticles.renderModeStretch&&playgroundParticles.applyStretchStartDirection?playgroundParticles.stretchStartDirection:Vector3.zero;
            }
            if (playgroundParticles.source==SOURCEC.Script) {
                // Velocity for script mode
                if (!playgroundParticles.onlySourcePositioning && !playgroundParticles.onlyLifetimePositioning)
                    playgroundParticles.playgroundCache.velocity[p] += playgroundParticles.scriptedEmissionVelocity;
                playgroundParticles.playgroundCache.targetPosition[p] = playgroundParticles.scriptedEmissionPosition;
                playgroundParticles.particleCache[p].velocity = playgroundParticles.renderModeStretch&&playgroundParticles.applyStretchStartDirection?playgroundParticles.stretchStartDirection:Vector3.zero;
            }

            // Set new random lifetime
            if (playgroundParticles.scriptedLifetime==0) {
                if (playgroundParticles.applyRandomLifetimeOnRebirth) {
                    if (playgroundParticles.lifetimeValueMethod==VALUEMETHOD.Constant) {
                        playgroundParticles.playgroundCache.lifetimeSubtraction[p] = 0;
                    } else {
                        playgroundParticles.playgroundCache.lifetimeSubtraction[p] = playgroundParticles.lifetime-RandomRange (random, playgroundParticles.lifetimeMin, playgroundParticles.lifetime);
                    }
                }

                // Set shuriken particles lifetime
                if (!playgroundParticles.syncPositionsOnMainThread)
                    playgroundParticles.particleCache[p].lifetime = playgroundParticles.lifetime;
                playgroundParticles.particleCache[p].startLifetime = playgroundParticles.lifetime-playgroundParticles.playgroundCache.lifetimeSubtraction[p];
            } else {

                playgroundParticles.playgroundCache.lifetimeSubtraction[p] = 0;
                if (!playgroundParticles.syncPositionsOnMainThread)
                    playgroundParticles.particleCache[p].lifetime = playgroundParticles.scriptedLifetime;
                playgroundParticles.particleCache[p].startLifetime = playgroundParticles.scriptedLifetime;
            }

            if (playgroundParticles.playgroundCache.rebirth[p]) {

                playgroundParticles.particleCache[p].color = playgroundParticles.GetParticleColor(p, 0f, (p*1f)/(playgroundParticles.particleCount*1f));

                // Source Scattering
                if (playgroundParticles.applySourceScatter && playgroundParticles.source!=SOURCEC.Script) {
                    if (playgroundParticles.playgroundCache.scatterPosition[p]==Vector3.zero || playgroundParticles.applyRandomScatterOnRebirth) {
                        if (playgroundParticles.sourceScatterMethod==MINMAXVECTOR3METHOD.Rectangular)
                            playgroundParticles.playgroundCache.scatterPosition[p] = RandomRange(random, playgroundParticles.sourceScatterMin, playgroundParticles.sourceScatterMax);
                        else if (playgroundParticles.sourceScatterMethod==MINMAXVECTOR3METHOD.RectangularLinear)
                            playgroundParticles.playgroundCache.scatterPosition[p] = Vector3.Lerp (playgroundParticles.sourceScatterMin, playgroundParticles.sourceScatterMax, (p*1f)/(playgroundParticles.particleCount*1f));
                        else if (playgroundParticles.sourceScatterMethod==MINMAXVECTOR3METHOD.SphericalLinear)
                            playgroundParticles.playgroundCache.scatterPosition[p] = RandomRangeSpherical(random, playgroundParticles.sourceScatterMin.x, playgroundParticles.sourceScatterMax.x, (p*1f)/(playgroundParticles.particleCount*1f));
                        //else if (playgroundParticles.sourceScatterMethod==MINMAXVECTOR3METHOD.SphericalSector)
                        //	playgroundParticles.playgroundCache.scatterPosition[p] = RandomRangeSpherical(random, playgroundParticles.sourceScatterMin.x, playgroundParticles.sourceScatterMax.x, playgroundParticles.sourceScatterMin.y, playgroundParticles.sourceScatterMax.y);
                        //else if (playgroundParticles.sourceScatterMethod==MINMAXVECTOR3METHOD.SphericalSectorLinear)
                        //	playgroundParticles.playgroundCache.scatterPosition[p] = RandomRangeSpherical(random, playgroundParticles.sourceScatterMin.x, playgroundParticles.sourceScatterMax.x, playgroundParticles.sourceScatterMin.y, playgroundParticles.sourceScatterMax.y, (p*1f)/(playgroundParticles.particleCount*1f));
                        else playgroundParticles.playgroundCache.scatterPosition[p] = RandomRangeSpherical(random, playgroundParticles.sourceScatterMin.x, playgroundParticles.sourceScatterMax.x);
                    }
                } else playgroundParticles.playgroundCache.scatterPosition[p] = Vector3.zero;

                if (!playgroundParticles.onlyLifetimePositioning) {
                    playgroundParticles.playgroundCache.position[p] = playgroundParticles.playgroundCache.targetPosition[p];
                    if (!playgroundParticles.syncPositionsOnMainThread)
                        playgroundParticles.particleCache[p].position = playgroundParticles.playgroundCache.targetPosition[p];
                    playgroundParticles.playgroundCache.previousParticlePosition[p] = playgroundParticles.playgroundCache.targetPosition[p];
                    playgroundParticles.playgroundCache.collisionParticlePosition[p] = playgroundParticles.playgroundCache.targetPosition[p];
                } else if (!playgroundParticles.onlySourcePositioning) {

                    // Lifetime Positioning by Vector3 Animation Curve
                    if (playgroundParticles.lifetimePositioningUsesSourceDirection && playgroundParticles.source!=SOURCEC.Script) {
                        playgroundParticles.playgroundCache.position[p] = playgroundParticles.playgroundCache.targetPosition[p]+(playgroundParticles.playgroundCache.targetDirection[p]);
                    } else {
                        if (!playgroundParticles.applyLifetimePositioningPositionScale) {
                            playgroundParticles.playgroundCache.position[p] =
                                playgroundParticles.playgroundCache.targetPosition[p]+
                                    playgroundParticles.lifetimePositioning.Evaluate(0, playgroundParticles.lifetimePositioningScale);
                        } else {
                            playgroundParticles.playgroundCache.position[p] =
                                playgroundParticles.playgroundCache.targetPosition[p]+
                                    playgroundParticles.lifetimePositioning.Evaluate(0, playgroundParticles.lifetimePositioningScale)*
                                    playgroundParticles.lifetimePositioningPositionScale.Evaluate(0);
                        }
                    }
                    if (!playgroundParticles.syncPositionsOnMainThread)
                        playgroundParticles.particleCache[p].position = playgroundParticles.playgroundCache.targetPosition[p];
                    playgroundParticles.playgroundCache.previousParticlePosition[p] = playgroundParticles.playgroundCache.targetPosition[p];
                    playgroundParticles.playgroundCache.collisionParticlePosition[p] = playgroundParticles.playgroundCache.targetPosition[p];
                }

                if (playgroundParticles.applyInitialColorOnRebirth) {
                    playgroundParticles.particleCache[p].color = playgroundParticles.playgroundCache.initialColor[p];
                    playgroundParticles.playgroundCache.color[p] = playgroundParticles.playgroundCache.initialColor[p];
                }
            } else {
                playgroundParticles.particleCache[p].position = PlaygroundC.initialTargetPosition;
            }

            // Set new random rotation
            if (playgroundParticles.applyRandomRotationOnRebirth && !playgroundParticles.rotateTowardsDirection)
                playgroundParticles.playgroundCache.initialRotation[p] = RandomRange(random, playgroundParticles.initialRotationMin, playgroundParticles.initialRotationMax);

            if (!playgroundParticles.rotateTowardsDirection)
                playgroundParticles.playgroundCache.rotation[p] = playgroundParticles.playgroundCache.initialRotation[p];
            else {
                Vector3 particleDir;
                if (!playgroundParticles.onlySourcePositioning&&playgroundParticles.onlyLifetimePositioning)
                    particleDir = (playgroundParticles.playgroundCache.position[p]+playgroundParticles.lifetimePositioning.Evaluate(.01f, playgroundParticles.lifetimePositioningScale))-playgroundParticles.playgroundCache.position[p];
                else
                    particleDir = playgroundParticles.playgroundCache.velocity[p];
                playgroundParticles.playgroundCache.rotation[p] = playgroundParticles.playgroundCache.initialRotation[p]+SignedAngle(
                    Vector3.up,
                    particleDir,
                    playgroundParticles.rotationNormal
                );
            }

            if (!playgroundParticles.syncPositionsOnMainThread)
                playgroundParticles.particleCache[p].rotation = playgroundParticles.playgroundCache.rotation[p];

            // Set size
            if (playgroundParticles.applyLifetimeSize && !playgroundParticles.applyParticleArraySize)
                playgroundParticles.playgroundCache.size[p] = playgroundParticles.playgroundCache.initialSize[p]*playgroundParticles.lifetimeSize.Evaluate(0)*playgroundParticles.scale;
            else if (playgroundParticles.applyLifetimeSize && playgroundParticles.applyParticleArraySize)
                playgroundParticles.playgroundCache.size[p] = playgroundParticles.playgroundCache.initialSize[p]*playgroundParticles.lifetimeSize.Evaluate(0)*playgroundParticles.particleArraySize.Evaluate((p*1f)/(playgroundParticles.particleCount*1f))*playgroundParticles.scale;
            else if (playgroundParticles.applyParticleArraySize)
                playgroundParticles.playgroundCache.size[p] = playgroundParticles.playgroundCache.initialSize[p]*playgroundParticles.particleArraySize.Evaluate((p*1f)/(playgroundParticles.particleCount*1f))*playgroundParticles.scale;
            else playgroundParticles.playgroundCache.size[p] = playgroundParticles.playgroundCache.initialSize[p]*playgroundParticles.scale;
            if (!playgroundParticles.syncPositionsOnMainThread)
                playgroundParticles.particleCache[p].size = playgroundParticles.playgroundCache.maskAlpha[p]>0?playgroundParticles.playgroundCache.size[p]:0;

            // Set color gradient id
            if (playgroundParticles.colorSource==COLORSOURCEC.LifetimeColors && playgroundParticles.lifetimeColors.Count>0) {
                playgroundParticles.lifetimeColorId++;playgroundParticles.lifetimeColorId=playgroundParticles.lifetimeColorId%playgroundParticles.lifetimeColors.Count;
                playgroundParticles.playgroundCache.lifetimeColorId[p] = playgroundParticles.lifetimeColorId;
            }

            // Local Manipulators
            if (playgroundParticles.calculateManipulatorOnRebirth) {
                for (int m = 0; m<playgroundParticles.manipulators.Count; m++) {
                    if (playgroundParticles.manipulators[m].transform!=null) {
                        CalculateManipulator(playgroundParticles, playgroundParticles.manipulators[m], p, playgroundParticles.t, playgroundParticles.playgroundCache.life[p], playgroundParticles.playgroundCache.position[p], (playgroundParticles.localSpace?playgroundParticles.manipulators[m].transform.localPosition:playgroundParticles.manipulators[m].transform.position)+playgroundParticles.manipulatorFix, playgroundParticles.localSpace);
                    }
                }
            }

            // Send birth event
            if (playgroundParticles.events.Count>0 && playgroundParticles.playgroundCache.rebirth[p])
                playgroundParticles.SendEvent(EVENTTYPEC.Birth, p);
            if (playgroundParticles.hasEventManipulatorLocal) {
                for (int i = 0; i<playgroundParticles.manipulators.Count; i++) {
                    if (playgroundParticles.manipulators[i].trackParticles &&
                        playgroundParticles.manipulators[i].sendEventBirth &&
                        playgroundParticles.manipulators[i].Contains (playgroundParticles.playgroundCache.targetPosition[p], playgroundParticles.manipulators[i].transform.position)) {

                        playgroundParticles.UpdateEventParticle(playgroundParticles.manipulators[i].manipulatorEventParticle, p);
                        playgroundParticles.manipulators[i].SendParticleEventBirth();
                    }
                }
            }
            if (playgroundParticles.hasEventManipulatorGlobal) {
                for (int i = 0; i<PlaygroundC.reference.manipulators.Count; i++) {
                    if (PlaygroundC.reference.manipulators[i].trackParticles &&
                        PlaygroundC.reference.manipulators[i].sendEventBirth &&
                        PlaygroundC.reference.manipulators[i].Contains (playgroundParticles.playgroundCache.targetPosition[p], PlaygroundC.reference.manipulators[i].transform.position)) {

                        playgroundParticles.UpdateEventParticle(PlaygroundC.reference.manipulators[i].manipulatorEventParticle, p);
                        PlaygroundC.reference.manipulators[i].SendParticleEventBirth();
                    }
                }
            }
        }
        /// <summary>
        /// Calculates particle collisions, this runs automatically if collision is set to true. (Must currently run on main-thread due to the Physics.Raycast dependency.)
        /// </summary>
        /// <param name="playgroundParticles">Particle Playground system.</param>
        public static void Collisions(PlaygroundParticlesC playgroundParticles)
        {
            if (!playgroundParticles.onlySourcePositioning && !playgroundParticles.onlyLifetimePositioning && playgroundParticles.collisionRadius>0) {
                Ray ray = new Ray();
                float distance;
                bool is3d = playgroundParticles.collisionType==COLLISIONTYPEC.Physics3D;
                bool hasCollisionExclusion = playgroundParticles.collisionExclusion!=null && playgroundParticles.collisionExclusion.Count>0;
                RaycastHit hitInfo;
                RaycastHit2D hitInfo2D;
                bool hasEvents = playgroundParticles.events.Count>0;
                Vector3 preCollisionVelocity;

                // Prepare the infinite collision planes
                if (playgroundParticles.collision && playgroundParticles.colliders.Count>0) {
                    for (int c = 0; c<playgroundParticles.colliders.Count; c++) {
                        playgroundParticles.colliders[c].UpdatePlane();
                    }
                }

                // Check cache length
                if (playgroundParticles.playgroundCache.noForce.Length!=playgroundParticles.particleCount)
                    playgroundParticles.playgroundCache.noForce = new bool[playgroundParticles.particleCount];
                if (playgroundParticles.playgroundCache.lifetimeSubtraction.Length!=playgroundParticles.particleCount)
                    playgroundParticles.playgroundCache.lifetimeSubtraction = new float[playgroundParticles.particleCount];

                for (int p = 0; p<playgroundParticles.particleCount; p++) {

                    if (playgroundParticles.playgroundCache.life[p]==0 || playgroundParticles.playgroundCache.life[p]>=(playgroundParticles.playgroundCache.death[p]-playgroundParticles.playgroundCache.birth[p])-playgroundParticles.playgroundCache.lifetimeSubtraction[p] || playgroundParticles.playgroundCache.noForce[p]) continue;

                    // Playground Plane colliders (never exceed these)
                    for (int c = 0; c<playgroundParticles.colliders.Count; c++) {
                        if (playgroundParticles.colliders[c].enabled && playgroundParticles.colliders[c].transform && !playgroundParticles.colliders[c].plane.GetSide(playgroundParticles.playgroundCache.position[p])) {

                            // Set particle to location
                            ray.origin = playgroundParticles.playgroundCache.position[p];
                            ray.direction = playgroundParticles.colliders[c].plane.normal;
                            if (playgroundParticles.colliders[c].plane.Raycast(ray, out distance))
                                playgroundParticles.playgroundCache.position[p] = ray.GetPoint(distance);

                            // Store velocity before collision
                            preCollisionVelocity = playgroundParticles.playgroundCache.velocity[p];

                            // Reflect particle
                            playgroundParticles.playgroundCache.velocity[p] = Vector3.Reflect(playgroundParticles.playgroundCache.velocity[p], playgroundParticles.colliders[c].plane.normal+RandomVector3(playgroundParticles.internalRandom01, playgroundParticles.bounceRandomMin, playgroundParticles.bounceRandomMax))*playgroundParticles.bounciness;

                            // Apply lifetime loss
                            if (playgroundParticles.lifetimeLoss>0) {
                                playgroundParticles.playgroundCache.birth[p] -= playgroundParticles.playgroundCache.life[p]/(1f-playgroundParticles.lifetimeLoss);
                                playgroundParticles.playgroundCache.changedByPropertyDeath[p] = true;
                            }

                            // Send event
                            if (hasEvents)
                                playgroundParticles.SendEvent(EVENTTYPEC.Collision, p, preCollisionVelocity, playgroundParticles.colliders[c].transform);
                        }
                    }

                    // Colliders in scene
                    if (playgroundParticles.playgroundCache.velocity[p].magnitude>PlaygroundC.collisionSleepVelocity) {

                        // Collide by checking for potential passed collider in the direction of this particle's velocity from the previous frame
                        if (is3d) {
                            if (Physics.Raycast(
                                playgroundParticles.playgroundCache.collisionParticlePosition[p],
                                (playgroundParticles.playgroundCache.position[p]-playgroundParticles.playgroundCache.collisionParticlePosition[p]).normalized,
                                out hitInfo,
                                (Vector3.SqrMagnitude(playgroundParticles.playgroundCache.position[p]-playgroundParticles.playgroundCache.collisionParticlePosition[p])+playgroundParticles.collisionRadius)*2f,
                                playgroundParticles.collisionMask))
                            {

                                // Check that this object isn't excluded
                                if (hasCollisionExclusion) {
                                    if (playgroundParticles.collisionExclusion.Contains(hitInfo.transform))
                                        continue;
                                }

                                // Set particle to location
                                playgroundParticles.playgroundCache.position[p] = playgroundParticles.playgroundCache.collisionParticlePosition[p];

                                // Store velocity before collision
                                preCollisionVelocity = playgroundParticles.playgroundCache.velocity[p];

                                // Reflect particle
                                playgroundParticles.playgroundCache.velocity[p] = Vector3.Reflect(playgroundParticles.playgroundCache.velocity[p], hitInfo.normal+RandomVector3(playgroundParticles.internalRandom01, playgroundParticles.bounceRandomMin, playgroundParticles.bounceRandomMax))*playgroundParticles.bounciness;

                                // Apply lifetime loss
                                if (playgroundParticles.lifetimeLoss>0) {
                                    playgroundParticles.playgroundCache.birth[p] -= playgroundParticles.playgroundCache.life[p]/(1f-playgroundParticles.lifetimeLoss);
                                    playgroundParticles.playgroundCache.changedByPropertyDeath[p] = true;
                                }

                                // Add force to rigidbody
                                if (playgroundParticles.affectRigidbodies && hitInfo.rigidbody)
                                    hitInfo.rigidbody.AddForceAtPosition((playgroundParticles.inverseRigidbodyCollision?-preCollisionVelocity:preCollisionVelocity)*playgroundParticles.mass, playgroundParticles.playgroundCache.position[p]);

                                // Send event
                                if (hasEvents)
                                    playgroundParticles.SendEvent(EVENTTYPEC.Collision, p, preCollisionVelocity, hitInfo.transform, hitInfo.collider);
                                if (playgroundParticles.hasEventManipulatorLocal) {
                                    for (int i = 0; i<playgroundParticles.manipulators.Count; i++) {
                                        if (playgroundParticles.manipulators[i].trackParticles &&
                                            playgroundParticles.manipulators[i].sendEventCollision &&
                                            playgroundParticles.manipulators[i].Contains (playgroundParticles.playgroundCache.position[p], playgroundParticles.manipulators[i].transform.position)) {

                                            playgroundParticles.UpdateEventParticle(playgroundParticles.manipulators[i].manipulatorEventParticle, p);
                                            playgroundParticles.manipulators[i].manipulatorEventParticle.collisionCollider = hitInfo.collider;
                                            playgroundParticles.manipulators[i].manipulatorEventParticle.collisionParticlePosition = hitInfo.point;
                                            playgroundParticles.manipulators[i].manipulatorEventParticle.collisionTransform = hitInfo.transform;
                                            playgroundParticles.manipulators[i].SendParticleEventCollision();
                                        }
                                    }
                                }
                                if (playgroundParticles.hasEventManipulatorGlobal) {
                                    for (int i = 0; i<PlaygroundC.reference.manipulators.Count; i++) {
                                        if (PlaygroundC.reference.manipulators[i].trackParticles &&
                                            PlaygroundC.reference.manipulators[i].sendEventCollision &&
                                            PlaygroundC.reference.manipulators[i].Contains (playgroundParticles.playgroundCache.position[p], PlaygroundC.reference.manipulators[i].transform.position)) {

                                            playgroundParticles.UpdateEventParticle(PlaygroundC.reference.manipulators[i].manipulatorEventParticle, p);
                                            playgroundParticles.manipulators[i].manipulatorEventParticle.collisionCollider = hitInfo.collider;
                                            playgroundParticles.manipulators[i].manipulatorEventParticle.collisionParticlePosition = hitInfo.point;
                                            playgroundParticles.manipulators[i].manipulatorEventParticle.collisionTransform = hitInfo.transform;
                                            PlaygroundC.reference.manipulators[i].SendParticleEventCollision();
                                        }
                                    }
                                }
                            }
                        } else {
                            hitInfo2D = Physics2D.Raycast(
                                playgroundParticles.playgroundCache.collisionParticlePosition[p],
                                (playgroundParticles.playgroundCache.position[p]-playgroundParticles.playgroundCache.collisionParticlePosition[p]).normalized,
                                (Vector3.SqrMagnitude(playgroundParticles.playgroundCache.position[p]-playgroundParticles.playgroundCache.collisionParticlePosition[p])+playgroundParticles.collisionRadius)*2f,
                                playgroundParticles.collisionMask,
                                playgroundParticles.minCollisionDepth,
                                playgroundParticles.maxCollisionDepth
                            );
                            if (hitInfo2D.collider!=null) {

                                // Check that this object isn't excluded
                                if (hasCollisionExclusion) {
                                    if (playgroundParticles.collisionExclusion.Contains(hitInfo2D.transform))
                                        continue;
                                }

                                // Set particle to location
                                playgroundParticles.playgroundCache.position[p] = playgroundParticles.playgroundCache.collisionParticlePosition[p];

                                // Store velocity before collision
                                preCollisionVelocity = playgroundParticles.playgroundCache.velocity[p];

                                // Reflect particle
                                playgroundParticles.playgroundCache.velocity[p] = Vector3.Reflect(playgroundParticles.playgroundCache.velocity[p], (Vector3)hitInfo2D.normal+RandomVector3(playgroundParticles.internalRandom01, playgroundParticles.bounceRandomMin, playgroundParticles.bounceRandomMax))*playgroundParticles.bounciness;

                                // Apply lifetime loss
                                if (playgroundParticles.lifetimeLoss>0) {
                                    playgroundParticles.playgroundCache.birth[p] -= playgroundParticles.playgroundCache.life[p]/(1f-playgroundParticles.lifetimeLoss);
                                    playgroundParticles.playgroundCache.changedByPropertyDeath[p] = true;
                                }

                                // Add force to rigidbody
                                if (playgroundParticles.affectRigidbodies && hitInfo2D.rigidbody)
                                    hitInfo2D.rigidbody.AddForceAtPosition((playgroundParticles.inverseRigidbodyCollision?-preCollisionVelocity:preCollisionVelocity)*playgroundParticles.mass, playgroundParticles.playgroundCache.position[p]);

                                // Send event
                                if (hasEvents)
                                    playgroundParticles.SendEvent(EVENTTYPEC.Collision, p, preCollisionVelocity, hitInfo2D.transform, hitInfo2D.collider);
                                if (playgroundParticles.hasEventManipulatorLocal) {
                                    for (int i = 0; i<playgroundParticles.manipulators.Count; i++) {
                                        if (playgroundParticles.manipulators[i].trackParticles &&
                                            playgroundParticles.manipulators[i].sendEventCollision &&
                                            playgroundParticles.manipulators[i].Contains (playgroundParticles.playgroundCache.position[p], playgroundParticles.manipulators[i].transform.position)) {

                                            playgroundParticles.UpdateEventParticle(playgroundParticles.manipulators[i].manipulatorEventParticle, p);
                                            playgroundParticles.manipulators[i].manipulatorEventParticle.collisionCollider2D = hitInfo2D.collider;
                                            playgroundParticles.manipulators[i].manipulatorEventParticle.collisionParticlePosition = hitInfo2D.point;
                                            playgroundParticles.manipulators[i].manipulatorEventParticle.collisionTransform = hitInfo2D.transform;
                                            playgroundParticles.manipulators[i].SendParticleEventCollision();
                                        }
                                    }
                                }
                                if (playgroundParticles.hasEventManipulatorGlobal) {
                                    for (int i = 0; i<PlaygroundC.reference.manipulators.Count; i++) {
                                        if (PlaygroundC.reference.manipulators[i].trackParticles &&
                                            PlaygroundC.reference.manipulators[i].sendEventCollision &&
                                            PlaygroundC.reference.manipulators[i].Contains (playgroundParticles.playgroundCache.position[p], PlaygroundC.reference.manipulators[i].transform.position)) {

                                            playgroundParticles.UpdateEventParticle(PlaygroundC.reference.manipulators[i].manipulatorEventParticle, p);
                                            playgroundParticles.manipulators[i].manipulatorEventParticle.collisionCollider2D = hitInfo2D.collider;
                                            playgroundParticles.manipulators[i].manipulatorEventParticle.collisionParticlePosition = hitInfo2D.point;
                                            playgroundParticles.manipulators[i].manipulatorEventParticle.collisionTransform = hitInfo2D.transform;
                                            PlaygroundC.reference.manipulators[i].SendParticleEventCollision();
                                        }
                                    }
                                }
                            }
                        }
                    } else {
                        playgroundParticles.playgroundCache.velocity[p] = Vector3.zero;
                    }
                }
            }
        }
        /// <summary>
        /// Calculates the effect from a Manipulator.
        /// </summary>
        /// <param name="playgroundParticles">Playground particles.</param>
        /// <param name="thisManipulator">This manipulator.</param>
        /// <param name="p">Particle index.</param>
        /// <param name="t">Delta time.</param>
        /// <param name="life">Lifetime.</param>
        /// <param name="particlePosition">Particle position.</param>
        /// <param name="manipulatorPosition">Manipulator position.</param>
        /// <param name="manipulatorDistance">Manipulator distance.</param>
        /// <param name="localSpace">Is calculation in local space?</param>
        public static void CalculateManipulator(PlaygroundParticlesC playgroundParticles, ManipulatorObjectC thisManipulator, int p, float t, float life, Vector3 particlePosition, Vector3 manipulatorPosition, bool localSpace)
        {
            if (thisManipulator.enabled && thisManipulator.transform.available && thisManipulator.strength!=0 && thisManipulator.LifetimeFilter(life, playgroundParticles.lifetime) && thisManipulator.ParticleFilter (p, playgroundParticles.particleCount)) {

                bool contains = thisManipulator.Contains(localSpace?(playgroundParticles.particleSystemRotation*particlePosition):particlePosition, localSpace?(playgroundParticles.particleSystemRotation*manipulatorPosition):manipulatorPosition);

                // Is this a particle which shouldn't be affected by this manipulator?
                if (contains && (playgroundParticles.playgroundCache.excludeFromManipulatorId[p]==thisManipulator.manipulatorId || thisManipulator.nonAffectedParticles.Count>0 && thisManipulator.ContainsNonAffectedParticle(playgroundParticles.particleSystemId, p))) {
                    return;
                }

                // Manipulator events
                if (thisManipulator.trackParticles) {

                    // Particle entering
                    if (contains) {
                        if ((thisManipulator.trackingMethod==TrackingMethod.ManipulatorId && !thisManipulator.IsSameId(playgroundParticles.playgroundCache.manipulatorId[p])) || (thisManipulator.trackingMethod==TrackingMethod.ParticleId && !thisManipulator.ContainsParticle(playgroundParticles.particleSystemId, p))) {
                            playgroundParticles.playgroundCache.manipulatorId[p] = thisManipulator.manipulatorId;
                            thisManipulator.AddParticle(playgroundParticles.particleSystemId, p);
                            if (thisManipulator.sendEventEnter) {
                                playgroundParticles.UpdateEventParticle(thisManipulator.manipulatorEventParticle, p);
                                thisManipulator.SendParticleEventEnter();
                            }
                        }
                    } else {

                        // Particle exiting
                        if ((thisManipulator.trackingMethod==TrackingMethod.ManipulatorId && thisManipulator.IsSameId(playgroundParticles.playgroundCache.manipulatorId[p])) || (thisManipulator.trackingMethod==TrackingMethod.ParticleId && thisManipulator.ContainsParticle(playgroundParticles.particleSystemId, p))) {
                            playgroundParticles.playgroundCache.manipulatorId[p] = 0;
                            thisManipulator.RemoveParticle(playgroundParticles.particleSystemId, p);
                            if (thisManipulator.sendEventExit) {
                                playgroundParticles.UpdateEventParticle(thisManipulator.manipulatorEventParticle, p);
                                thisManipulator.SendParticleEventExit();
                            }
                        }
                    }
                }

                float manipulatorDistance = 0;

                if (!playgroundParticles.onlySourcePositioning && !playgroundParticles.playgroundCache.noForce[p]) {
                    // Attractors
                    if (thisManipulator.type==MANIPULATORTYPEC.Attractor) {
                        if (contains) {
                            manipulatorDistance = thisManipulator.strengthDistanceEffect>0?Vector3.Distance (manipulatorPosition, playgroundParticles.playgroundCache.position[p])/thisManipulator.strengthDistanceEffect:10f;
                            playgroundParticles.playgroundCache.velocity[p] = Vector3.Lerp(playgroundParticles.playgroundCache.velocity[p], (manipulatorPosition-particlePosition)*(thisManipulator.strength/manipulatorDistance), t*(thisManipulator.strength/manipulatorDistance)/thisManipulator.strengthSmoothing);
                        }
                    } else

                    // Attractors Gravitational
                    if (thisManipulator.type==MANIPULATORTYPEC.AttractorGravitational) {
                        if (contains) {
                            manipulatorDistance = thisManipulator.strengthDistanceEffect>0?Vector3.Distance (manipulatorPosition, playgroundParticles.playgroundCache.position[p])/thisManipulator.strengthDistanceEffect:10f;
                            playgroundParticles.playgroundCache.velocity[p] = Vector3.Lerp(playgroundParticles.playgroundCache.velocity[p], (manipulatorPosition-particlePosition)*thisManipulator.strength/manipulatorDistance, t/thisManipulator.strengthSmoothing);
                        }
                    } else

                    // Repellents
                    if (thisManipulator.type==MANIPULATORTYPEC.Repellent) {
                        if (contains) {
                            manipulatorDistance = thisManipulator.strengthDistanceEffect>0?Vector3.Distance (manipulatorPosition, playgroundParticles.playgroundCache.position[p])/thisManipulator.strengthDistanceEffect:10f;
                            playgroundParticles.playgroundCache.velocity[p] = Vector3.Lerp(playgroundParticles.playgroundCache.velocity[p], (particlePosition-manipulatorPosition)*(thisManipulator.strength/manipulatorDistance), t*(thisManipulator.strength/manipulatorDistance)/thisManipulator.strengthSmoothing);
                        }
                    } else

                    // Vortex
                    if (thisManipulator.type==MANIPULATORTYPEC.Vortex) {
                        if (contains) {
                            manipulatorDistance = thisManipulator.strengthDistanceEffect>0?Vector3.Distance (manipulatorPosition, playgroundParticles.playgroundCache.position[p])/thisManipulator.strengthDistanceEffect:10f;
                            playgroundParticles.playgroundCache.velocity[p] = Vector3.Lerp(playgroundParticles.playgroundCache.velocity[p], ((manipulatorPosition-particlePosition)*thisManipulator.strength/manipulatorDistance)-Vector3.Cross(thisManipulator.transform.up, (manipulatorPosition-particlePosition))*thisManipulator.strength/manipulatorDistance, (t*thisManipulator.strength/manipulatorDistance)/thisManipulator.strengthSmoothing);
                        }
                    }
                }

                // Properties
                if (thisManipulator.type==MANIPULATORTYPEC.Property) {
                    manipulatorDistance = thisManipulator.strengthDistanceEffect>0?Vector3.SqrMagnitude (manipulatorPosition - particlePosition)/thisManipulator.strengthDistanceEffect:10f;
                    PropertyManipulator(playgroundParticles, thisManipulator, thisManipulator.property, p, t, particlePosition, manipulatorPosition, manipulatorDistance, localSpace, contains);
                } else

                // Combined
                if (thisManipulator.type==MANIPULATORTYPEC.Combined) {
                    manipulatorDistance = thisManipulator.strengthDistanceEffect>0?Vector3.SqrMagnitude (manipulatorPosition - particlePosition)/thisManipulator.strengthDistanceEffect:10f;
                    for (int i = 0; i<thisManipulator.properties.Count; i++)
                        PropertyManipulator(playgroundParticles, thisManipulator, thisManipulator.properties[i], p, t, particlePosition, manipulatorPosition, manipulatorDistance, localSpace, contains);
                }
            }
        }
        // Rebirth of a specified particle
        public static void Rebirth(PlaygroundParticlesC playgroundParticles, int p, System.Random random)
        {
            if (!playgroundParticles.hasActiveParticles) return;
            // Set initial values
            playgroundParticles.playgroundCache.rebirth[p] = playgroundParticles.source==SOURCEC.Script?true:(playgroundParticles.emit && (playgroundParticles.loop || playgroundParticles.playgroundCache.isNonBirthed[p]) && playgroundParticles.playgroundCache.emission[p]);
            playgroundParticles.playgroundCache.isFirstLoop[p] = playgroundParticles.playgroundCache.isNonBirthed[p];
            playgroundParticles.playgroundCache.isNonBirthed[p] = false;
            playgroundParticles.playgroundCache.birthDelay[p] = 0f;
            playgroundParticles.playgroundCache.life[p] = 0f;
            playgroundParticles.playgroundCache.birth[p] = playgroundParticles.playgroundCache.death[p];
            playgroundParticles.playgroundCache.death[p] += playgroundParticles.lifetime;
            playgroundParticles.playgroundCache.velocity[p] = Vector3.zero;
            playgroundParticles.playgroundCache.noForce[p] = false;

            // Set new random lifetime
            if (playgroundParticles.applyRandomLifetimeOnRebirth) {
                if (playgroundParticles.lifetimeValueMethod==VALUEMETHOD.Constant) {
                    playgroundParticles.playgroundCache.lifetimeSubtraction[p] = 0;
                } else {
                    playgroundParticles.playgroundCache.lifetimeSubtraction[p] = playgroundParticles.lifetime-RandomRange (random, playgroundParticles.lifetimeMin, playgroundParticles.lifetime);
                }
            }

            // Set new random size
            if (playgroundParticles.applyRandomSizeOnRebirth)
                playgroundParticles.playgroundCache.initialSize[p] = RandomRange(random, playgroundParticles.sizeMin, playgroundParticles.sizeMax);

            // Initial velocity
            if (!playgroundParticles.onlySourcePositioning && !playgroundParticles.onlyLifetimePositioning) {

                // Initial global velocity
                if (playgroundParticles.applyInitialVelocity) {
                    if (playgroundParticles.applyRandomInitialVelocityOnRebirth)
                        playgroundParticles.playgroundCache.initialVelocity[p] = RandomRange(random, playgroundParticles.initialVelocityMin, playgroundParticles.initialVelocityMax);
                    playgroundParticles.playgroundCache.velocity[p] = playgroundParticles.playgroundCache.initialVelocity[p];

                    // Give this spawning particle its velocity shape
                    if (playgroundParticles.applyInitialVelocityShape)
                        playgroundParticles.playgroundCache.velocity[p] = Vector3.Scale(playgroundParticles.playgroundCache.velocity[p], playgroundParticles.initialVelocityShape.Evaluate((p*1f)/(playgroundParticles.particleCount*1f), playgroundParticles.initialVelocityShapeScale));
                }

                // Initial local velocity
                if (playgroundParticles.applyInitialLocalVelocity && playgroundParticles.source!=SOURCEC.Script) {
                    playgroundParticles.playgroundCache.initialLocalVelocity[p] = RandomRange(random, playgroundParticles.initialLocalVelocityMin, playgroundParticles.initialLocalVelocityMax);
                    playgroundParticles.playgroundCache.velocity[p] += playgroundParticles.playgroundCache.targetDirection[p];

                    // Give this spawning particle its local velocity shape
                    if (playgroundParticles.applyInitialVelocityShape)
                        playgroundParticles.playgroundCache.velocity[p] = Vector3.Scale(playgroundParticles.playgroundCache.velocity[p], playgroundParticles.initialVelocityShape.Evaluate((p*1f)/(playgroundParticles.particleCount*1f), playgroundParticles.initialVelocityShapeScale));
                }

                // Initial stretch
                if (playgroundParticles.renderModeStretch) {
                    if (playgroundParticles.playgroundCache.velocity[p]!=Vector3.zero)
                        playgroundParticles.particleCache[p].velocity = playgroundParticles.playgroundCache.velocity[p];
                    else
                        playgroundParticles.particleCache[p].velocity = playgroundParticles.stretchStartDirection;
                } else
                    playgroundParticles.particleCache[p].velocity = Vector3.zero;
            }
            if (playgroundParticles.source==SOURCEC.Script) {
                // Velocity for script mode
                if (!playgroundParticles.onlySourcePositioning && !playgroundParticles.onlyLifetimePositioning)
                    playgroundParticles.playgroundCache.velocity[p] += playgroundParticles.scriptedEmissionVelocity;
                playgroundParticles.playgroundCache.targetPosition[p] = playgroundParticles.scriptedEmissionPosition;
                playgroundParticles.particleCache[p].velocity = playgroundParticles.playgroundCache.velocity[p];
            }

            if (playgroundParticles.playgroundCache.rebirth[p]) {

                // Source Scattering
                if (playgroundParticles.applySourceScatter && playgroundParticles.source!=SOURCEC.Script) {
                    if (playgroundParticles.playgroundCache.scatterPosition[p]==Vector3.zero || playgroundParticles.applyRandomScatterOnRebirth)
                        playgroundParticles.playgroundCache.scatterPosition[p] = RandomRange(random, playgroundParticles.sourceScatterMin, playgroundParticles.sourceScatterMax);
                } else playgroundParticles.playgroundCache.scatterPosition[p] = Vector3.zero;

                if (!playgroundParticles.onlyLifetimePositioning) {
                    playgroundParticles.playgroundCache.position[p] = playgroundParticles.playgroundCache.targetPosition[p];
                    playgroundParticles.particleCache[p].position = playgroundParticles.playgroundCache.targetPosition[p];
                    playgroundParticles.playgroundCache.previousParticlePosition[p] = playgroundParticles.playgroundCache.targetPosition[p];
                    playgroundParticles.playgroundCache.collisionParticlePosition[p] = playgroundParticles.playgroundCache.targetPosition[p];
                } else if (!playgroundParticles.onlySourcePositioning) {
                    Vector3 evalLifetimePosition = playgroundParticles.lifetimePositioning.Evaluate(0f, playgroundParticles.lifetimePositioningScale);
                    if (playgroundParticles.lifetimePositioningUsesSourceDirection)
                        evalLifetimePosition = playgroundParticles.playgroundCache.targetDirection[p];
                    playgroundParticles.playgroundCache.position[p] = playgroundParticles.playgroundCache.targetPosition[p]+evalLifetimePosition;
                    playgroundParticles.particleCache[p].position = playgroundParticles.playgroundCache.targetPosition[p]+evalLifetimePosition;
                    playgroundParticles.playgroundCache.previousParticlePosition[p] = playgroundParticles.playgroundCache.targetPosition[p]+evalLifetimePosition;
                    playgroundParticles.playgroundCache.collisionParticlePosition[p] = playgroundParticles.playgroundCache.targetPosition[p]+evalLifetimePosition;
                }

                if (playgroundParticles.applyInitialColorOnRebirth) {
                    playgroundParticles.particleCache[p].color = playgroundParticles.playgroundCache.initialColor[p];
                    playgroundParticles.playgroundCache.color[p] = playgroundParticles.playgroundCache.initialColor[p];
                }
            } else {
                playgroundParticles.particleCache[p].position = PlaygroundC.initialTargetPosition;
            }

            // Set new random rotation
            if (playgroundParticles.applyRandomRotationOnRebirth && !playgroundParticles.rotateTowardsDirection)
                playgroundParticles.playgroundCache.initialRotation[p] = RandomRange(random, playgroundParticles.initialRotationMin, playgroundParticles.initialRotationMax);

            if (!playgroundParticles.rotateTowardsDirection)
                playgroundParticles.playgroundCache.rotation[p] = playgroundParticles.playgroundCache.initialRotation[p];
            else {
                Vector3 particleDir;
                if (!playgroundParticles.onlySourcePositioning&&playgroundParticles.onlyLifetimePositioning)
                    particleDir = (playgroundParticles.playgroundCache.position[p]+playgroundParticles.lifetimePositioning.Evaluate(.01f, playgroundParticles.lifetimePositioningScale))-playgroundParticles.playgroundCache.position[p];
                else
                    particleDir = playgroundParticles.playgroundCache.velocity[p];
                playgroundParticles.playgroundCache.rotation[p] = playgroundParticles.playgroundCache.initialRotation[p]+SignedAngle(
                    Vector3.up,
                    particleDir,
                    playgroundParticles.rotationNormal
                );
            }

            playgroundParticles.particleCache[p].rotation = playgroundParticles.playgroundCache.rotation[p];

            // Set size
            if (playgroundParticles.applyLifetimeSize) {
                //playgroundParticles.playgroundCache.size[p] = playgroundParticles.playgroundCache.initialSize[p]*playgroundParticles.lifetimeSize.Evaluate(0f)*playgroundParticles.scale;
            } else
                playgroundParticles.playgroundCache.size[p] = playgroundParticles.playgroundCache.initialSize[p]*playgroundParticles.scale;
            playgroundParticles.particleCache[p].size = p>=playgroundParticles.particleMask?playgroundParticles.playgroundCache.size[p]:0;

            // Set color gradient id
            if (playgroundParticles.colorSource==COLORSOURCEC.LifetimeColors && playgroundParticles.lifetimeColors.Count>0) {
                playgroundParticles.lifetimeColorId++;playgroundParticles.lifetimeColorId=playgroundParticles.lifetimeColorId%playgroundParticles.lifetimeColors.Count;
                playgroundParticles.playgroundCache.lifetimeColorId[p] = playgroundParticles.lifetimeColorId;
            }

            // Reset manipulators influence
            playgroundParticles.playgroundCache.changedByProperty[p] = false;
            playgroundParticles.playgroundCache.changedByPropertyColor[p] = false;
            playgroundParticles.playgroundCache.changedByPropertyColorLerp[p] = false;
            playgroundParticles.playgroundCache.changedByPropertyColorKeepAlpha[p] = false;
            playgroundParticles.playgroundCache.changedByPropertySize[p] = false;
            playgroundParticles.playgroundCache.changedByPropertyTarget[p] = false;
            playgroundParticles.playgroundCache.changedByPropertyDeath[p] = false;
            playgroundParticles.playgroundCache.propertyTarget[p] = 0;
            playgroundParticles.playgroundCache.propertyId[p] = 0;
            playgroundParticles.playgroundCache.propertyColorId[p] = 0;
            playgroundParticles.playgroundCache.manipulatorId[p] = 0;

            // Send birth event
            if (playgroundParticles.events.Count>0 && playgroundParticles.playgroundCache.rebirth[p])
                playgroundParticles.SendEvent(EVENTTYPEC.Birth, p);
            if (playgroundParticles.hasEventManipulatorLocal) {
                for (int i = 0; i<playgroundParticles.manipulators.Count; i++) {
                    if (playgroundParticles.manipulators[i].trackParticles &&
                        playgroundParticles.manipulators[i].sendEventBirth &&
                        playgroundParticles.manipulators[i].Contains (playgroundParticles.playgroundCache.targetPosition[p], playgroundParticles.manipulators[i].transform.position)) {

                        playgroundParticles.UpdateEventParticle(playgroundParticles.manipulators[i].manipulatorEventParticle, p);
                        playgroundParticles.manipulators[i].SendParticleEventBirth();
                    }
                }
            }
            if (playgroundParticles.hasEventManipulatorGlobal) {
                for (int i = 0; i<PlaygroundC.reference.manipulators.Count; i++) {
                    if (PlaygroundC.reference.manipulators[i].trackParticles &&
                        PlaygroundC.reference.manipulators[i].sendEventBirth &&
                        PlaygroundC.reference.manipulators[i].Contains (playgroundParticles.playgroundCache.targetPosition[p], PlaygroundC.reference.manipulators[i].transform.position)) {

                        playgroundParticles.UpdateEventParticle(PlaygroundC.reference.manipulators[i].manipulatorEventParticle, p);
                        PlaygroundC.reference.manipulators[i].SendParticleEventBirth();
                    }
                }
            }
        }