Libgdx Viewport and World Units

Hello,

I want to start working on a very long project which i wil
work on and learn from. I’ve been making some basic games. Now i feel it’s tine to step it up a notch.

My idéa is to create a 2.5d game such as Zelda. But i got stuck with viewport and world units. Since there is alot of viewports i can choose from and i’ve read what they offer. So what is the preferred viewport, dimension and world unit for a 2.5d rpg mobile/desktop game?

Thanks

Edit: Just saw you meant the libgdx viewport class! The ScalingViewport works well.

camera = new OrthographicCamera();
viewport = new ScalingViewport(Scaling.fit, worldWidth , worldHeight, camera);

worldWidth/Height can be in meters, just multiply your screen width/height in pixels with the meters per pixel you want to achieve.
Keep in mind that worldWidth/Height parameter is NOT the size of your entire game world but the size of the viewport in world coordinates!

Don’t forget to update the viewport upon resize!

viewport.setWorldSize(worldWidth , worldHeight);
viewport.update(screenHeight, screenHeight, false);

Have a look at this paper: Dimetric View
(You can choose different angles, like 45 degrees downwards camera angle and no rotation along the z-axis, like in the screenshot on page 27)

An camera like this allows for simple sprite creation and projection math (just multiply/divide by sqrt(0.5) to project/unproject) while giving you a good view on the xy plane.

This is how the 45 degrees top down orthographic view looks like in my game:

[these are all sprites]

I just choose meters as a unit, 10 pixels are 1 meter, you’ll probably want more pixels per meter.

Keep in mind that this is a very subjective question, there is no correct answer!

Vatteger gave a solid answer, the viewports and cameras are quite a tricky topic to wrap your head around. But, once you get it, its feels obvious.

I would add to that question; how do you determine (for yourselves) how to define a 1 meter in your game? While I’ve not completed anything since changing to libgdx / java, I’ve tended to define it based on the height of the player (1.1-1.3 meters).

On that same line, how do you determine what are good movement speeds and acceleration rates? As in, do you just go by how it looks / feels, or do you run some numbers trying to figure out what should be best for the circumstance? (If the latter, could an example be provided?)

Printer - Are you looking for a true 2.5D game? Or are you thinking more like Zelda snes style where its a 2d game where the depth field is simulated graphically (as in, walking up stairs just moves you to an area with a different collision layer to create the illusion of height?)

I ask only because Zelda is not really 2.5D in the same sense that it’s usually discussed.

BTW - This is a HUGE undertaking, particularly if you are working solo… probably more than you might realize. I don’t say that to dissuade you, only to give you the warning that, if you are as noob as I am, it’s very easy to bite off more than you can chew, and will find yourself wasting many weeks figuring out things that would take someone with more experience a matter of hours, only to tick off one notch on the project list that is many pages long.

You could just choose real world proportions for calculations (human ~ 1.8m, speed in m/s etc) and use the viewport class to transform this into screen coordinates.
You calculate the sprites world size by multiplying the size in pixels by some factor.

Lets say you want 32 pixel per meter along the x axis with a 45 degrees camera angle.

public static final float ymodp = (float)Math.sqrt(0.5d); //multiply this with y to project
public static final float ymodu = 1f/ymodp; //multiply this with y to unproject

public static final float ppm = 32; //pixels per meter
public static final float mpp = 1f/ppm; // meters per pixel

public static int wv = Gdx.graphics.getWidth(); //Sceen width in pixels
public static int hv = Gdx.graphics.getHeight(); //Sceen height in pixels

public static float ww = wv * mpp; //Viewport width in meters
public static float hw = hv * mpp; //Viewport height in meters

Before using your Sprite call this once to set it’s size to be in meters:

sprite.setSize(sprite.getWidth() * mpp, sprite.getHeight() * mpp);

and for the batch:

spriteBatch.setProjectionMatrix(camera.combined);

And when rendering (sprite.getWidth() is in meters now):

sprite.setPosition(-sprite.getWidth() / 2f + position.x, -sprite.getHeight() / 2f + (position.y + position.z) * ymodp);
sprite.draw(spriteBatch);

This draws the sprite centered. (y+z)*projectionCoefficient is only possible because the camera is tilted 45 degrees which means that y and z have equal influence on the perceived y-position of the sprite on screen!

You can now do all other calculations in the normal world coordinate system where 1 unit is 1 meter in all directions.

To move the camera keep in mind that the y axis is not flat anymore, you need to use your projection constant:

public void setPosition(float x, float y, float z) {
	camPos.set(x, y, z); //keep the camera position in world coordinates for later use

	Math2D.project(camPosProjected.set(camPos)); //transform
	
	camera.position.set(camPosProjected); //set position
	camera.update();
}

public static Vector3 project(Vector3 v){
	v.y = Metrics.ymodp * (v.y + v.z);
	v.z = 0f;
	return v;
}

Here’s the whole magic:
GameScreen
SpriteRenderSystem
CameraController2D
Math2D
Metrics

Agreed. And also try to encapsulate the transformation from world units to pixel units completely within your projection matrix.
You should never have to do any such unit transformations/calculations explicitly when setting any sprite sizes or positions.
Every size and position on a sprite or any other model should use world coordinates (meters, feet, or whatever you choose).