package fi.hbp.angr.models; import com.badlogic.gdx.math.MathUtils; import com.badlogic.gdx.math.Vector2; import com.badlogic.gdx.physics.box2d.Body; import com.badlogic.gdx.physics.box2d.BodyDef.BodyType; import com.badlogic.gdx.physics.box2d.Fixture; import com.badlogic.gdx.physics.box2d.QueryCallback; /** * Explosion model. */ public class Explosion { private final Body body; private final float maxDistance; private final float maxForce; private final Vector2 bodyPos = new Vector2(); private final Vector2 hitBodyPos = new Vector2(); /** * Class constructor. * @param body the body that sends the shock. */ public Explosion(Body body) { this.maxDistance = 9.0f; this.maxForce = 80.0f; this.body = body; } /** * Class constructor with configurable maximum distance and force. * @param body the body that sends the shock. * @param maxDist the maximum distance of shock wave. * @param maxForce the maximum force applied. */ public Explosion(Body body, float maxDist, float maxForce) { this.maxDistance = maxDist; this.maxForce = maxForce; this.body = body; } /** * Emits a shock impulse to the nearby bodies. */ public void doExplosion() { /* Set exploding body as static so it won't fly away */ BodyType origBdType = body.getType(); body.setType(BodyType.StaticBody); bodyPos.set(body.getPosition()); body.getWorld().QueryAABB(callback, bodyPos.x - maxDistance, bodyPos.y - maxDistance, bodyPos.x + maxDistance, bodyPos.y + maxDistance); /* Restore body type */ body.setType(origBdType); } private QueryCallback callback = new QueryCallback() { @Override public boolean reportFixture (Fixture fixture) { float force; float angle; Body hitBody = fixture.getBody(); hitBodyPos.set(hitBody.getPosition()); float distance = body.getPosition().dst(hitBodyPos); if (distance <= maxDistance) { /* Closer objects should feel greater force */ force = ((maxDistance - distance) / maxDistance) * maxForce; angle = MathUtils.atan2(hitBodyPos.y - bodyPos.y, hitBodyPos.x - bodyPos.x); /* Apply an impulse to the body, using the angle */ hitBody.applyLinearImpulse( new Vector2(MathUtils.cos(angle) * force, MathUtils.sin(angle) * force), hitBodyPos); } return true; /* Keep going until all bodies in the area are checked. */ } }; }