我正在使用带有 Java 和 LibGDX 的 Android Studio。
我需要让一些球在另一个移动的物体上旋转。
身体不动就起作用:
否则,球会被移动体“拉动”,而不是在其上公转。
以下是身体移动到底部时的一些截图:
我注意到,如果我大幅增加旋转速度,球几乎会正确旋转,但我需要让它以许多不同的速度工作。
无论我使用 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);
}
考虑使用单个
Body
和卫星球作为 Fixture
上的 Body
。
如果这不适用于您的用例,一种方法是使用
WeldJoint
代替:在上面的示例中,我首先启用移动,然后旋转
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();
}
}
}