Example #1
0
        void ICmpUpdatable.OnUpdate()
        {
            Transform		transform	= this.GameObj.Transform;
            RigidBody		body		= this.GameObj.GetComponent<RigidBody>();
            ShipBlueprint	blueprint	= this.blueprint.Res;

            // Heal when damaged
            if (this.hitpoints < 1.0f)
            {
                this.hitpoints = MathF.Clamp(this.hitpoints + blueprint.HealRate * Time.SPFMult * Time.TimeMult / blueprint.MaxHitpoints, 0.0f, 1.0f);
            }

            // Apply force according to the desired thrust
            Vector2 actualVelocity = body.LinearVelocity;
            Vector2 targetVelocity = this.targetThrust * blueprint.MaxSpeed;
            Vector2 velocityDiff = (targetVelocity - actualVelocity);
            float sameDirectionFactor = Vector2.Dot(
                velocityDiff / MathF.Max(0.001f, velocityDiff.Length),
                this.targetThrust / MathF.Max(0.001f, this.targetThrust.Length));
            Vector2 thrusterActivity = this.targetThrust.Length * MathF.Max(sameDirectionFactor, 0.0f) * velocityDiff / MathF.Max(velocityDiff.Length, 1.0f);
            body.ApplyWorldForce(thrusterActivity * blueprint.ThrusterPower);

            // Turn to the desired fire angle
            if (this.targetAngleRatio > 0.0f)
            {
                float shortestTurnDirection	= MathF.TurnDir(transform.Angle, this.targetAngle);
                float shortestTurnLength	= MathF.CircularDist(transform.Angle, this.targetAngle);
                float turnDirection;
                float turnLength;
                if (MathF.Abs(body.AngularVelocity) > blueprint.MaxTurnSpeed * 0.25f)
                {
                    turnDirection	= MathF.Sign(body.AngularVelocity);
                    turnLength		= (turnDirection == shortestTurnDirection) ? shortestTurnLength : (MathF.RadAngle360 - shortestTurnLength);
                }
                else
                {
                    turnDirection	= shortestTurnDirection;
                    turnLength		= shortestTurnLength;
                }
                float turnSpeedRatio	= MathF.Min(turnLength * 0.25f, MathF.RadAngle30) / MathF.RadAngle30;
                float turnVelocity		= turnSpeedRatio * turnDirection * blueprint.MaxTurnSpeed * this.targetAngleRatio;
                body.AngularVelocity	+= (turnVelocity - body.AngularVelocity) * blueprint.TurnPower * Time.TimeMult;
            }

            // Weapon cooldown
            this.weaponTimer = MathF.Max(0.0f, this.weaponTimer - Time.MsPFMult * Time.TimeMult);

            // Play the owners special flight sound, when available
            if (this.owner != null && this.owner.FlightLoop != null)
            {
                SoundListener listener = Scene.Current.FindComponent<SoundListener>();
                Vector3 listenerPos = listener.GameObj.Transform.Pos;

                // Determine the target panning manually, because we don't want a true 3D sound here (doppler, falloff, ...)
                float targetPanning;
                if (listenerPos.Xy == transform.Pos.Xy || Player.AlivePlayers.Count() <= 1)
                    targetPanning = 0.0f;
                else
                    targetPanning = -Vector2.Dot(Vector2.UnitX, (listenerPos - transform.Pos).Xy.Normalized);

                // Determine the target volume
                float targetVolume = MathF.Clamp(this.targetThrust.Length, 0.0f, 1.0f);

                // Clean up disposed flight loop
                if (this.flightLoop != null && this.flightLoop.Disposed)
                    this.flightLoop = null;

                // Start the flight loop when requested
                if (targetVolume > 0.0f && this.flightLoop == null)
                {
                    if ((int)Time.MainTimer.TotalMilliseconds % 2976 <= (int)Time.MsPFMult)
                    {
                        this.flightLoop = DualityApp.Sound.PlaySound(this.owner.FlightLoop);
                        this.flightLoop.Looped = true;
                    }
                }

                // Configure existing flight loop
                if (this.flightLoop != null)
                {
                    this.flightLoop.Volume += (targetVolume - this.flightLoop.Volume) * 0.05f * Time.TimeMult;
                    this.flightLoop.Panning += (targetPanning - this.flightLoop.Panning) * 0.05f * Time.TimeMult;
                }
            }

            // Display the damage effect when damaged
            if (this.hitpoints < 0.85f && blueprint.DamageEffect != null)
            {
                // Create a new damage effect instance, if not present yet
                if (this.damageEffect == null)
                {
                    GameObject damageObj = blueprint.DamageEffect.Res.Instantiate(transform.Pos);
                    damageObj.Parent = this.GameObj;

                    this.damageEffect = damageObj.GetComponent<ParticleEffect>();
                    if (this.damageEffect == null) throw new NullReferenceException();
                }

                // Configure the damage effect
                foreach (ParticleEmitter emitter in this.damageEffect.Emitters)
                {
                    if (emitter == null) continue;
                    emitter.BurstDelay = new Range(50.0f + this.hitpoints * 50.0f, 100.0f + this.hitpoints * 300.0f);
                    if (this.owner != null)
                    {
                        ColorHsva targetColor = this.owner.Color.ToHsva();
                        emitter.MinColor = new ColorHsva(targetColor.H, targetColor.S, emitter.MinColor.V, emitter.MinColor.A);
                        emitter.MaxColor = new ColorHsva(targetColor.H, targetColor.S, emitter.MaxColor.V, emitter.MaxColor.A);
                    }
                }
            }
            // Get rid of existing damage effects, if no longer needed
            else if (this.damageEffect != null)
            {
                // Stop emitting and dispose when empty
                foreach (ParticleEmitter emitter in this.damageEffect.Emitters)
                {
                    if (emitter == null) continue;
                    emitter.BurstDelay = float.MaxValue;
                }
                this.damageEffect.DisposeWhenEmpty = true;
                this.damageEffect = null;
            }
        }
Example #2
0
		public void Update(ParticleEffect effect)
		{
			this.burstTimer -= Time.MsPFMult * Time.TimeMult;
			while (this.burstTimer <= 0.0f && (this.burstCount < this.maxBurstCount || this.maxBurstCount < 0))
			{
				this.burstTimer += MathF.Rnd.NextFloat(this.burstDelay.MinValue, this.burstDelay.MaxValue);
				this.burstCount++;

				int count = MathF.Rnd.Next((int)this.burstParticleNum.MinValue, (int)this.burstParticleNum.MaxValue);
				effect.AddParticles(this, count);
			}
		}
Example #3
0
        void ICmpUpdatable.OnUpdate()
        {
            Transform     transform = this.GameObj.Transform;
            RigidBody     body      = this.GameObj.GetComponent <RigidBody>();
            ShipBlueprint blueprint = this.blueprint.Res;

            // Heal when damaged
            if (this.hitpoints < 1.0f)
            {
                this.hitpoints = MathF.Clamp(this.hitpoints + blueprint.HealRate * Time.SPFMult * Time.TimeMult / blueprint.MaxHitpoints, 0.0f, 1.0f);
            }

            // Apply force according to the desired thrust
            Vector2 actualVelocity      = body.LinearVelocity;
            Vector2 targetVelocity      = this.targetThrust * blueprint.MaxSpeed;
            Vector2 velocityDiff        = (targetVelocity - actualVelocity);
            float   sameDirectionFactor = Vector2.Dot(
                velocityDiff / MathF.Max(0.001f, velocityDiff.Length),
                this.targetThrust / MathF.Max(0.001f, this.targetThrust.Length));
            Vector2 thrusterActivity = this.targetThrust.Length * MathF.Max(sameDirectionFactor, 0.0f) * velocityDiff / MathF.Max(velocityDiff.Length, 1.0f);

            if (thrusterActivity.Length > 0.00001f)             // Don't wake physics without actually doing work
            {
                body.ApplyWorldForce(thrusterActivity * blueprint.ThrusterPower);
            }

            // Turn to the desired fire angle
            if (this.targetAngleRatio > 0.0f)
            {
                float shortestTurnDirection = MathF.TurnDir(transform.Angle, this.targetAngle);
                float shortestTurnLength    = MathF.CircularDist(transform.Angle, this.targetAngle);
                float turnDirection;
                float turnLength;
                if (MathF.Abs(body.AngularVelocity) > blueprint.MaxTurnSpeed * 0.25f)
                {
                    turnDirection = MathF.Sign(body.AngularVelocity);
                    turnLength    = (turnDirection == shortestTurnDirection) ? shortestTurnLength : (MathF.RadAngle360 - shortestTurnLength);
                }
                else
                {
                    turnDirection = shortestTurnDirection;
                    turnLength    = shortestTurnLength;
                }
                float turnSpeedRatio        = MathF.Min(turnLength * 0.25f, MathF.RadAngle30) / MathF.RadAngle30;
                float turnVelocity          = turnSpeedRatio * turnDirection * blueprint.MaxTurnSpeed * this.targetAngleRatio;
                float angularVelocityChange = (turnVelocity - body.AngularVelocity) * blueprint.TurnPower;
                if (MathF.Abs(angularVelocityChange) > 0.0000001f)                 // Don't wake physics without actually doing work
                {
                    body.AngularVelocity += angularVelocityChange * Time.TimeMult;
                }
            }

            // Weapon cooldown
            this.weaponTimer = MathF.Max(0.0f, this.weaponTimer - Time.MsPFMult * Time.TimeMult);

            // Play the owners special flight sound, when available
            if (this.owner != null && this.owner.FlightLoop != null)
            {
                SoundListener listener    = Scene.Current.FindComponent <SoundListener>();
                Vector3       listenerPos = listener.GameObj.Transform.Pos;

                // Determine the target panning manually, because we don't want a true 3D sound here (doppler, falloff, ...)
                float targetPanning;
                if (listenerPos.Xy == transform.Pos.Xy || Player.AlivePlayers.Count() <= 1)
                {
                    targetPanning = 0.0f;
                }
                else
                {
                    targetPanning = -Vector2.Dot(Vector2.UnitX, (listenerPos - transform.Pos).Xy.Normalized);
                }

                // Determine the target volume
                float targetVolume = MathF.Clamp(this.targetThrust.Length, 0.0f, 1.0f);

                // Clean up disposed flight loop
                if (this.flightLoop != null && this.flightLoop.Disposed)
                {
                    this.flightLoop = null;
                }

                // Start the flight loop when requested
                if (targetVolume > 0.0f && this.flightLoop == null)
                {
                    if ((int)Time.MainTimer.TotalMilliseconds % 2976 <= (int)Time.MsPFMult)
                    {
                        this.flightLoop        = DualityApp.Sound.PlaySound(this.owner.FlightLoop);
                        this.flightLoop.Looped = true;
                    }
                }

                // Configure existing flight loop
                if (this.flightLoop != null)
                {
                    this.flightLoop.Volume  += (targetVolume - this.flightLoop.Volume) * 0.05f * Time.TimeMult;
                    this.flightLoop.Panning += (targetPanning - this.flightLoop.Panning) * 0.05f * Time.TimeMult;
                }
            }

            // Display the damage effect when damaged
            if (this.hitpoints < 0.85f && blueprint.DamageEffect != null)
            {
                // Create a new damage effect instance, if not present yet
                if (this.damageEffect == null)
                {
                    GameObject damageObj = blueprint.DamageEffect.Res.Instantiate(transform.Pos);
                    damageObj.Parent = this.GameObj;

                    this.damageEffect = damageObj.GetComponent <ParticleEffect>();
                    if (this.damageEffect == null)
                    {
                        throw new NullReferenceException();
                    }
                }

                // Configure the damage effect
                foreach (ParticleEmitter emitter in this.damageEffect.Emitters)
                {
                    if (emitter == null)
                    {
                        continue;
                    }
                    emitter.BurstDelay = new Range(50.0f + this.hitpoints * 50.0f, 100.0f + this.hitpoints * 300.0f);
                    if (this.owner != null)
                    {
                        ColorHsva targetColor = this.owner.Color.ToHsva();
                        emitter.MinColor = new ColorHsva(targetColor.H, targetColor.S, emitter.MinColor.V, emitter.MinColor.A);
                        emitter.MaxColor = new ColorHsva(targetColor.H, targetColor.S, emitter.MaxColor.V, emitter.MaxColor.A);
                    }
                }
            }
            // Get rid of existing damage effects, if no longer needed
            else if (this.damageEffect != null)
            {
                // Stop emitting and dispose when empty
                foreach (ParticleEmitter emitter in this.damageEffect.Emitters)
                {
                    if (emitter == null)
                    {
                        continue;
                    }
                    emitter.BurstDelay = float.MaxValue;
                }
                this.damageEffect.DisposeWhenEmpty = true;
                this.damageEffect = null;
            }
        }
Example #4
0
        void ICmpCollisionListener.OnCollisionBegin(Component sender, CollisionEventArgs args)
        {
            RigidBodyCollisionEventArgs bodyArgs = args as RigidBodyCollisionEventArgs;

            if (bodyArgs == null)
            {
                return;
            }
            if (bodyArgs.OtherShape.IsSensor)
            {
                return;
            }

            // Did we collide with a ship? If it's the same that fired the bullet, ignore this
            Ship otherShip = args.CollideWith.GetComponent <Ship>();

            if (otherShip != null && otherShip.Owner == this.owner)
            {
                return;
            }

            // Get all the objet references we'll need
            RigidBody       otherBody = args.CollideWith.RigidBody;
            Transform       transform = this.GameObj.Transform;
            RigidBody       body      = this.GameObj.RigidBody;
            BulletBlueprint blueprint = this.blueprint.Res;

            // Okay, let's determine where *exactly* our bullet hit
            RayCastData firstHit;
            bool        hitAnything = RigidBody.RayCast(transform.Pos.Xy - body.LinearVelocity * 2, transform.Pos.Xy + body.LinearVelocity * 2, data =>
            {
                if (data.Shape.IsSensor)
                {
                    return(-1.0f);
                }
                return(data.Fraction);
            }, out firstHit);

            Vector3 hitPos;
            float   hitAngle;

            if (hitAnything)
            {
                hitPos   = new Vector3(firstHit.Pos, 0.0f);
                hitAngle = (-firstHit.Normal).Angle;
            }
            else
            {
                // Note that it is possible for the raycast to not hit anything,
                // because it is essentially a line, while our bullet is wider than zero.
                hitPos   = transform.Pos;
                hitAngle = transform.Angle;
            }

            // Push around whatever we've just hit and do damage, if it was a ship
            otherBody.ApplyWorldImpulse(body.LinearVelocity * MathF.Min(otherBody.Mass, blueprint.ImpactMass), transform.Pos.Xy);
            if (otherShip != null)
            {
                otherShip.DoDamage(blueprint.Damage);
            }

            // If we hit a part of the world, spawn the world hit effect
            if (otherShip == null && blueprint.HitWorldEffect != null)
            {
                GameObject effectObj = blueprint.HitWorldEffect.Res.Instantiate(hitPos, hitAngle);
                Scene.Current.AddObject(effectObj);
            }

            // Also spawn a generic hit effect in the color of the bullet
            if (blueprint.HitEffect != null)
            {
                GameObject     effectObj = blueprint.HitEffect.Res.Instantiate(hitPos, hitAngle);
                ParticleEffect effect    = effectObj.GetComponent <ParticleEffect>();
                if (effect != null && this.owner != null)
                {
                    ColorHsva color = this.owner.Color.ToHsva();
                    foreach (ParticleEmitter emitter in effect.Emitters)
                    {
                        emitter.MaxColor = emitter.MaxColor.WithSaturation(color.S).WithHue(color.H);
                        emitter.MinColor = emitter.MinColor.WithSaturation(color.S).WithHue(color.H);
                    }
                }
                Scene.Current.AddObject(effectObj);
            }

            // Play hit sounds
            if (blueprint.HitSound != null)
            {
                SoundInstance inst = DualityApp.Sound.PlaySound3D(blueprint.HitSound, hitPos);
                inst.Pitch = MathF.Rnd.NextFloat(0.95f, 1.05f);
            }
            HitSoundController otherHitSound = otherBody.GameObj.GetComponent <HitSoundController>();

            if (otherHitSound != null)
            {
                otherHitSound.NotifyHit(MathF.Rnd.NextFloat(0.75f, 1.0f));
            }

            // Delete the bullet
            this.GameObj.DisposeLater();
        }