using System; using System.Collections.Generic; using FarseerPhysics.Collision; using FarseerPhysics.Dynamics; using Microsoft.Xna.Framework; namespace FarseerPhysics.Common.PhysicsLogic { /// /// Creates a simple explosion that ignores other bodies hiding behind static bodies. /// public sealed class SimpleExplosion : PhysicsLogic { public SimpleExplosion(World world) : base(world, PhysicsLogicType.Explosion) { Power = 1; //linear } /// /// This is the power used in the power function. A value of 1 means the force /// applied to bodies in the explosion is linear. A value of 2 means it is exponential. /// public float Power { get; set; } /// /// Activate the explosion at the specified position. /// /// The position (center) of the explosion. /// The radius of the explosion. /// The force applied /// A maximum amount of force. When force gets over this value, it will be equal to maxForce /// A list of bodies and the amount of force that was applied to them. public Dictionary Activate(Vector2 pos, float radius, float force, float maxForce = float.MaxValue) { HashSet affectedBodies = new HashSet(); AABB aabb; aabb.LowerBound = pos - new Vector2(radius); aabb.UpperBound = pos + new Vector2(radius); // Query the world for bodies within the radius. World.QueryAABB(fixture => { if (Vector2.Distance(fixture.Body.Position, pos) <= radius) { if (!affectedBodies.Contains(fixture.Body)) affectedBodies.Add(fixture.Body); } return true; }, ref aabb); return ApplyImpulse(pos, radius, force, maxForce, affectedBodies); } private Dictionary ApplyImpulse(Vector2 pos, float radius, float force, float maxForce, HashSet overlappingBodies) { Dictionary forces = new Dictionary(overlappingBodies.Count); foreach (Body overlappingBody in overlappingBodies) { if (IsActiveOn(overlappingBody)) { float distance = Vector2.Distance(pos, overlappingBody.Position); float forcePercent = GetPercent(distance, radius); Vector2 forceVector = pos - overlappingBody.Position; forceVector *= 1f / (float)Math.Sqrt(forceVector.X * forceVector.X + forceVector.Y * forceVector.Y); forceVector *= MathHelper.Min(force * forcePercent, maxForce); forceVector *= -1; overlappingBody.ApplyLinearImpulse(forceVector); forces.Add(overlappingBody, forceVector); } } return forces; } private float GetPercent(float distance, float radius) { //(1-(distance/radius))^power-1 float percent = (float)Math.Pow(1 - ((distance - radius) / radius), Power) - 1; if (float.IsNaN(percent)) return 0f; return MathHelper.Clamp(percent, 0f, 1f); } } }