public static void ExplosionDamage(Vector2 at, float radius, float damage, Predicate <RigidBody> affectsObject) { // Iterate over all RigidBodies with a line-of-sight to the explosion center and damage them IterateLineOfSightBodies(at, radius, affectsObject, (body, hitData) => { Ship ship = body.GameObj.GetComponent <Ship>(); if (ship == null) { return; } float distanceFactor = MathF.Pow(1.0f - hitData.Fraction, 1.5f); ship.DoDamage(distanceFactor * damage); }); }
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(); }