Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Multiple cameras in libgdx ( probably similar in other frameworks )

I have been trying to solve this problem for two days and I have given up trying to find an existing solution.

I have started learning libgdx and finished a couple of tutorials. And now I have tried to use all that I have learned and create a simple side scrolling game. Now, I know that there are libgdx examples of this, but I haven't found a one that incorporates Box2d with scene2d and actors as well as tiled maps.

My main problem is with the cameras.

You need a camera for the Stage (which as far as I know is used for the projection matrix of the SpriteBatch passed to the method draw() at actors, if this is wrong please correct me) and you need a camera for the TileMapRender for calling the render() method. Also, in some of the tutorials there is a OrthographicCamera in the GameScreen, which is used where needed.

I have tried to pass a OrthographicCamera object to methods, I have tried to use the camera from the Stage and the camera from the TileMapRenderer everywhere. Ex.

OrthographicCamera ocam  = new OrthographicCamera(FRUSTUM_WIDTH, FRUSTUM_HEIGHT);
stage.setCamera(ocam); // In the other cases i replace ocam with stage.getCamera() or the one i use for the tileMap Render
tileMapRenderer.render(ocam);
stage.getSpriteBatch().setProjectionMatrix(ocam.combined); // I am not sure if this is needed

I have also tried to use different cameras everywhere.

After trying all of this I haven't noted what happens exactly when but I will list what happens :

  • There is nothing on the screen ( Probably the camera is away from the stuff that is drawn )
  • I can see the tiled map and the contours from the debugRenderer (I use debugRender too but I don't think that it interferes with the cameras), but the sprite of the actor is not visible ( probably off screen )
  • I can see everything that I should but when I try to move the Actor and the Camera, which is supposed to follow him, the sprite goes faster than the body ( the green debug square ).

So my main questions are :

  • I don't understand what happens when you have multiple cameras. "Through" which one do you actually see on the montior?
  • Should I use multiple cameras and how ?

Also, I thought that I should mention that I am using OpenGL ES 2.0.

I am sorry for the long question, but I thought that I should describe in detail, since it's a bit complicated for me.

like image 329
Ikspeto Avatar asked Aug 20 '13 22:08

Ikspeto


1 Answers

You actually see through all of them at the same time. They might look at a completely different world though, but all of them render their point of view to the screen. You can use several cameras, or just one. If you use only one you need to make sure that you update the projection matrix correctly, between drawing the TiledMap, your Stage with Actors and maybe for the optional Box2DDebugRenderer.

I'd use an extra Camera for the Box2DDebugRenderer, because you can easily throw it away later. I assume you use a conversion factor to convert meters to pixels and the other way around. Having a 1:1 ratio wouldnt be very good. I always used something between 1m=16px and 1m=128px.

So you initialize it this way, and use that one for your debugging renderer:

OrthographicCamera physicsDebugCam = new OrthographicCamera(Gdx.graphics.getWidth() / Constants.PIXEL_PER_METER, Gdx.graphics.getHeight() / Constants.PIXEL_PER_METER);

For your TiledMapRenderer you may use an extra camera as well, but that one will work in screen-coordinates only, so no conversion:

OrthographicCamera tiledMapCam = new OrthographicCamera(Gdx.graphics.getWidth(), Gdx.graphics.getHeight());

The TiledMap will always be rendered at (0, 0). So you need to use the camera to move around on the map. It will probably follow a body, so you can update it via:

tiledMapCam.position.set(body.getPosition().x * Constants.PIXELS_PER_METER, body.getPosition().y * Constants.PIXELS_PER_METER)

Or in case it follows an Actor:

tiledMapCam.position.set(actor.getX(), actor.getY())

I actually haven't used scene2d together with Box2D yet, because I didn't need to interact very much with my game objects. You need to implement a custom PhysicsActor here, which extends Actor and builds the bridge from scene2d to Box2D by having a body as a property. It will have to set the Actors position, rotation etc based on the Body at every update-step. But here you have several options. You may re-use the tiledMapCam and work in screen-coordinates. In this case you need to always remember to multiply with Constants.PIXELS_PER_METER when you update your actor. Or you will use another cam with the same viewport like the physicsDebugCam. In this case no conversion is needed, but I'm not sure if this might interfere with some scene2d-specific things.

For a ParallaxBackground you may use another camera as well, for UI you can use another stage and another camera again... or reuse others by resetting them correctly. It's your choice but I think several cameras do not influence performance much. Less resetting and conversions might even improve it.

After everything is setup, you just need to render everything, using the correct cameras and render every "layer"/"view" on top of each other. First a ParallaxBackground, then your Tiledmap, then your Entity-Stage, then your Box2DDebugging view, then your UI-stage.

In general remember to call spriteBatch.setProjectionMatrix(cam.combined); and using cam.update() after you changed anything of your camera.

like image 165
noone Avatar answered Oct 03 '22 10:10

noone