Recently I have read that you can work with 2 cameras whenever you involve Box2d, which only works in meters.
In my Renderer class, I receive all the entities in the game and then draw them. I work with ashley library so all my entities are a formed by components.
Now, in my renderer method I check if the current Entity has BodyComponent. If true, then it draws the Sprite in the physicsCam, who has a Viewport of meters. Otherwise, it will just draw the Sprite in sceneCam, which has a Viewport of pixels.
My problem is I try to draw the Sprite according to the Body's position in meters, but it is drawn not exactly where the body is.
NOTE: I also have PhysicsDebugSystem which basically just call the DebugRenderer.render() method.
Here is my RenderSystem class:
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;
}
}
In my GameWorld class I construct the ball in this method:
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);
}