package com.arretadogames.pilot.entities; import com.arretadogames.pilot.entities.effects.EffectDescriptor; import com.arretadogames.pilot.entities.effects.EffectManager; import com.arretadogames.pilot.physics.PhysicalWorld; import com.arretadogames.pilot.render.AnimationManager; import com.arretadogames.pilot.render.AnimationSwitcher; import com.arretadogames.pilot.render.PhysicsRect; import com.arretadogames.pilot.render.opengl.GLCanvas; import org.jbox2d.callbacks.QueryCallback; import org.jbox2d.collision.AABB; import org.jbox2d.collision.shapes.PolygonShape; import org.jbox2d.common.Vec2; import org.jbox2d.dynamics.Body; import org.jbox2d.dynamics.BodyType; import org.jbox2d.dynamics.Fixture; import org.jbox2d.dynamics.World; import org.jbox2d.dynamics.contacts.Contact; import java.util.HashSet; import java.util.Set; public class Mine extends Entity { private static final float MINE_SIZE = 0.1f; private static final PhysicsRect MINE_IMAGE_SIZE = new PhysicsRect(0.6f, 0.6f); private static final PhysicsRect EXPLOSION_SIZE = new PhysicsRect(5, 5); private static final float PUSH_FORCE = 5; private static final float PARALYSIS_DURATION = 5; private AnimationSwitcher sprite; public Mine(float x, float y) { super(x, y); PolygonShape shape = new PolygonShape(); shape.setAsBox(MINE_SIZE / 2, MINE_SIZE / 2); Fixture bodyFixture = body.createFixture(shape, 50f); bodyFixture.setFriction(0.8f); body.setType(BodyType.DYNAMIC); body.setFixedRotation(true); physRect = MINE_IMAGE_SIZE; sprite = AnimationManager.getInstance().getSprite("mine"); } @Override public void render(GLCanvas canvas, float timeElapsed) { canvas.saveState(); canvas.translatePhysics(getPosX(), getPosY() + MINE_IMAGE_SIZE.height() / 2.3f); // Mine is on the bottom of the image canvas.rotate((float) (180 * - body.getAngle() / Math.PI)); sprite.render(canvas, physRect, timeElapsed); canvas.restoreState(); } @Override public EntityType getType() { return EntityType.MINE; } @Override public void setSprite(AnimationSwitcher sprite) { } @Override public void beginContact(Entity e, Contact contact) { if (e.getType() == EntityType.PLAYER && isAlive()) { Player p = (Player) e; p.paralyze(PARALYSIS_DURATION); EffectDescriptor effect = new EffectDescriptor(); effect.type = "explosion"; effect.pRect = EXPLOSION_SIZE; effect.position = body.getPosition().clone(); effect.layerPosition = Ground.GROUND_LAYER_POSITION - 1; EffectManager.getInstance().addEffect(effect); pushEntities(); kill(); PhysicalWorld.getInstance().addDeadEntity(this); } } private void pushEntities() { World world = body.getWorld(); Vec2 upperVertex = new Vec2(body.getPosition().x + EXPLOSION_SIZE.width() / 2, body.getPosition().y + EXPLOSION_SIZE.height() / 2); Vec2 lowerVertex = new Vec2(body.getPosition().x - EXPLOSION_SIZE.width() / 2, body.getPosition().y - EXPLOSION_SIZE.height() / 2); AABB aabb = new AABB(lowerVertex, upperVertex); final Set<Entity> affectedEntities = new HashSet<Entity>(); world.queryAABB(new QueryCallback() { @Override public boolean reportFixture(Fixture fixture) { Entity entity = (Entity) fixture.getBody().getUserData(); if (entity != null) { affectedEntities.add(entity); } return true; } }, aabb); Vec2 minePosition = body.getPosition(); for (Entity entity : affectedEntities) { Body b = entity.body; Vec2 pos = b.getPosition(); Vec2 pushDirection = pos.sub(minePosition); float distance = pushDirection.normalize(); // Normalizes the vector float halfExplosionSize = EXPLOSION_SIZE.width() / 2; float pushForce = (halfExplosionSize - distance) * PUSH_FORCE * b.getMass(); pushDirection.mulLocal(pushForce); entity.body.applyLinearImpulse(pushDirection, entity.body.getWorldCenter(), true); } } }