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; }