3
\$\begingroup\$

I want to implement rotating rectangle around cicrle in such way, that circle has no rotation, and rectangle has, and I could myself control rotation of this rectangle (I mean set its angular velocity). All object's are Box2D Body objects. Here is picture, what I want to have:

enter image description here

In my case rectangle touches circle, but I think it doesn't matter.

At first I tried to do it with two Fictures for same Body, but there was a problem with rotation: I couldn't have one ficture with rotation and another without.

I think, it should be somehow connected, but I don't know what exactly Joint I should use.

I tried to use DistanceJoint, but there was a problem, that I couldn't control Rectangle: when I even linear velocity of rectangle to 0 in render() method it continued to rotate.

Maybe are there another solutions?

P.S. It's important, that Cicrle should be DynamicBody, not StaticBody.

\$\endgroup\$
2
\$\begingroup\$

You can achieve this using a RevoluteJoint to anchor the "motor" to a point in the world, and a WeldJoint to anchor the rotating box to the "motor".

In my example I've used two static bodies, one for the circle that shouldn't move, and one for a small box inside the circle that will serve as the anchor point in the world.

The dynamic rotator Body is attached to the anchorBody using the RevoluteJoint and then the box (which is also dynamic) is welded to the rotator (which serves as the engine) using a `WeldJoint'.

The result looks like this; Rotating boxes! Sorry about the artifacts, the gif capture seems to be broken.

Full source for the above looks like this;

package com.bornander.androidstudiosandbox;

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.BodyDef;
import com.badlogic.gdx.physics.box2d.Box2DDebugRenderer;
import com.badlogic.gdx.physics.box2d.CircleShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.Shape;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJointDef;
import com.badlogic.gdx.physics.box2d.joints.WeldJointDef;

public class MyAndroidStudioSandboxGame extends ApplicationAdapter {
    World world;
    OrthographicCamera camera;
    Box2DDebugRenderer renderer;

    @Override
    public void create () {
        camera = new OrthographicCamera(100, 100);
        camera.position.set(0,0,0);

        world = new World(Vector2.Zero, true);

        renderer = new Box2DDebugRenderer();

        Body visibleCircle = createCircle(5, 0, 0);
        visibleCircle.setType(BodyDef.BodyType.StaticBody);

        Body anchorPoint = createBox(2, 2, 0, 0);
        anchorPoint.setType(BodyDef.BodyType.StaticBody);

        Body rotator = createBox(4,4,0,0);
        rotator.setType(BodyDef.BodyType.DynamicBody);

        Body box = createBox(4,4,8,0);
        box.setType(BodyDef.BodyType.DynamicBody);


        RevoluteJointDef revoluteJointDef = new RevoluteJointDef();
        revoluteJointDef.initialize(anchorPoint, rotator, anchorPoint.getWorldCenter());
        revoluteJointDef.enableMotor = true;
        revoluteJointDef.motorSpeed = 20;
        revoluteJointDef.maxMotorTorque = 50;

        WeldJointDef weldJointDef = new WeldJointDef();
        weldJointDef.initialize(rotator, box, rotator.getWorldCenter());

        world.createJoint(revoluteJointDef);
        world.createJoint(weldJointDef);

    }

    private Body createBox(float w, float h, float x, float y) {
        BodyDef nodeBodyDefinition = new BodyDef();
        nodeBodyDefinition.type = BodyDef.BodyType.DynamicBody;
        nodeBodyDefinition.position.set(10, 10);

        PolygonShape shape = new PolygonShape();
        float density = 1.0f;
        shape.setAsBox(w / 2.0f, h / 2.0f);

        Body body = world.createBody(nodeBodyDefinition);
        body.setUserData(this);
        body.setTransform(x, y, 0);
        final FixtureDef nodeFixtureDefinition = createFixtureDefinition(shape, density);

        body.createFixture(nodeFixtureDefinition);
        shape.dispose();

        return body;
    }

    private Body createCircle(float r, float x, float y) {
        BodyDef nodeBodyDefinition = new BodyDef();
        nodeBodyDefinition.type = BodyDef.BodyType.DynamicBody;
        nodeBodyDefinition.position.set(10, 10);

        CircleShape shape = new CircleShape();
        float density = 1.0f;
        shape.setRadius(r);

        Body body = world.createBody(nodeBodyDefinition);
        body.setUserData(this);
        body.setTransform(x, y, 0);
        final FixtureDef nodeFixtureDefinition = createFixtureDefinition(shape, density);

        body.createFixture(nodeFixtureDefinition);
        shape.dispose();

        return body;
    }

    private static FixtureDef createFixtureDefinition(final Shape shape, final float density) {
        final FixtureDef nodeFixtureDefinition = new FixtureDef();
        nodeFixtureDefinition.shape = shape;
        nodeFixtureDefinition.friction = 1;
        nodeFixtureDefinition.density = density;
        nodeFixtureDefinition.restitution = 0.1f;
        return nodeFixtureDefinition;
    }



    @Override
    public void render () {
        Gdx.gl.glClearColor(0, 0, 0, 1);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);

        world.step(Gdx.graphics.getDeltaTime(), 4, 4);
        camera.update();

        renderer.render(world, camera.combined);
    }
}
\$\endgroup\$
  • \$\begingroup\$ In my case I need Circle to be DynamicBody. When I copied your code and changed Static to Dynamic, everything has broken. How can I fix it? Anyway thanks for your help! \$\endgroup\$ – OneOne Dec 16 '15 at 21:41
  • \$\begingroup\$ In that case you need to set the collision filters and masks so that the circle does not collide with the anchor or the rotor. Or you could try setting the anchor and rotor to be sensors using setSensor (true). \$\endgroup\$ – bornander Dec 16 '15 at 22:32
  • \$\begingroup\$ Ok, as I understand, RevoluteJoint is only for such joints where one of bodies doesn't change his place (we even set anchorPoint.getWorldCenter() as anchor point). So could you please explain your solution a little bit more in details? \$\endgroup\$ – OneOne Dec 16 '15 at 22:43
  • \$\begingroup\$ @OneOne RevoluteJoint works on all bodies, not just when one is static but if you make the thing that the box rotate around being dynamic then the centripetal force of the orbiting box will make the center Body wobble unless you have a very large difference in density. If you elaborate a bit more on how all the bodies in you example should behave I am certain a solution can be found that works well for you. \$\endgroup\$ – bornander Dec 18 '15 at 8:07

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.