当前位置: 首页 > 知识库问答 >
问题:

Box2D无法理解其工作方式-libgdx

李经国
2023-03-14

我试图在libgdx中使用Box2D,但不幸的是,我似乎无法理解它的工作方式。

这里有几个让我抓狂的例子:

shape.setAsBox(1, 2);

最后,关节的值。我定义了一个多边形形状的体和一个地面体。现在我用旋转关节把这两个“固定”在地面的中心,目的是创造一个能在一定范围内很好地旋转的弹射器。

现在我还定义了一个鼠标关节,这样我就可以很好地来回拖动弹射器(多边形形状),但似乎我需要设置关节的maxForce到一个巨大的值,这样我就可以看到弹射器的移动/旋转!我不懂.所有这件事都应该由小的价值来操作,关于我必须建立的价值。

这里是我的非常基本的代码,它包含了上面所有的内容。请告诉我,我做错了什么,我在这里吓坏了:

package com.david.box2dpractice;

import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.Screen;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.Texture;
import com.badlogic.gdx.graphics.g2d.Sprite;
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.ChainShape;
import com.badlogic.gdx.physics.box2d.FixtureDef;
import com.badlogic.gdx.physics.box2d.PolygonShape;
import com.badlogic.gdx.physics.box2d.BodyDef.BodyType;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.physics.box2d.joints.RevoluteJointDef;
import com.badlogic.gdx.utils.Array;

public class GameScreen implements Screen{

    private Box2DDebugRenderer debugRenderer;
    private Texture texture;
    private Sprite sprite;
    private Sprite tempSprite;
    private SpriteBatch batch;
    private Body arm , ground;
    private World world;
    public OrthographicCamera camera;
    private RevoluteJointDef jointDef;
    private Array<Body> tempBodies;

    public GameScreen() {
        debugRenderer = new Box2DDebugRenderer();
        batch = new SpriteBatch();
        texture = new Texture(Gdx.files.internal("catapult_arm.png"));
        camera = new OrthographicCamera();
        camera.setToOrtho(false, Gdx.graphics.getWidth(), Gdx.graphics.getHeight());
        tempBodies = new Array<Body>();
    }
    @Override
    public void render(float delta) {
        // TODO Auto-generated method stub
        Gdx.gl.glClearColor(0, 0, 0, 0);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        batch.setProjectionMatrix(camera.combined);
        world.getBodies(tempBodies);
        batch.begin();
        for(Body body : tempBodies) {
            if(body.getUserData() != null && body.getUserData() instanceof Sprite) {
                tempSprite = (Sprite) body.getUserData();
                tempSprite.setPosition(body.getPosition().x-tempSprite.getWidth()/2, body.getPosition().y-tempSprite.getHeight()/2);
                tempSprite.setRotation((float) Math.toDegrees(body.getAngle()));
                tempSprite.draw(batch);
            }
        }
        batch.end();
        debugRenderer.render(world, camera.combined);
        world.step(1/60f, 6, 2);
    }

    @Override
    public void resize(int width, int height) {
        // TODO Auto-generated method stub
        Gdx.app.log("System", "resize() was invoked");
    }

    @Override
    public void show() {
        // TODO Auto-generated method stub
        Gdx.app.log("System", "show() was invoked");
        world = new World(new Vector2(0,0), true);
        sprite = new Sprite(texture);
        BodyDef bodyDef = new BodyDef();
        bodyDef.position.set(Gdx.graphics.getWidth()/2,Gdx.graphics.getHeight()/2+sprite.getHeight()/2);
        bodyDef.type = BodyType.DynamicBody;

        // The shape
        PolygonShape shape = new PolygonShape();
        shape.setAsBox(11, 91);

        // The fixture
        FixtureDef fixtureDef = new FixtureDef();
        fixtureDef.shape = shape;
        fixtureDef.density = .10f;
        arm = world.createBody(bodyDef);
        arm.createFixture(fixtureDef);
        sprite.setOrigin(sprite.getWidth()/2, sprite.getHeight()/2);
        arm.setUserData(sprite);
        shape.dispose();

        bodyDef = new BodyDef();
        bodyDef.position.set(Gdx.graphics.getWidth()/2,Gdx.graphics.getHeight()/2);
        bodyDef.type = BodyType.StaticBody;

        ChainShape shape2 = new ChainShape();
        shape2.createChain(new Vector2[] {new Vector2(-20*Pixels_To_Meters,0),new Vector2(20*Pixels_To_Meters,0)});

        // The fixture
        fixtureDef.shape = shape2;
        fixtureDef.restitution = .65f;
        fixtureDef.friction = .75f;
        ground = world.createBody(bodyDef);
        ground.createFixture(fixtureDef);
        shape2.dispose();
        // joint
        jointDef = new RevoluteJointDef();
        jointDef.bodyA = arm;
        jointDef.bodyB = ground;
        jointDef.localAnchorB.set(ground.getLocalCenter());
        jointDef.localAnchorA.set(arm.getLocalCenter().x,arm.getLocalCenter().y-sprite.getHeight()/2);
        jointDef.enableLimit = true;
        jointDef.enableMotor = true;
        jointDef.motorSpeed = 15;
        jointDef.lowerAngle = (float) -Math.toRadians(75);
        jointDef.upperAngle = (float) -Math.toRadians(9);
        jointDef.maxMotorTorque = 4800;
        world.createJoint(jointDef);
        Gdx.input.setInputProcessor(new InputHandler(arm,ground,world,camera));
    }

    @Override
    public void hide() {
        // TODO Auto-generated method stub
        Gdx.app.log("System", "hide() was invoked");
        dispose();
    }

    @Override
    public void pause() {
        // TODO Auto-generated method stub
        Gdx.app.log("System", "pause() was invoked");
    }

    @Override
    public void resume() {
        // TODO Auto-generated method stub
        Gdx.app.log("System", "resume() was invoked");
    }

    @Override
    public void dispose() {
        // TODO Auto-generated method stub
        Gdx.app.log("System", "dispose() was invoked");
        texture.dispose();
        batch.dispose();
        world.dispose();
    }
}
package com.david.box2dpractice;

import com.badlogic.gdx.InputProcessor;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.math.Vector2;
import com.badlogic.gdx.math.Vector3;
import com.badlogic.gdx.physics.box2d.Body;
import com.badlogic.gdx.physics.box2d.Fixture;
import com.badlogic.gdx.physics.box2d.QueryCallback;
import com.badlogic.gdx.physics.box2d.World;
import com.badlogic.gdx.physics.box2d.joints.MouseJoint;
import com.badlogic.gdx.physics.box2d.joints.MouseJointDef;

public class InputHandler implements InputProcessor{

    Body ground;
    MouseJoint mouseJoint;
    MouseJointDef mouseJointDef;
    World world;
    Vector2 target,initialPos;
    Vector3 temp;
    QueryCallback query;
    OrthographicCamera camera;
    boolean firstTime = true;
    public InputHandler(Body arm, Body ground, final World world, OrthographicCamera camera) {
        this.camera = camera;
        this.ground = ground;
        this.world =  world;
        mouseJointDef = new MouseJointDef();
        target = new Vector2();
        temp = new Vector3();
        mouseJointDef.bodyA = ground;
        mouseJointDef.collideConnected = true;
        mouseJointDef.maxForce = 9000;
        query = new QueryCallback() {

            @Override
            public boolean reportFixture(Fixture fixture) {
                // TODO Auto-generated method stub
                if(!fixture.testPoint(temp.x, temp.y))
                    return true;
                if(firstTime) {
                    initialPos = new Vector2(fixture.getBody().getPosition().x,fixture.getBody().getPosition().y);
                    firstTime = false;
                }
                mouseJointDef.bodyB = fixture.getBody();
                mouseJointDef.target.set(temp.x,temp.y);
                mouseJoint = (MouseJoint) world.createJoint(mouseJointDef);
                return false;
            }
        };
    }
    @Override
    public boolean keyDown(int keycode) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean keyUp(int keycode) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean keyTyped(char character) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean touchDown(int screenX, int screenY, int pointer, int button) {
        // TODO Auto-generated method stub
        camera.unproject(temp.set(screenX, screenY, 0));
        world.QueryAABB(query, temp.x, temp.y, temp.x, temp.y);
        return true;
    }

    @Override
    public boolean touchUp(int screenX, int screenY, int pointer, int button) {
        // TODO Auto-generated method stub
        if(mouseJoint == null) 
            return false;
        mouseJoint.setTarget(initialPos);
        world.destroyJoint(mouseJoint);
        mouseJoint = null;
        firstTime = true;
        return true;
    }

    @Override
    public boolean touchDragged(int screenX, int screenY, int pointer) {
        // TODO Auto-generated method stub
        if(mouseJoint == null)
            return false;
        camera.unproject(temp.set(screenX, screenY, 0));
        mouseJoint.setTarget(target.set(temp.x, temp.y));
        return true;
    }

    @Override
    public boolean mouseMoved(int screenX, int screenY) {
        // TODO Auto-generated method stub
        return false;
    }

    @Override
    public boolean scrolled(int amount) {
        // TODO Auto-generated method stub
        return false;
    }

}

如果你能帮我,我真的真的理解。谢谢!!

共有1个答案

仉成益
2023-03-14

Box2D只是物理引擎,逻辑部分。它对视图不起作用,因此将米转换为像素是您的工作。
libgdx中,这可以通过使用摄像机来完成。
您已经准备好使用摄像机了,但您给它的视口大小“错误”。
您告诉摄像机要和游戏一样大(GDx.Graphics.GetWidth,GDx.Graphics.GetWidth,GDx.Graphics.GetHeight),而不是您应该考虑要在屏幕上显示多少米。
如果要显示宽80米、高45米(16/9),则需要设置相机,如下所示:

 camera = new OrthographicCamera();
 camera.setToOrtho(false, 80, 45);

因此,如果您的游戏的分辨率为1600*900px,则每米将转换为20px(相机为您执行此操作),如果您使用的分辨率为800*450,则每米将转换为10px。

此外,box2Ds P(0/0)不在屏幕的中间,它不在屏幕的任何位置。它在box2D世界的P(0/0)上,您的工作是在中间或底部或任何您想要的地方绘制它。
同样,这是由相机完成的。默认情况下,相机S P(0/0)位于屏幕的中间,但您可以将相机四处移动,因此它可以无处不在。

现在应该很清楚了,您创建的形状不是“超小”的,只是您没有“放大”。一辆3米长的汽车,如果你从100米远的地方看,它似乎很小。如果你站在离它1米远的地方,你几乎无法一次看到整辆车,因为它比你的“视区”还要大。
我不确定关节/力,但如果你用相机“放大”,你的问题就解决了。但我也可能错了,因为我从来没有用过Box2D...

一些教程:

  1. iforce2d-box2d,这是一个fpr C++的教程。但是通过阅读解释,您应该能够理解它,并且能够在Java/libgdx中实现它。
  2. 在Libgdx游戏中使用Box2D,本教程向您展示如何使用Box2D和Libgdx创建游戏。了解如何将box2D与libgdx连接,这将非常有帮助。
 类似资料:
  • 问题内容: 我正在尝试了解其工作原理。 我在他们的文档中看到他们使用预先填充的用户列表。我想玩一个数据库存储的用户列表。 但是,我不了解本模块中的某些内容。 每次请求都会调用此代码吗?这是用来加载我的用户对象的所有详细信息吗? 现在,我有以下代码: 当我访问/ make-login时,我想登录。 我的用户类别: 另外,我写了另外两个用于身份验证/注册的功能 我不知道如何使它与MySQL一起使用。另

  • 我的gradle构建: 处理器不在单独的模块中。 处理器不做任何事情,在< code>#process中,它只是抛出,看看它是否在工作。 但绝对没有发生任何事情。没有错误,什么都没有。我怎样才能使它工作?

  • 我需要用新顶点更新我的网格。我这样创建VBO(最初创建时只有一个顶点): 然后我要更新VBO缓冲区,并将新顶点写入其中。请注意,我创建VBO是为了给我的新顶点留有足够的空间,并且我控制它不会被过度填充。我还控制每个渲染调用绘制多少元素,因此我不会绘制空的0/0/0顶点。 我的问题是,这段代码可以工作: 因此,当我传递整个顶点数组,从头开始重新分配VBO内存时,它就会提取出我所需要的内容。但是我希望

  • 我正在尝试在两个设备之间使用wifi dirict发送图像。然后接收设备将其发送到数据库。 它给了我这个错误 }

  • 问题内容: 我正在尝试在Swift中使用碰撞位掩码和接触测试位掩码,我希望两个对象不会碰撞在一起,所以我正在做: 由于SpriteKit对这两个数字执行AND操作,因此结果不应该是因为? 那么为什么仍然发生碰撞呢? 谢谢。 问题答案: 这不是冲突处理的工作原理。当两个物体相交时,物理引擎在当前物体与他人的物体 之间执行逻辑运算符: 当两个物理物体相互接触时,可能会发生碰撞。通过执行逻辑“与”运算,

  • 问题内容: 我有一个终结点实现,即将一个对象传递给参数列表。我正在尝试使用@NotNull批注来验证该对象是否为null。 如果该对象被验证为非null,则端点将仅返回200 OK响应。但是,当我使用指定的路径向该终结点发出请求时,体内没有任何内容时,不会引发任何错误。相反,我能够检索200响应(即使我在返回响应之前检查对象是否为null,也表明是这种情况)。 有人可以指导我如何以正确的方式验证对