Example #1
0
    public FixtureData(Fixture fixture) {
      PolygonShape poly = (PolygonShape) fixture.getShape();

      // get vertices
      vertices = new Vector2[poly.getVertexCount()];
      for (int i = 0; i < vertices.length; i++) {
        vertices[i] = new Vector2();
        poly.getVertex(i, vertices[i]);
      }

      mesh =
          new Mesh(
              true,
              poly.getVertexCount(),
              0,
              new VertexAttribute(Usage.Position, 3, ShaderProgram.POSITION_ATTRIBUTE),
              new VertexAttribute(Usage.ColorPacked, 4, ShaderProgram.COLOR_ATTRIBUTE),
              new VertexAttribute(Usage.TextureCoordinates, 2, ShaderProgram.TEXCOORD_ATTRIBUTE));

      meshesData = new float[vertices.length * 6];
    }
  /**
   * Creates an array of PolySpatials based on fixture information from the scene. Note that
   * fixtures create aligned textures.
   *
   * @param scene
   */
  private void createPolySpatialsFromRubeFixtures(RubeScene scene) {
    Array<Body> bodies = scene.getBodies();

    EarClippingTriangulator ect = new EarClippingTriangulator();

    if ((bodies != null) && (bodies.size > 0)) {
      polySpatials = new Array<PolySpatial>();
      Vector2 bodyPos = new Vector2();
      // for each body in the scene...
      for (int i = 0; i < bodies.size; i++) {
        Body body = bodies.get(i);
        bodyPos.set(body.getPosition());

        Array<Fixture> fixtures = body.getFixtureList();

        if ((fixtures != null) && (fixtures.size > 0)) {
          // for each fixture on the body...
          for (int j = 0; j < fixtures.size; j++) {
            Fixture fixture = fixtures.get(j);

            String textureName = (String) scene.getCustom(fixture, "TextureMask", null);
            if (textureName != null) {
              String textureFileName = "data/" + textureName;
              Texture texture = textureMap.get(textureFileName);
              TextureRegion textureRegion = null;
              if (texture == null) {
                texture = new Texture(textureFileName);
                texture.setWrap(TextureWrap.Repeat, TextureWrap.Repeat);
                textureMap.put(textureFileName, texture);
                textureRegion = new TextureRegion(texture);
                textureRegionMap.put(texture, textureRegion);
              } else {
                textureRegion = textureRegionMap.get(texture);
              }

              // only handle polygons at this point -- no chain, edge, or circle fixtures.
              if (fixture.getType() == Shape.Type.Polygon) {
                PolygonShape shape = (PolygonShape) fixture.getShape();
                int vertexCount = shape.getVertexCount();
                float[] vertices = new float[vertexCount * 2];

                // static bodies are texture aligned and do not get drawn based off of the related
                // body.
                if (body.getType() == BodyType.StaticBody) {
                  for (int k = 0; k < vertexCount; k++) {

                    shape.getVertex(k, mTmp);
                    mTmp.rotate(body.getAngle() * MathUtils.radiansToDegrees);
                    mTmp.add(
                        bodyPos); // convert local coordinates to world coordinates to that textures
                                  // are
                    // aligned
                    vertices[k * 2] = mTmp.x * PolySpatial.PIXELS_PER_METER;
                    vertices[k * 2 + 1] = mTmp.y * PolySpatial.PIXELS_PER_METER;
                  }

                  short[] triangleIndices = ect.computeTriangles(vertices).toArray();
                  PolygonRegion region =
                      new PolygonRegion(textureRegion, vertices, triangleIndices);
                  PolySpatial spatial = new PolySpatial(region, Color.WHITE);
                  polySpatials.add(spatial);
                } else {
                  // all other fixtures are aligned based on their associated body.
                  for (int k = 0; k < vertexCount; k++) {
                    shape.getVertex(k, mTmp);
                    vertices[k * 2] = mTmp.x * PolySpatial.PIXELS_PER_METER;
                    vertices[k * 2 + 1] = mTmp.y * PolySpatial.PIXELS_PER_METER;
                  }
                  short[] triangleIndices = ect.computeTriangles(vertices).toArray();
                  PolygonRegion region =
                      new PolygonRegion(textureRegion, vertices, triangleIndices);
                  PolySpatial spatial = new PolySpatial(region, body, Color.WHITE);
                  polySpatials.add(spatial);
                }
              } else if (fixture.getType() == Shape.Type.Circle) {
                CircleShape shape = (CircleShape) fixture.getShape();
                float radius = shape.getRadius();
                int vertexCount = (int) (12f * radius);
                float[] vertices = new float[vertexCount * 2];
                System.out.println("SpatialFactory: radius: " + radius);
                if (body.getType() == BodyType.StaticBody) {
                  mTmp3.set(shape.getPosition());
                  for (int k = 0; k < vertexCount; k++) {
                    // set the initial position
                    mTmp.set(radius, 0);
                    // rotate it by 1/vertexCount * k
                    mTmp.rotate(360f * k / vertexCount);
                    // add it to the position.
                    mTmp.rotate(body.getAngle() * MathUtils.radiansToDegrees);
                    mTmp.add(mTmp3);
                    mTmp.add(
                        bodyPos); // convert local coordinates to world coordinates to that textures
                                  // are aligned
                    vertices[k * 2] = mTmp.x * PolySpatial.PIXELS_PER_METER;
                    vertices[k * 2 + 1] = mTmp.y * PolySpatial.PIXELS_PER_METER;
                  }
                  short[] triangleIndices = ect.computeTriangles(vertices).toArray();
                  PolygonRegion region =
                      new PolygonRegion(textureRegion, vertices, triangleIndices);
                  PolySpatial spatial = new PolySpatial(region, Color.WHITE);
                  polySpatials.add(spatial);
                } else {
                  mTmp3.set(shape.getPosition());
                  for (int k = 0; k < vertexCount; k++) {
                    // set the initial position
                    mTmp.set(radius, 0);
                    // rotate it by 1/vertexCount * k
                    mTmp.rotate(360f * k / vertexCount);
                    // add it to the position.
                    mTmp.add(mTmp3);
                    vertices[k * 2] = mTmp.x * PolySpatial.PIXELS_PER_METER;
                    vertices[k * 2 + 1] = mTmp.y * PolySpatial.PIXELS_PER_METER;
                  }
                  short[] triangleIndices = ect.computeTriangles(vertices).toArray();
                  PolygonRegion region =
                      new PolygonRegion(textureRegion, vertices, triangleIndices);
                  PolySpatial spatial = new PolySpatial(region, body, Color.WHITE);
                  polySpatials.add(spatial);
                }
              }
            }
          }
        }
      }
    }
  }
  @Override
  public void create() {
    float w = Gdx.graphics.getWidth();
    float h = Gdx.graphics.getHeight();

    Gdx.input.setInputProcessor(this);

    mB2Controllers = new Array<B2Controller>();

    mCamPos = new Vector3();
    mCurrentPos = new Vector3();

    camera = new OrthographicCamera(100, 100 * h / w);
    camera.position.set(50, 50, 0);
    camera.zoom = 1.8f;
    camera.update();

    loader = new RubeSceneLoader();

    scene = loader.loadScene(Gdx.files.internal("data/palmcontrollers.json"));

    debugRender = new Box2DDebugRenderer();

    batch = new SpriteBatch();
    polygonBatch = new PolygonSpriteBatch();

    textureMap = new HashMap<String, Texture>();
    textureRegionMap = new HashMap<Texture, TextureRegion>();

    createSpatialsFromRubeImages(scene);
    createPolySpatialsFromRubeFixtures(scene);

    mWorld = scene.getWorld();
    // configure simulation settings
    mVelocityIter = scene.velocityIterations;
    mPositionIter = scene.positionIterations;
    if (scene.stepsPerSecond != 0) {
      mSecondsPerStep = 1f / scene.stepsPerSecond;
    }
    mWorld.setContactListener(this);

    //
    // example of custom property handling
    //
    Array<Body> bodies = scene.getBodies();
    if ((bodies != null) && (bodies.size > 0)) {
      for (int i = 0; i < bodies.size; i++) {
        Body body = bodies.get(i);
        String gameInfo = (String) scene.getCustom(body, "GameInfo", null);
        if (gameInfo != null) {
          System.out.println("GameInfo custom property: " + gameInfo);
        }
      }
    }

    // Instantiate any controllers that are in the scene
    Array<Fixture> fixtures = scene.getFixtures();
    if ((fixtures != null) && (fixtures.size > 0)) {
      for (int i = 0; i < fixtures.size; i++) {
        Fixture fixture = fixtures.get(i);
        int controllerType = (Integer) scene.getCustom(fixture, "ControllerType", 0);
        switch (controllerType) {
          case B2Controller.BUOYANCY_CONTROLLER:
            // only allow polygon buoyancy controllers for now..
            if (fixture.getShape().getType() == Shape.Type.Polygon) {
              float bodyHeight = fixture.getBody().getPosition().y;
              // B2BuoyancyController b2c = new B2BuoyancyController();

              // need to calculate the fluid surface height for the buoyancy controller
              PolygonShape shape = (PolygonShape) fixture.getShape();
              shape.getVertex(0, mTmp);
              float maxHeight =
                  mTmp.y + bodyHeight; // initialize the height, transforming to 'world'
              // coordinates

              // find the maxHeight
              for (int j = 1; j < shape.getVertexCount(); j++) {
                shape.getVertex(j, mTmp);
                maxHeight =
                    Math.max(maxHeight, mTmp.y + bodyHeight); // transform to world coordinates
              }
              B2BuoyancyController b2c =
                  new B2BuoyancyController(
                      B2BuoyancyController.DEFAULT_SURFACE_NORMAL, // assume up
                      (Vector2)
                          scene.getCustom(
                              fixture,
                              "ControllerVelocity",
                              B2BuoyancyController.DEFAULT_FLUID_VELOCITY),
                      mWorld.getGravity(),
                      maxHeight,
                      fixture.getDensity(),
                      (Float)
                          scene.getCustom(
                              fixture, "LinearDrag", B2BuoyancyController.DEFAULT_LINEAR_DRAG),
                      (Float)
                          scene.getCustom(
                              fixture, "AngularDrag", B2BuoyancyController.DEFAULT_ANGULAR_DRAG));
              fixture.setUserData(b2c); // reference back to the controller from the fixture (see
              // beginContact/endContact)
              mB2Controllers.add(b2c); // add it to the list so it can be stepped later
            }
            break;

          case B2Controller.GRAVITY_CONTROLLER:
            {
              B2GravityController b2c = new B2GravityController();
              b2c =
                  new B2GravityController(
                      (Vector2)
                          scene.getCustom(
                              fixture, "ControllerVelocity", B2GravityController.DEFAULT_GRAVITY));
              fixture.setUserData(b2c);
              mB2Controllers.add(b2c);
            }
            break;
        }
      }
    }
    scene.printStats();
    scene.clear(); // no longer need any scene references
  }
  /**
   * @param f - fixture that is affected
   * @return true if force was applied, false otherwise.
   */
  private boolean ApplyToFixture(Fixture f) {
    float shapeDensity = mUseDensity ? f.getDensity() : mFluidDensity;

    // don't bother with buoyancy on sensors or fixtures with no density
    if (f.isSensor() || (shapeDensity == 0)) {
      return false;
    }
    Body body = f.getBody();
    mAreac.set(Vector2.Zero);
    mMassc.set(Vector2.Zero);
    float area = 0;

    // Get shape for displacement area calculations
    Shape shape = f.getShape();

    mSC.set(Vector2.Zero);
    float sarea;
    switch (shape.getType()) {
      case Circle:
        sarea =
            B2ShapeExtensions.ComputeSubmergedArea(
                (CircleShape) shape, mSurfaceNormal, mSurfaceHeight, body.getTransform(), mSC);
        break;

      case Chain:
        sarea =
            B2ShapeExtensions.ComputeSubmergedArea(
                (ChainShape) shape, mSurfaceNormal, mSurfaceHeight, body.getTransform(), mSC);
        break;

      case Edge:
        sarea =
            B2ShapeExtensions.ComputeSubmergedArea(
                (EdgeShape) shape, mSurfaceNormal, mSurfaceHeight, body.getTransform(), mSC);
        break;

      case Polygon:
        sarea =
            B2ShapeExtensions.ComputeSubmergedArea(
                (PolygonShape) shape, mSurfaceNormal, mSurfaceHeight, body.getTransform(), mSC);
        break;

      default:
        sarea = 0;
        break;
    }

    area += sarea;
    mAreac.x += sarea * mSC.x;
    mAreac.y += sarea * mSC.y;
    float mass = sarea * shapeDensity;
    mMassc.x += sarea * mSC.x * shapeDensity;
    mMassc.y += sarea * mSC.y * shapeDensity;

    mAreac.x /= area;
    mAreac.y /= area;
    mMassc.x /= mass;
    mMassc.y /= mass;
    if (area < Float.MIN_VALUE) {
      return false;
    }

    if (DEBUG_BUOYANCY) {
      // Run debug w/HCR to see the effects of different fluid densities / linear drag
      mFluidDensity = 2f;
      mLinearDrag = 5;
      mAngularDrag = 2;
    }

    // buoyancy force.
    mTmp.set(mGravity).scl(-mFluidDensity * area);
    body.applyForce(mTmp, mMassc, true); // multiply by -density to invert gravity

    // linear drag.
    mTmp.set(
        body.getLinearVelocityFromWorldPoint(mAreac).sub(mFluidVelocity).mul(-mLinearDrag * area));
    body.applyForce(mTmp, mAreac, true);

    // angular drag.
    float bodyMass = body.getMass();
    if (bodyMass < 1) // prevent a huge torque from being generated...
    {
      bodyMass = 1;
    }
    float torque = -body.getInertia() / bodyMass * area * body.getAngularVelocity() * mAngularDrag;
    body.applyTorque(torque, true);
    return true;
  }