Libgdx box2d body 移动缓慢
Libgdx box2d body moves slow
这是一个非常简单的box2d场景。我尝试了不同的视口和不同的屏幕尺寸。我不明白为什么 body 下降很慢。实际上,我不太确定它是否慢,原因可能是视口设置等。
这是主要的 class:
public class Main extends Game {
LevelScreen levelScreen;
@Override
public void create () {
levelScreen = new LevelScreen();
setScreen(levelScreen);
}
@Override
public void render () {
super.render();
}
}
和关卡画面:
public class LevelScreen extends Stage implements Screen {
private Batch batch;
private Camera camera;
private Texture ballTexture;
private Sprite ball;
private Viewport viewport;
//com
private Vector3 point = new Vector3();
private World world;
private Box2DDebugRenderer box2DDebugRenderer;
private CircleShape circleShape;
private FixtureDef fixtureDef;
private BodyDef bodyDef;
private Body circleBody;
private static final float SCENE_WIDTH = 1080;
private static final float SCENE_HEIGHT = 1920f;
public LevelScreen() {
super(new FitViewport(SCENE_WIDTH, SCENE_HEIGHT, new OrthographicCamera(SCENE_WIDTH, SCENE_HEIGHT)));
batch = getBatch();
camera = getCamera();
viewport = getViewport();
world = new World(new Vector2(0,-9.8f), true);
box2DDebugRenderer = new Box2DDebugRenderer();
bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(600, 1000);
ballTexture = new Texture("ball.png");
ball = new Sprite(ballTexture);
ball.setPosition(0,0);
circleShape = new CircleShape();
circleShape.setRadius(25f);
fixtureDef = new FixtureDef();
fixtureDef.shape = circleShape;
fixtureDef.density = 0.5f;
fixtureDef.friction = 0.4f;
fixtureDef.restitution = 0.6f;
circleBody = world.createBody(bodyDef);
circleBody.createFixture(fixtureDef);
box2DDebugRenderer = new Box2DDebugRenderer(
true, /* draw bodies */
false, /* don't draw joints */
true, /* draw aabbs */
true, /* draw inactive bodies */
false, /* don't draw velocities */
true /* draw contacts */);
Gdx.input.setInputProcessor(this);
}
@Override
public void show() {
System.out.println("show");
}
@Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
ball.draw(batch);
batch.end();
world.step(1 / 60f, 6, 2);
ball.setPosition(circleBody.getPosition().x - 25f, circleBody.getPosition().y - 25f);
box2DDebugRenderer.render(world, viewport.getCamera().combined);
}
@Override
public void resize(int width, int height) {
viewport.update(width, height);
System.out.println("resize");
}
@Override
public void pause() {
System.out.println("pause");
}
@Override
public void resume() {
System.out.println("resume");
}
@Override
public void hide() {
System.out.println("hide");
}
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
viewport.getCamera().unproject(point.set(screenX, screenY, 0));
return false;
}
}
您应该为 box2d 使用小型相机,因为 box2d 在 0-10 值下效果更好。
这是你的关卡画面class.Try吧。
public class LevelScreen extends Stage implements Screen {
private Batch batch;
private Camera camera;
private Texture ballTexture;
private Sprite ball;
private Viewport viewport;
private Vector3 point = new Vector3();
private World world;
private Box2DDebugRenderer box2DDebugRenderer;
private CircleShape circleShape;
private FixtureDef fixtureDef;
private BodyDef bodyDef;
private Body circleBody;
private static final float SCENE_WIDTH = 28;
private static final float SCENE_HEIGHT = 48f;
public LevelScreen() {
super(new FitViewport(SCENE_WIDTH, SCENE_HEIGHT, new OrthographicCamera(SCENE_WIDTH, SCENE_HEIGHT)));
batch = getBatch();
camera = getCamera();
viewport = getViewport();
world = new World(new Vector2(0,-9.8f), true);
box2DDebugRenderer = new Box2DDebugRenderer();
bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(10, 28);
ballTexture = new Texture("ball.png");
ball = new Sprite(ballTexture);
ball.setPosition(0,0);
circleShape = new CircleShape();
circleShape.setRadius(1f);
fixtureDef = new FixtureDef();
fixtureDef.shape = circleShape;
fixtureDef.density = 0.5f;
fixtureDef.friction = 0.4f;
fixtureDef.restitution = 0.6f;
circleBody = world.createBody(bodyDef);
circleBody.createFixture(fixtureDef);
box2DDebugRenderer = new Box2DDebugRenderer(
true, /* draw bodies */
false, /* don't draw joints */
true, /* draw aabbs */
true, /* draw inactive bodies */
false, /* don't draw velocities */
true /* draw contacts */);
Gdx.input.setInputProcessor(this);
}
@Override
public void show() {
System.out.println("show");
}
@Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
ball.draw(batch);
batch.end();
world.step(1 / 60f, 6, 2);
ball.setPosition(circleBody.getPosition().x - 25f, circleBody.getPosition().y - 25f);
box2DDebugRenderer.render(world, viewport.getCamera().combined);
}
@Override
public void resize(int width, int height) {
viewport.update(width, height);
System.out.println("resize");
}
@Override
public void pause() {
System.out.println("pause");
}
@Override
public void resume() {
System.out.println("resume");
}
@Override
public void hide() {
System.out.println("hide");
}
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
viewport.getCamera().unproject(point.set(screenX, screenY, 0));
return false;
}
}
好吧,我似乎无法通过简单的评论让您理解。让我们通过代码试试:
屏幕
public class TestScreen implements Screen {
SpriteBatch batch;
OrthographicCamera camera;
World world;
Box2DDebugRenderer dr;
Ball ball;
public TestScreen() {
batch = new SpriteBatch();
camera = new OrthographicCamera(1.6f, 1f); // <---- Very small camera so it passes by fast since less surface is being shown
world = new World(new Vector2(0, -9.8f), true);
ball = new Ball(.11f, world); // <---- Create ball and pass in the diameter
//Try playing with the value of camera let's say we have a ball the size of planet earth:
//ball = new Ball(6371, world);
//Now zoom out the screen so we can see our planet sized ball
//camera = new OrthographicCamera(16000, 10000);
//Believe me, our planet ball falls as fast as the little soccer ball. //But since you zoomed out each pixel represents so much more distance.
dr = new Box2DDebugRenderer(true, false, false, false, false, false);
}
@Override
public void show() {
}
@Override
public void render (float delta) {
Gdx.gl.glClearColor(.1f, .1f, .14f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
world.step(Gdx.graphics.getDeltaTime(), 6, 2);
batch.begin();
ball.draw(batch);
batch.end();
dr.render(world, camera.combined);
}
//... Other mandatory screen methods
}
Ball.java
public class Ball {
private float radius;
private CircleShape shape;
private FixtureDef fixtureDef;
private BodyDef bodyDef;
private Body circleBody;
private Texture ballTexture;
public Ball(float radius, World world) {
this.radius = radius;
ballTexture = new Texture("sprites/soccerball.png");
bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(0, 0);
shape = new CircleShape();
shape.setRadius(radius);
fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 0.5f;
fixtureDef.friction = 0.4f;
fixtureDef.restitution = 0.6f;
circleBody = world.createBody(bodyDef);
circleBody.createFixture(fixtureDef);
}
public void draw(SpriteBatch batch)
{
batch.draw(ballTexture, circleBody.getPosition().x - radius, circleBody.getPosition().y - radius,
radius * 2, radius * 2); // <---- draw the size you give it in the physics engine
}
}
让我们开始你做错了什么:
你给了世界 9.8 个单位的引力。这些不是像素,也不是距离,也不是任何东西。当你决定这些是米(代表地球上的重力)时,它们才会是米,你应该保持真实的比例。
接下来您制作一个半径为 25 米的球,并将相机拉远以显示 1920 米高的区域。在现实生活中,将一个物体从 2 公里高处掉落到地面需要一段时间。因此,由于您在现实世界中使用的是每秒 9.8 米的速度,因此在您的应用程序中落地也需要一些时间。
所以你要做的是缩小规模。足球的半径只有 11 厘米,所以我创建了一个半径为 0.11 米的球。但是你将无法看到它,因为到目前为止它只是一个像素的一小部分。所以放大你的相机(因为它是正交的,你只需设置它的视口尺寸)。
对于有关绘制正确大小的球的后续问题,您只需使用之前给出的半径即可。正如您所看到的球,相机 vp 非常小,球也非常小。对于行星大小的示例,相机被缩小得很远,行星的大小与我们自己的地球一样大。然而,我只是用它的半径画球,一切都会好起来的。
希望你明白,也许你不必想太多,因为这个概念很简单。
这是一个非常简单的box2d场景。我尝试了不同的视口和不同的屏幕尺寸。我不明白为什么 body 下降很慢。实际上,我不太确定它是否慢,原因可能是视口设置等。 这是主要的 class:
public class Main extends Game {
LevelScreen levelScreen;
@Override
public void create () {
levelScreen = new LevelScreen();
setScreen(levelScreen);
}
@Override
public void render () {
super.render();
}
}
和关卡画面:
public class LevelScreen extends Stage implements Screen {
private Batch batch;
private Camera camera;
private Texture ballTexture;
private Sprite ball;
private Viewport viewport;
//com
private Vector3 point = new Vector3();
private World world;
private Box2DDebugRenderer box2DDebugRenderer;
private CircleShape circleShape;
private FixtureDef fixtureDef;
private BodyDef bodyDef;
private Body circleBody;
private static final float SCENE_WIDTH = 1080;
private static final float SCENE_HEIGHT = 1920f;
public LevelScreen() {
super(new FitViewport(SCENE_WIDTH, SCENE_HEIGHT, new OrthographicCamera(SCENE_WIDTH, SCENE_HEIGHT)));
batch = getBatch();
camera = getCamera();
viewport = getViewport();
world = new World(new Vector2(0,-9.8f), true);
box2DDebugRenderer = new Box2DDebugRenderer();
bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(600, 1000);
ballTexture = new Texture("ball.png");
ball = new Sprite(ballTexture);
ball.setPosition(0,0);
circleShape = new CircleShape();
circleShape.setRadius(25f);
fixtureDef = new FixtureDef();
fixtureDef.shape = circleShape;
fixtureDef.density = 0.5f;
fixtureDef.friction = 0.4f;
fixtureDef.restitution = 0.6f;
circleBody = world.createBody(bodyDef);
circleBody.createFixture(fixtureDef);
box2DDebugRenderer = new Box2DDebugRenderer(
true, /* draw bodies */
false, /* don't draw joints */
true, /* draw aabbs */
true, /* draw inactive bodies */
false, /* don't draw velocities */
true /* draw contacts */);
Gdx.input.setInputProcessor(this);
}
@Override
public void show() {
System.out.println("show");
}
@Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
ball.draw(batch);
batch.end();
world.step(1 / 60f, 6, 2);
ball.setPosition(circleBody.getPosition().x - 25f, circleBody.getPosition().y - 25f);
box2DDebugRenderer.render(world, viewport.getCamera().combined);
}
@Override
public void resize(int width, int height) {
viewport.update(width, height);
System.out.println("resize");
}
@Override
public void pause() {
System.out.println("pause");
}
@Override
public void resume() {
System.out.println("resume");
}
@Override
public void hide() {
System.out.println("hide");
}
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
viewport.getCamera().unproject(point.set(screenX, screenY, 0));
return false;
}
}
您应该为 box2d 使用小型相机,因为 box2d 在 0-10 值下效果更好。 这是你的关卡画面class.Try吧。
public class LevelScreen extends Stage implements Screen {
private Batch batch;
private Camera camera;
private Texture ballTexture;
private Sprite ball;
private Viewport viewport;
private Vector3 point = new Vector3();
private World world;
private Box2DDebugRenderer box2DDebugRenderer;
private CircleShape circleShape;
private FixtureDef fixtureDef;
private BodyDef bodyDef;
private Body circleBody;
private static final float SCENE_WIDTH = 28;
private static final float SCENE_HEIGHT = 48f;
public LevelScreen() {
super(new FitViewport(SCENE_WIDTH, SCENE_HEIGHT, new OrthographicCamera(SCENE_WIDTH, SCENE_HEIGHT)));
batch = getBatch();
camera = getCamera();
viewport = getViewport();
world = new World(new Vector2(0,-9.8f), true);
box2DDebugRenderer = new Box2DDebugRenderer();
bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(10, 28);
ballTexture = new Texture("ball.png");
ball = new Sprite(ballTexture);
ball.setPosition(0,0);
circleShape = new CircleShape();
circleShape.setRadius(1f);
fixtureDef = new FixtureDef();
fixtureDef.shape = circleShape;
fixtureDef.density = 0.5f;
fixtureDef.friction = 0.4f;
fixtureDef.restitution = 0.6f;
circleBody = world.createBody(bodyDef);
circleBody.createFixture(fixtureDef);
box2DDebugRenderer = new Box2DDebugRenderer(
true, /* draw bodies */
false, /* don't draw joints */
true, /* draw aabbs */
true, /* draw inactive bodies */
false, /* don't draw velocities */
true /* draw contacts */);
Gdx.input.setInputProcessor(this);
}
@Override
public void show() {
System.out.println("show");
}
@Override
public void render(float delta) {
Gdx.gl.glClearColor(1, 0, 0, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
batch.begin();
ball.draw(batch);
batch.end();
world.step(1 / 60f, 6, 2);
ball.setPosition(circleBody.getPosition().x - 25f, circleBody.getPosition().y - 25f);
box2DDebugRenderer.render(world, viewport.getCamera().combined);
}
@Override
public void resize(int width, int height) {
viewport.update(width, height);
System.out.println("resize");
}
@Override
public void pause() {
System.out.println("pause");
}
@Override
public void resume() {
System.out.println("resume");
}
@Override
public void hide() {
System.out.println("hide");
}
@Override
public boolean touchDown(int screenX, int screenY, int pointer, int button) {
viewport.getCamera().unproject(point.set(screenX, screenY, 0));
return false;
}
}
好吧,我似乎无法通过简单的评论让您理解。让我们通过代码试试:
屏幕
public class TestScreen implements Screen {
SpriteBatch batch;
OrthographicCamera camera;
World world;
Box2DDebugRenderer dr;
Ball ball;
public TestScreen() {
batch = new SpriteBatch();
camera = new OrthographicCamera(1.6f, 1f); // <---- Very small camera so it passes by fast since less surface is being shown
world = new World(new Vector2(0, -9.8f), true);
ball = new Ball(.11f, world); // <---- Create ball and pass in the diameter
//Try playing with the value of camera let's say we have a ball the size of planet earth:
//ball = new Ball(6371, world);
//Now zoom out the screen so we can see our planet sized ball
//camera = new OrthographicCamera(16000, 10000);
//Believe me, our planet ball falls as fast as the little soccer ball. //But since you zoomed out each pixel represents so much more distance.
dr = new Box2DDebugRenderer(true, false, false, false, false, false);
}
@Override
public void show() {
}
@Override
public void render (float delta) {
Gdx.gl.glClearColor(.1f, .1f, .14f, 1);
Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
batch.setProjectionMatrix(camera.combined);
world.step(Gdx.graphics.getDeltaTime(), 6, 2);
batch.begin();
ball.draw(batch);
batch.end();
dr.render(world, camera.combined);
}
//... Other mandatory screen methods
}
Ball.java
public class Ball {
private float radius;
private CircleShape shape;
private FixtureDef fixtureDef;
private BodyDef bodyDef;
private Body circleBody;
private Texture ballTexture;
public Ball(float radius, World world) {
this.radius = radius;
ballTexture = new Texture("sprites/soccerball.png");
bodyDef = new BodyDef();
bodyDef.type = BodyDef.BodyType.DynamicBody;
bodyDef.position.set(0, 0);
shape = new CircleShape();
shape.setRadius(radius);
fixtureDef = new FixtureDef();
fixtureDef.shape = shape;
fixtureDef.density = 0.5f;
fixtureDef.friction = 0.4f;
fixtureDef.restitution = 0.6f;
circleBody = world.createBody(bodyDef);
circleBody.createFixture(fixtureDef);
}
public void draw(SpriteBatch batch)
{
batch.draw(ballTexture, circleBody.getPosition().x - radius, circleBody.getPosition().y - radius,
radius * 2, radius * 2); // <---- draw the size you give it in the physics engine
}
}
让我们开始你做错了什么:
你给了世界 9.8 个单位的引力。这些不是像素,也不是距离,也不是任何东西。当你决定这些是米(代表地球上的重力)时,它们才会是米,你应该保持真实的比例。
接下来您制作一个半径为 25 米的球,并将相机拉远以显示 1920 米高的区域。在现实生活中,将一个物体从 2 公里高处掉落到地面需要一段时间。因此,由于您在现实世界中使用的是每秒 9.8 米的速度,因此在您的应用程序中落地也需要一些时间。
所以你要做的是缩小规模。足球的半径只有 11 厘米,所以我创建了一个半径为 0.11 米的球。但是你将无法看到它,因为到目前为止它只是一个像素的一小部分。所以放大你的相机(因为它是正交的,你只需设置它的视口尺寸)。
对于有关绘制正确大小的球的后续问题,您只需使用之前给出的半径即可。正如您所看到的球,相机 vp 非常小,球也非常小。对于行星大小的示例,相机被缩小得很远,行星的大小与我们自己的地球一样大。然而,我只是用它的半径画球,一切都会好起来的。
希望你明白,也许你不必想太多,因为这个概念很简单。