Example #1
0
        public void Initialize(ParticleEmitterConfig emitterConfig, Vector2 spawnPosition)
        {
            _collided = false;

            // init the position of the Particle. This is based on the source position of the particle emitter
            // plus a configured variance. The Random.minusOneToOne method allows the number to be both positive
            // and negative
            position.X = emitterConfig.SourcePositionVariance.X * Rand.MinusOneToOne();
            position.Y = emitterConfig.SourcePositionVariance.Y * Rand.MinusOneToOne();

            this.spawnPosition = spawnPosition;

            // init the direction of the   The newAngle is calculated using the angle passed in and the
            // angle variance.
            var newAngle =
                MathHelper.ToRadians(emitterConfig.Angle + emitterConfig.AngleVariance * Rand.MinusOneToOne());

            // create a new Vector2 using the newAngle
            var vector = new Vector2(Mathf.Cos(newAngle), Mathf.Sin(newAngle));

            // calculate the vectorSpeed using the speed and speedVariance which has been passed in
            var vectorSpeed = emitterConfig.Speed + emitterConfig.SpeedVariance * Rand.MinusOneToOne();

            // the particles direction vector is calculated by taking the vector calculated above and
            // multiplying that by the speed
            _direction = vector * vectorSpeed;

            // calculate the particles life span using the life span and variance passed in
            _timeToLive = MathHelper.Max(0,
                                         emitterConfig.ParticleLifespan + emitterConfig.ParticleLifespanVariance * Rand.MinusOneToOne());
            _particleLifetime = _timeToLive;

            var startRadius = emitterConfig.MaxRadius + emitterConfig.MaxRadiusVariance * Rand.MinusOneToOne();
            var endRadius   = emitterConfig.MinRadius + emitterConfig.MinRadiusVariance * Rand.MinusOneToOne();

            // set the default diameter of the particle from the source position
            _radius           = startRadius;
            _radiusDelta      = (endRadius - startRadius) / _timeToLive;
            _angle            = MathHelper.ToRadians(emitterConfig.Angle + emitterConfig.AngleVariance * Rand.MinusOneToOne());
            _degreesPerSecond = MathHelper.ToRadians(emitterConfig.RotatePerSecond +
                                                     emitterConfig.RotatePerSecondVariance * Rand.MinusOneToOne());

            _radialAcceleration = emitterConfig.RadialAcceleration +
                                  emitterConfig.RadialAccelVariance * Rand.MinusOneToOne();
            _tangentialAcceleration = emitterConfig.TangentialAcceleration +
                                      emitterConfig.TangentialAccelVariance * Rand.MinusOneToOne();

            // calculate the particle size using the start and finish particle sizes
            var particleStartSize = emitterConfig.StartParticleSize +
                                    emitterConfig.StartParticleSizeVariance * Rand.MinusOneToOne();
            var particleFinishSize = emitterConfig.FinishParticleSize +
                                     emitterConfig.FinishParticleSizeVariance * Rand.MinusOneToOne();

            _particleSizeDelta = (particleFinishSize - particleStartSize) / _timeToLive;
            particleSize       = MathHelper.Max(0, particleStartSize);


            // calculate the color the particle should have when it starts its life. All the elements
            // of the start color passed in along with the variance are used to calculate the start color
            _startColor = new Color
                          (
                (int)(emitterConfig.StartColor.R + emitterConfig.StartColorVariance.R * Rand.MinusOneToOne()),
                (int)(emitterConfig.StartColor.G + emitterConfig.StartColorVariance.G * Rand.MinusOneToOne()),
                (int)(emitterConfig.StartColor.B + emitterConfig.StartColorVariance.B * Rand.MinusOneToOne()),
                (int)(emitterConfig.StartColor.A + emitterConfig.StartColorVariance.A * Rand.MinusOneToOne())
                          );
            color = _startColor;

            // calculate the color the particle should be when its life is over. This is done the same
            // way as the start color above
            _finishColor = new Color
                           (
                (int)(emitterConfig.FinishColor.R + emitterConfig.FinishColorVariance.R * Rand.MinusOneToOne()),
                (int)(emitterConfig.FinishColor.G + emitterConfig.FinishColorVariance.G * Rand.MinusOneToOne()),
                (int)(emitterConfig.FinishColor.B + emitterConfig.FinishColorVariance.B * Rand.MinusOneToOne()),
                (int)(emitterConfig.FinishColor.A + emitterConfig.FinishColorVariance.A * Rand.MinusOneToOne())
                           );

            // calculate the rotation
            var startA = MathHelper.ToRadians(emitterConfig.RotationStart +
                                              emitterConfig.RotationStartVariance * Rand.MinusOneToOne());
            var endA = MathHelper.ToRadians(emitterConfig.RotationEnd +
                                            emitterConfig.RotationEndVariance * Rand.MinusOneToOne());

            rotation       = startA;
            _rotationDelta = (endA - startA) / _timeToLive;
        }
Example #2
0
        /// <summary>
        /// updates the particle. Returns true when the particle is no longer alive
        /// </summary>
        /// <param name="emitterConfig">Emitter config.</param>
        public bool Update(ParticleEmitterConfig emitterConfig, ref ParticleCollisionConfig collisionConfig,
                           Vector2 rootPosition)
        {
            // PART 1: reduce the life span of the particle
            _timeToLive -= Time.DeltaTime;

            // if the current particle is alive then update it
            if (_timeToLive > 0)
            {
                // only update the particle position if it has not collided. If it has, physics takes over
                if (!_collided)
                {
                    // if maxRadius is greater than 0 then the particles are going to spin otherwise they are affected by speed and gravity
                    if (emitterConfig.EmitterType == ParticleEmitterType.Radial)
                    {
                        // PART 2: update the angle of the particle from the radius. This is only done if the particles are rotating
                        _angle  += _degreesPerSecond * Time.DeltaTime;
                        _radius += _radiusDelta * Time.DeltaTime;

                        Vector2 tmp;
                        tmp.X = -Mathf.Cos(_angle) * _radius;
                        tmp.Y = -Mathf.Sin(_angle) * _radius;

                        _velocity = tmp - position;
                        position  = tmp;
                    }
                    else
                    {
                        Vector2 tmp, radial, tangential;
                        radial = Vector2.Zero;

                        if (position.X != 0 || position.Y != 0)
                        {
                            Vector2.Normalize(ref position, out radial);
                        }

                        tangential = radial;
                        radial     = radial * _radialAcceleration;

                        var newy = tangential.X;
                        tangential.X = -tangential.Y;
                        tangential.Y = newy;
                        tangential   = tangential * _tangentialAcceleration;

                        tmp        = radial + tangential + emitterConfig.Gravity;
                        tmp        = tmp * Time.DeltaTime;
                        _direction = _direction + tmp;
                        tmp        = _direction * Time.DeltaTime;

                        _velocity = tmp / Time.DeltaTime;
                        position  = position + tmp;
                    }
                }

                // update the particles color. we do the lerp from finish-to-start because timeToLive counts from particleLifespan to 0
                var t = (_particleLifetime - _timeToLive) / _particleLifetime;
                ColorExt.Lerp(ref _startColor, ref _finishColor, out color, t);

                // update the particle size
                particleSize += _particleSizeDelta * Time.DeltaTime;
                particleSize  = MathHelper.Max(0, particleSize);

                // update the rotation of the particle
                rotation += _rotationDelta * Time.DeltaTime;


                if (collisionConfig.Enabled)
                {
                    // if we already collided we have to handle the collision response
                    if (_collided)
                    {
                        // handle after collision movement. we need to track velocity for this
                        _velocity += collisionConfig.Gravity * Time.DeltaTime;
                        position  += _velocity * Time.DeltaTime;

                        // if we move too slow we die
                        if (_velocity.LengthSquared() < collisionConfig.MinKillSpeedSquared)
                        {
                            return(true);
                        }
                    }

                    // should we use our spawnPosition as a reference or the parent Transforms position?
                    var pos = emitterConfig.SimulateInWorldSpace ? spawnPosition : rootPosition;

                    _circleCollisionShape.RecalculateBounds(particleSize * 0.5f * collisionConfig.RadiusScale,
                                                            pos + position);
                    var neighbors = Physics.BoxcastBroadphase(ref _circleCollisionShape.bounds,
                                                              collisionConfig.CollidesWithLayers);
                    foreach (var neighbor in neighbors)
                    {
                        CollisionResult result;
                        if (_circleCollisionShape.CollidesWithShape(neighbor.Shape, out result))
                        {
                            // handle the overlap
                            position -= result.MinimumTranslationVector;
                            CalculateCollisionResponseVelocity(collisionConfig.Friction, collisionConfig.Elasticity,
                                                               ref result.MinimumTranslationVector);

                            // handle collision config props
                            _timeToLive -= _timeToLive * collisionConfig.LifetimeLoss;
                            _collided    = true;
                        }
                    }
                }
            }
            else
            {
                // timeToLive expired. were done
                return(true);
            }

            return(false);
        }