package org.andengine.extension.debugdraw; import java.util.ArrayList; import java.util.HashMap; import java.util.HashSet; import java.util.Iterator; import java.util.LinkedList; import java.util.Set; import org.andengine.entity.Entity; import org.andengine.extension.physics.box2d.PhysicsConnector; import org.andengine.extension.physics.box2d.PhysicsWorld; import org.andengine.opengl.vbo.VertexBufferObjectManager; import org.andengine.util.color.Color; import com.badlogic.gdx.physics.box2d.Body; import com.badlogic.gdx.physics.box2d.Fixture; import com.badlogic.gdx.physics.box2d.Shape.Type; public class DebugRenderer extends Entity { private PhysicsWorld mWorld; private final VertexBufferObjectManager mVBO; private HashMap<Body, RenderOfBody> mToBeRenderred = new HashMap<Body, RenderOfBody>(); private Set<RenderOfBody> mInactiveSet = new HashSet<RenderOfBody>(); private Set<RenderOfBody> mActiveSet = new HashSet<RenderOfBody>(); /** * To construct the renderer physical world is needed (to access physics) * and VBO (to construct visible representations) * @param world * @param pVBO */ public DebugRenderer(PhysicsWorld world, VertexBufferObjectManager pVBO) { super(); this.mWorld = world; this.mVBO = pVBO; } /** * This is where all the magic happens. Bodies representations are rendered. * Dead bodies (not being part of physical world anymore) are removed from * the rendering. */ @Override protected void onManagedUpdate(float pSecondsElapsed) { super.onManagedUpdate(pSecondsElapsed); mActiveSet.clear(); mInactiveSet.clear(); Iterator<Body> iterator = mWorld.getBodies(); while (iterator.hasNext()) { Body body = iterator.next(); RenderOfBody renderOfBody; if (!mToBeRenderred.containsKey(body)) { renderOfBody = new RenderOfBody(body, mVBO); mToBeRenderred.put(body, renderOfBody); this.attachChild(renderOfBody); } else { renderOfBody = mToBeRenderred.get(body); } mActiveSet.add(renderOfBody); /** * This is where debug renders are moved to match body position. * These 4 lines probably have to be modified if you are not using new * GLES2-AnchorCenter branch of AE (ie. you are using old GLES2 branch) */ renderOfBody.updateColor(); // XXX for some reason, setRotationCenter() is not needed on GLES2 branch... why? //renderOfBody.setRotationCenter(body.getMassData().center.x * PhysicsConnector.PIXEL_TO_METER_RATIO_DEFAULT, body.getMassData().center.y * PhysicsConnector.PIXEL_TO_METER_RATIO_DEFAULT); renderOfBody.setRotation((float) (body.getAngle() * (180 / Math.PI))); renderOfBody.setPosition(body.getPosition().x * PhysicsConnector.PIXEL_TO_METER_RATIO_DEFAULT, body.getPosition().y * PhysicsConnector.PIXEL_TO_METER_RATIO_DEFAULT); } /** * Get rid of all bodies that where not rendered in this iteration */ // inactive = renderred - active mInactiveSet.addAll(mToBeRenderred.values()); mInactiveSet.removeAll(mActiveSet); for (RenderOfBody killme : mInactiveSet) { this.detachChild(killme); } mToBeRenderred.values().removeAll(mInactiveSet); } /** * Translates b2d Fixture to appropriate color, depending on body state/type * Modify to suit your needs * @param fixture * @return */ private static Color fixtureToColor(Fixture fixture) { if (fixture.isSensor()) { return Color.PINK; } else { Body body = fixture.getBody(); if (!body.isActive()) { return Color.BLACK; } else { if (!body.isAwake()) { return Color.RED; } else { switch (body.getType()) { case StaticBody: return Color.CYAN; case KinematicBody: return Color.WHITE; case DynamicBody: default: return Color.GREEN; } } } } } /** * Physical body representation- it contains of multiple RenderFixture * @author nazgee * */ private class RenderOfBody extends Entity { public LinkedList<IRenderOfFixture> mRenderFixtures = new LinkedList<IRenderOfFixture>(); public RenderOfBody(Body pBody, VertexBufferObjectManager pVBO) { ArrayList<Fixture> fixtures = pBody.getFixtureList(); /** * Spawn all IRenderOfFixture for this body that are out there, * and bind them to this RenderOfBody */ for (Fixture fixture : fixtures) { IRenderOfFixture renderOfFixture; if (fixture.getShape().getType() == Type.Circle) { renderOfFixture = new RenderOfCircleFixture(fixture, pVBO); } else if (fixture.getShape().getType() == Type.Edge) { renderOfFixture = new RenderOfEdgeFixture(fixture, pVBO); } else if (fixture.getShape().getType() == Type.Chain) { renderOfFixture = new RenderOfChainFixture(fixture, pVBO); } else { renderOfFixture = new RenderOfPolyFixture(fixture, pVBO); } updateColor(); mRenderFixtures.add(renderOfFixture); this.attachChild(renderOfFixture.getEntity()); } } public void updateColor() { for (IRenderOfFixture renderOfFix : mRenderFixtures) { renderOfFix.getEntity().setColor(fixtureToColor(renderOfFix.getFixture())); } } } }