移动物体上的旋转球

问题描述 投票:0回答:1

我正在使用带有 Java 和 LibGDX 的 Android Studio。

我需要让一些球在另一个移动的物体上旋转。

身体不动就起作用:

enter image description here

否则,球会被移动体“拉动”,而不是在其上公转。

以下是身体移动到底部时的一些截图:

enter image description here

我注意到,如果我大幅增加旋转速度,球几乎会正确旋转,但我需要让它以许多不同的速度工作。

无论我使用 setTransform 还是使用 LinearVelocity 移动主球,结果都是相同的。

如何在主球运动的同时保持平稳的公转运动?

谢谢


public Ball(World world, float x, float y, float sizeInWorld) {
    this.sizeInWorld = sizeInWorld;
    this.ballInitialSize = sizeInWorld;
    
    BodyDef bodyDef = new BodyDef();
    bodyDef.type = BodyDef.BodyType.KinematicBody;
    bodyDef.position.set(x, y);
    bodyDef.fixedRotation = false;
    bodyDef.bullet = true;
    body = world.createBody(bodyDef);
    body.setLinearDamping(0);

    CircleShape circle = new CircleShape();
    circle.setRadius(sizeInWorld / 2);
    FixtureDef fixtureDef = new FixtureDef();
    fixtureDef.shape = circle;
    fixtureDef.friction = 0f;
    fixtureDef.restitution = 1f;
    fixtureDef.density = 1f;
    circle.dispose();
    
    body.setLinearVelocity(0, -10);
}

public BallRevoluting(World world, float x, float y, float sizeInWorld) {
    this.sizeInWorld = sizeInWorld;
    this.ballInitialSize = sizeInWorld;
    
    BodyDef bodyDef = new BodyDef();
    bodyDef.type = BodyDef.BodyType.DynamicBody;
    bodyDef.position.set(x, y);
    bodyDef.fixedRotation = false;
    bodyDef.awake = true;
    bodyDef.bullet = true;
    body = world.createBody(bodyDef);
    body.setLinearDamping(0);

    CircleShape circle = new CircleShape();
    circle.setRadius(sizeInWorld / 2);
    FixtureDef fixtureDef = new FixtureDef();
    fixtureDef.shape = circle;
    fixtureDef.friction = 0.1f;
    fixtureDef.isSensor = true;
    fixtureDef.restitution = 0;
    fixtureDef.density = 1f;
    circle.dispose();
}

public static void createRevoluteJoint(World world, Body body, Body revolutingBody, float speed, boolean clockWise) {
    RevoluteJointDef revoluteJointDef = new RevoluteJointDef();
    revoluteJointDef.initialize(body, revolutingBody, body.getPosition());
    revoluteJointDef.enableMotor = true;
    float targetVelocity = speed * 5;
    float radius = revolutingBody.getPosition().dst(body.getPosition());
    revoluteJointDef.maxMotorTorque = calculateMotorTorque(revolutingBody, targetVelocity, radius);
    revoluteJointDef.motorSpeed = targetVelocity / radius;
    if(clockWise) {
        Gdx.app.log(TAG, "using revoluteToClockwise direction");
        revoluteJointDef.motorSpeed = -revoluteJointDef.motorSpeed;
    }
    world.createJoint(revoluteJointDef);
}

public calculateMotorTorque(Body body, float targetVelocity, float radius) {
    float mass = body.getMass();
    float angularVelocity = targetVelocity / radius;
    float inertia = mass * radius * radius;
    return inertia * angularVelocity;
}


public Ball mainBall = new Ball(world, 0, 0, 1);

int numOrbitingBalls = 4;
float orbitRadius = 2.0f;
for (int i = 0; i < numOrbitingBalls; i++) {
    float angle = (float) (i * 2 * Math.PI / numOrbitingBalls);
    float x = mainBall.getPosition().x + orbitRadius * (float)Math.cos(angle);
    float y = mainBall.getPosition().y + orbitRadius * (float)Math.sin(angle);

    BallRevoluting newBall = new BallRevoluting(world, x, y, mainBall.sizeInWorld/2);

    createRevoluteJoint(world, mainBall.body, newBall.body, 1, true);
}
libgdx box2d
1个回答
0
投票

考虑使用单个

Body
和卫星球作为
Fixture
上的
Body

如果这不适用于您的用例,一种方法是使用

WeldJoint
代替:enter image description here

在上面的示例中,我首先启用移动,然后旋转

mainBall
,但这本来可以一步完成。

如果这种方法也不起作用(假设因为你的“mainBall”不允许旋转),那么我会为卫星创建一个带有 4 个固定装置的主体,然后将该主体附加到

mainBall
偏移量为零的
MotorJoint

gif 的完整来源:

import com.badlogic.gdx.ApplicationAdapter;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Input;
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.*;
import com.badlogic.gdx.physics.box2d.joints.DistanceJointDef;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJointDef;
import com.badlogic.gdx.physics.box2d.joints.WeldJointDef;
import com.badlogic.gdx.utils.ScreenUtils;

 
public class SandboxGame extends ApplicationAdapter {

    public OrthographicCamera camera;
    public World world;
    public Box2DDebugRenderer box2DDebugRenderer;
    public Ball mainBall;

    @Override
    public void create() {
        float w = 32.0f;
        float h = w * Gdx.graphics.getHeight() / (float)Gdx.graphics.getWidth();
        camera = new OrthographicCamera(w, h);
        camera.position.set(0, 0, 1);
        camera.update();
        world = new World(Vector2.Zero, false);
        box2DDebugRenderer =new Box2DDebugRenderer();
        mainBall = new Ball(world, -10, 0, 1);

        int numOrbitingBalls = 4;
        float orbitRadius = 2.0f;
        for (int i = 0; i < numOrbitingBalls; i++) {
            float angle = (float) (i * 2 * Math.PI / numOrbitingBalls);
            float x = mainBall.body.getWorldCenter().x + orbitRadius * (float)Math.cos(angle);
            float y = mainBall.body.getWorldCenter().y + orbitRadius * (float)Math.sin(angle);

            BallRevoluting newBall = new BallRevoluting(world, x, y, mainBall.sizeInWorld/2);
            createWeldJoint(world, mainBall.body, newBall.body);
        }
    }

    @Override
    public void render() {
        if (Gdx.input.isKeyJustPressed(Input.Keys.ENTER))
            mainBall.body.setAngularVelocity(8);

        if (Gdx.input.isKeyJustPressed(Input.Keys.SPACE))
            mainBall.body.setLinearVelocity(4, 0);
        camera.update();
        world.step(Gdx.graphics.getDeltaTime(), 8, 8);
        ScreenUtils.clear(0.15f, 0.15f, 0.2f, 1f);
        box2DDebugRenderer.render(world, camera.combined);
    }

    public static void createWeldJoint(World world, Body body, Body revolutingBody) {
        WeldJointDef weldJointDef = new WeldJointDef();
        weldJointDef.initialize(body, revolutingBody, body.getWorldCenter());
        world.createJoint(weldJointDef);
    }

    public static class Ball
    {
        private final float sizeInWorld;
        private final Body body;

        public Ball(World world, float x, float y, float sizeInWorld) {
            this.sizeInWorld = sizeInWorld;
            BodyDef bodyDef = new BodyDef();
            bodyDef.type = BodyDef.BodyType.KinematicBody;
            bodyDef.position.set(x, y);
            bodyDef.fixedRotation = false;
            bodyDef.bullet = true;
            body = world.createBody(bodyDef);
            body.setLinearDamping(0);

            CircleShape circle = new CircleShape();
            circle.setRadius(sizeInWorld / 2.0f);
            FixtureDef fixtureDef = new FixtureDef();
            fixtureDef.shape = circle;
            fixtureDef.friction = 0f;
            fixtureDef.restitution = 1f;
            fixtureDef.density = 1f;
            circle.dispose();

            body.createFixture(fixtureDef);

            //body.setLinearVelocity(0, -10);
        }
    }


    public static class BallRevoluting
    {
        private final Body body;

        public BallRevoluting(World world, float x, float y, float sizeInWorld) {
            BodyDef bodyDef = new BodyDef();
            bodyDef.type = BodyDef.BodyType.DynamicBody;
            bodyDef.position.set(x, y);
            bodyDef.fixedRotation = false;
            bodyDef.awake = true;
            bodyDef.bullet = true;
            body = world.createBody(bodyDef);
            body.setLinearDamping(0);

            CircleShape circle = new CircleShape();
            circle.setRadius(sizeInWorld / 2);
            FixtureDef fixtureDef = new FixtureDef();
            fixtureDef.shape = circle;
            fixtureDef.friction = 0.1f;
            fixtureDef.isSensor = true;
            fixtureDef.restitution = 0;
            fixtureDef.density = 1f;
            body.createFixture(fixtureDef);
            circle.dispose();
        }
    }
}
最新问题
© www.soinside.com 2019 - 2025. All rights reserved.