【问题标题】:Libgdx + Box2d working with 2 camerasLibgdx + Box2d 使用 2 个摄像头
【发布时间】:2016-03-13 17:41:58
【问题描述】:

最近我读到,只要涉及 Box2d,您就可以使用 2 个摄像头,它只能以米为单位。

在我的 Renderer 类中,我接收游戏中的所有实体,然后绘制它们。 我使用 ashley 库,所以我的所有实体都是由组件组成的。

现在,在我的渲染器方法中,我检查当前实体是否有BodyComponent。如果为真,那么它会在 physicsCam 中绘制 Sprite,它的视口为米。否则,它只会在具有像素视口的 sceneCam 中绘制 Sprite。

我的问题是我尝试根据身体的位置(以米为单位)绘制 Sprite,但绘制的不是身体所在的位置。

注意:我也有 PhysicsDebugSystem,它基本上只是调用 DebugRenderer.render() 方法。

这是我的 RenderSystem 类:

package engine.systems;

import com.badlogic.ashley.core.Component;
import com.badlogic.ashley.core.ComponentMapper;
import com.badlogic.ashley.core.Entity;
import com.badlogic.ashley.core.Family;
import com.badlogic.ashley.systems.IteratingSystem;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.graphics.GL20;
import com.badlogic.gdx.graphics.OrthographicCamera;
import com.badlogic.gdx.graphics.g2d.SpriteBatch;
import com.badlogic.gdx.utils.Array;

import engine.Values;
import engine.components.BodyComponent;
import engine.components.SpriteComponent;
import engine.components.TransformComponent;

public class RenderSystem extends IteratingSystem{

    private SpriteBatch batch;
    private Array<Entity> renderQueue;
    private OrthographicCamera sceneCam;
    private OrthographicCamera physicsCam;
    private ComponentMapper<SpriteComponent> txt;
    private ComponentMapper<TransformComponent> trs;

    @SuppressWarnings("unchecked")
    public RenderSystem(SpriteBatch batch) {
        super(Family.all(TransformComponent.class, SpriteComponent.class).get());
        txt = ComponentMapper.getFor(SpriteComponent.class);
        trs = ComponentMapper.getFor(TransformComponent.class);
        sceneCam = new OrthographicCamera(Values.WIDTH, Values.HEIGHT);
        sceneCam.setToOrtho(false);
        physicsCam = new OrthographicCamera(Values.WIDTH, Values.HEIGHT);
        physicsCam.setToOrtho(false);
        renderQueue = new Array<Entity>();
        this.batch = batch;
    }

    @Override
    public void update(float deltaTime) {
        super.update(deltaTime);
        Gdx.gl.glClearColor(230/255f, 242/255f, 242/255f, 0);
        Gdx.gl.glClear(GL20.GL_COLOR_BUFFER_BIT);
        sceneCam.update();
        physicsCam.update();
        batch.enableBlending();
        batch.begin();
        for (Entity entity : renderQueue) {
            Component comp = entity.getComponent(BodyComponent.class);
            if(comp == null) {
                batch.setProjectionMatrix(sceneCam.combined);
            } else {
                batch.setProjectionMatrix(physicsCam.combined);
            }
            SpriteComponent texture = txt.get(entity);
            TransformComponent transform = trs.get(entity);
            if (texture.region == null || transform.isHidden) {
                continue;
            }
            texture.region.setPosition(transform.position.x, transform.position.y);
            texture.region.setRotation(transform.rotation);
            texture.region.setScale(transform.scale.x, transform.scale.y);
            texture.region.draw(batch);
        }
        batch.end();
        renderQueue.clear();
    }

    @Override
    protected void processEntity(Entity entity, float deltaTime) {
        renderQueue.add(entity);
    }

    public OrthographicCamera getCamera() {
        return sceneCam;
    }

}

在我的 GameWorld 类中,我用这种方法构造球:

public void initBall() {
        Entity entity = new Entity();
        float x = Values.WIDTH/2*Values.PPM;
        float y = Values.HEIGHT*Values.PPM;
        SpriteComponent txt = new SpriteComponent();
        txt.region = skin.getSprite("soccerball");
        txt.region.setSize(Values.BALL_WIDTH, Values.BALL_HEIGHT);
        entity.add(txt);
        TransformComponent trs = new TransformComponent();
        trs.isHidden = false;
        trs.position.x = x;
        trs.position.y = y;
        entity.add(trs);
        BodyComponent bc = new BodyComponent();
        BodyDef bodyDef = new BodyDef();
        // Set our body to dynamic
        bodyDef.type = BodyDef.BodyType.DynamicBody;

        // Set our body's starting position in the world
        bodyDef.position.set(x, y+Values.BALL_HEIGHT/2);
        bc.body = world.createBody(bodyDef);
        bc.body.applyAngularImpulse(50f, true);

        CircleShape circle = new CircleShape();
        circle.setRadius(Values.BALL_WIDTH/2f);
        FixtureDef fixtureDef = new FixtureDef();
        fixtureDef.shape = circle;
        fixtureDef.density = 20f;
        fixtureDef.friction = 0.4f;
        fixtureDef.restitution = 0.6f;
        bc.body.createFixture(fixtureDef);
        circle.dispose();
        entity.add(bc);
        engine.addEntity(entity);
    }

这是我在模拟过程中截取的屏幕截图:

【问题讨论】:

  • 我阅读了这篇文章,但我仍然不明白我的代码有什么问题。我为 GUI 使用一台相机,为物理世界使用一台相机。为什么还是不行?
  • 只需使用一台相机。该屏幕截图中没有任何内容可以使用香蕉单位。不要让事情变得更难。

标签: java android libgdx sprite box2d


【解决方案1】:

你的球精灵似乎从你的 box2d 身体偏移渲染的原因是因为你的纹理的锚点是它的左下角,这意味着当你设置你的纹理的位置时,你基本上设置了它的左下角的位置。为了正确定位你的球,你需要从它的位置中减去它的半宽和半高:

final float halfWidth = texture.region.getRegionWidth() * 0.5f;
final float halfHeight = texture.region.getRegionHeight() * 0.5f;
texture.region.setPosition(transform.position.x - halfWidth, transform.position.y - halfHeight);

我还敦促您使用read this box2d blog post,因为根据您发布的代码,您似乎没有缩放您的 box2d 实体,这意味着您拥有的球是Values.BALL_WIDTH 米宽。从屏幕截图来看,它的半径约为 2.5m。那是一个巨大的球!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-31
    • 1970-01-01
    • 2012-06-28
    • 2012-01-28
    • 1970-01-01
    相关资源
    最近更新 更多