@Override
  public void initialize() {
    super.initialize();

    // doStep true = not simulate inactive bodies
    world = new World(new Vector2(0.0f, 10.0f), true);
    world.setContinuousPhysics(true);
    world.setWarmStarting(true);
    world.setAutoClearForces(true);
    ValueMap valueMap = game.getGameState();
    valueMap.setValue((String) null, VAR_PH_WORLD, world);

    velocityIterations = 24;
    positionIterations = 8;

    for (SceneElement e : effect.getElements()) {
      createBody(world, e, valueMap);
    }

    for (SceneElement e : effect.getJoints()) {
      createBody(world, e, valueMap);
    }

    RevoluteJointDef jd = new RevoluteJointDef();
    jd.collideConnected = false;

    for (int i = 0; i < effect.getJoints().size() - 1; i += 2) {
      SceneElement e1 = effect.getJoints().get(i);
      SceneElement e2 = effect.getJoints().get(i + 1);
      Body b1 = (Body) valueMap.getValue(e1.getId(), VAR_PH_BODY, null);
      Body b2 = (Body) valueMap.getValue(e2.getId(), VAR_PH_BODY, null);
      jd.initialize(b2, b1, new Vector2(b1.getPosition().x, b1.getPosition().y));
      world.createJoint(jd);
    }
  }
  @Override
  public void act(float delta) {
    super.act(delta);
    timeStep = delta / 1000.0f;
    world.step(timeStep, velocityIterations, positionIterations);

    Scene scene = (Scene) gui.getScene().getElement();

    if (scene != null) {
      for (SceneElement e : scene.getSceneElements()) {
        ValueMap valueMap = game.getGameState();
        Body b = (Body) valueMap.getValue(e.getId(), VAR_PH_BODY, null);
        if (b != null) {

          valueMap.setValue(e, SceneElement.VAR_X, (float) (b.getWorldCenter().x * WORLD_SCALE));
          valueMap.setValue(e, SceneElement.VAR_Y, (float) (b.getWorldCenter().y * WORLD_SCALE));
          valueMap.setValue(e, SceneElement.VAR_ROTATION, (float) Math.toDegrees(b.getAngle()));
        }
      }
    } else {
      stop();
    }
  }
  public static void createBody(World world, SceneElement e, ValueMap valueMap) {
    float x = valueMap.getValue(e, SceneElement.VAR_X, 0f) / WORLD_SCALE;
    float y = valueMap.getValue(e, SceneElement.VAR_Y, 0f) / WORLD_SCALE;
    float width = valueMap.getValue(e, SceneElement.VAR_WIDTH, 1) / WORLD_SCALE;
    float height = valueMap.getValue(e, SceneElement.VAR_HEIGHT, 1) / WORLD_SCALE;

    // TODO what if corner is not center?
    PhType phType = valueMap.getValue(e, PhysicsEf.VAR_PH_TYPE, PhType.DYNAMIC);
    PhShape phShape = valueMap.getValue(e, PhysicsEf.VAR_PH_SHAPE, PhShape.RECTANGULAR);

    Shape s = null;
    switch (phShape) {
      case CIRCULAR:
        s = new CircleShape();
        s.setRadius(width / 2);
        break;
      default:
        s = new PolygonShape();
        ((PolygonShape) s).setAsBox(width / 2, height / 2);
    }

    BodyDef bd = new BodyDef();

    switch (phType) {
      case STATIC:
        bd.type = BodyType.StaticBody;
        break;
      case DYNAMIC:
        bd.type = BodyType.DynamicBody;
        break;
    }

    bd.position.set(x, y);
    bd.angle = valueMap.getValue(e, SceneElement.VAR_ROTATION, 0);

    FixtureDef fixture = new FixtureDef();
    fixture.shape = s;
    fixture.density = valueMap.getValue(e, PhysicsEf.VAR_PH_DENSITY, 1f);
    fixture.friction = valueMap.getValue(e, PhysicsEf.VAR_PH_FRICTION, 1f);
    fixture.restitution = valueMap.getValue(e, PhysicsEf.VAR_PH_RESTITUTION, 1f);

    Body body = world.createBody(bd);
    body.createFixture(fixture);

    body.resetMassData();

    valueMap.setValue(e.getId(), VAR_PH_BODY, body);
  }