2D scrolling game

Started by
15 comments, last by Servant of the Lord 11 years, 1 month ago

I am currently centering the player this way:


player.draw(playerX - cameraX + (screen.width/2), playerY - cameraY + 240);

This do indeed work, although i'm confused as to why it does. Since playerX = cameraX I am just drawing it at screen.width/2. Say screen.width/2 is 400px. If cameraX is at 800 the player will still be drawn at 400px, yet still be centered in the screen. Why is that?

Advertisement

Because your cameraX is the top-right (or bottom-right) of the camera, and not the center of the camera.

You're mixing two different formulas into a single location:

A) You're calculating the center of the camera from the camera's position and the screen size.

B) You're calculating the player's on-screen position from his absolute (or 'world') position and the (now centered) camera.

I suggest you keep your camera position as the center point of the camera, I just find it easier that way. Then your function would just look like:

player.draw(playerX - cameraX, playerY - cameraY);

Further, holding a 2D 'position' is a very very common game task. It adds extra visual code clutter and extra opportunities for mistakes if for every 'position' you have two variables (one for x and one for y).

Instead, a position is a prime candidate for its own struct or class.

A 'Point' class, that contains an 'x' and 'y', and has built-in addition and subtraction functions. Instead of every function taking an 'x' and a 'y', now you just take a 'point'.

This further reduces and simplifies your code to:

player.draw(playerPos - cameraPos);

It has the extra same code costs, but alot less visual clutter, and alot less potential for bugs, and alot easier maintenance, and alot easier readability.

Here's the interface for my point class: http://ideone.com/lH9X3B

Here's the source file: http://ideone.com/G5aAst

Many people (and different libraries) have their own custom point class. It's a very useful thing to have.

I suggest you make yourself a Point, a Size, and a Rect (which contains a Point and a Size).

if playerpos = (400,0) and camerapos = (800,0) and the player is still centered on the screen, then something is wrong.

It should be drawing the player at (-400,0) relative to the center of the screen, which should be on the left side of the screen.

As to why it works, since playerpos = camerapos, playerpos-camerapos = (0,0). So then when you add half your screenDimension, which is the center of the screen, it will center the player onto the screen.

Because your cameraX is the top-right (or bottom-right) of the camera, and not the center of the camera.

You're mixing two different formulas into a single location:

A) You're calculating the center of the camera from the camera's position and the screen size.

B) You're calculating the player's on-screen position from his absolute (or 'world') position and the (now centered) camera.

I suggest you keep your camera position as the center point of the camera, I just find it easier that way. Then your function would just look like:


player.draw(playerX - cameraX, playerY - cameraY);

Further, holding a 2D 'position' is a very very common game task. It adds extra visual code clutter and extra opportunities for mistakes if for every 'position' you have two variables (one for x and one for y).

Instead, a position is a prime candidate for its own struct or class.

A 'Point' class, that contains an 'x' and 'y', and has built-in addition and subtraction functions. Instead of every function taking an 'x' and a 'y', now you just take a 'point'.

This further reduces and simplifies your code to:


player.draw(playerPos - cameraPos);

It has the extra same code costs, but alot less visual clutter, and alot less potential for bugs, and alot easier maintenance, and alot easier readability.

Here's the interface for my point class: http://ideone.com/lH9X3B

Here's the source file: http://ideone.com/G5aAst

Many people (and different libraries) have their own custom point class. It's a very useful thing to have.

I suggest you make yourself a Point, a Size, and a Rect (which contains a Point and a Size).

"I suggest you keep your camera position as the center point of the camera." Hmm, not sure I follow. Isn't the camera view camera.x + camera.width and camera.y + camera.height? Also I'm not sure I entirely understand the difference between world position and screen position.

Say object A and B is at (50, 50)

If I draw them like this:


A.draw(50, 50);
B.draw(50 - camera.x, 50 - camera.y);

A will be at (50, 50) within the screen all the time. B will be drawn at (50, 50) world position. Is the coordinates within the screen always the same?

"I suggest you keep your camera position as the center point of the camera." Hmm, not sure I follow.
Isn't the camera view camera.x + camera.width and camera.y + camera.height?

Also I'm not sure I entirely understand the difference between world position and screen position.

Say object A and B is at (50, 50)

If I draw them like this:


A.draw(50, 50);
B.draw(50 - camera.x, 50 - camera.y);

A will be at (50, 50) within the screen all the time. B will be drawn at (50, 50) world position. Is the coordinates within the screen always the same?

APIs usually have their drawing code takes positions relative to the screen (well, relative to the screen's 'view', which is then stretched to fit the screen). So A.draw(50,50) always means (50,50) within the screen (i.e. in 'screen space'). A.draw(-50,-50) will always draw (-50, -50) outside of the screen (still in 'screen space' coordinates).

Positions in space are always relative to some known point. Putting a position in 'screen space' is making it relative to the screen/camera/view.

'world space' or 'world positions' or 'absolute positions' (Whatever you want to call it, the terms aren't standardized) mean that the positions are relative to the center of your 'world', whatever you define the 'world' as. (It could be the current level you have loaded, or the entire game world, or only the current fraction of the area that's actually loaded around the player).

Your camera position is always in 'world space' coordinates.
So if your camera is at (100, 100), then it really means 'world space origin' + (100,100), but 'world space origin' is (0,0) and so not mentioned.

When drawing, you want to convert to screen space. Screen space's origin is cameraPos.

Since you should keep your entities in world space (since the entities are within the world, unlike your GUI):


EntityAPos = (500, 500) //This is actually (0,0) + (500,500), since the entity's position is in world space.
CameraPos = (400, 400) //This is actually (0,0) + (400, 400), since the camera's position is in world space.

positionOfEntityAInScreenSpace = EntityAPos - CameraPos 


This is now (100, 100)... it's but converted to screen space, because 'cameraPos' is the origin of screenspace.
Since your drawing functions take screenspace coordinates, this is what you pass to those functions.

Some APIs, like SFML, handle these conversions for you. Others don't.

Have you ever generated a random number using (rand() % 50) + 25 ?
It generates a number from 25 to 74.
First you generate a number from 0 to 49. This is in the 'domain' (or as I've been calling it above, the 'space') of 0 - 49.
Then, you shift it over to a new 'domain', making '25' be the origin instead of 0. So the new domain is from '25 to 74'.
The range (50) stayed the same, the origin just shifted. We shifted it from one "space" or "domain" to a new "space" or "domain".

When we convert the entity's position from world-space to screen-space, everything stays the same, but the origin shifts to be relative to the camera, instead of relative to the world.

If you aren't understanding, this isn't because it's a difficult subject, it's simply because I'm doing a butchered job of explaining it! laugh.png

Maybe graphs will help me illustrate:
worldspacegraph1.png

worldspacegraph2.png

Servant of the Lord it's not a bad way to explain it, but it's not that clear either. I'm not saying this because I could explain it better, but because i was trying to learn from your example but..I feel that I got a little closer to understanding it , but ... biggrin.png

About the screen/ camera space it says infinite in every direction, is this mistake or am I not undestanting something here. As screen space is definetly finite?

My forte` isn't explanations. Someone else could (and hopefully will) explain it in less words and clearer.

Just because the screen isn't infinite (let's say it's 800 x 600), the screen space is a Cartesian grid with x, y, axes that can go negative or positive.

Even if your screen is from (0,0) to (800, 600), the position (-100, -700) is outside of the screen's rectangle, but still in 'screen space' coordinates, because it's still relative to the same origin as the screen.

Everything in space is relative to some other position. There's no such thing as a 'position' except as a measurement relative to another point (the origin of your measurement).

A 'position' of an object is the distance between the object and the origin of the 'space' it is being measured in.

Where is the Earth located? You can give me the distance of the Earth from the Sun. That would make the Sun the origin, and you measuring the Earth's position in what we'll arbitrarily decide to call 'Sun-space'. Or you can give me the location of the Earth relative to the center of our Galaxy, making the center of the galaxy the origin.

Or you can give me the distance relative to the center of the universe, making the center of the universe the origin.

None of these are incorrect answers - they all refer to the same location (the location of the earth) but are in different coordinate spaces.

To convert between these spaces:

earthPosInGalaxySpace = earthPosInSolarSystemSpace + originOfSolarSystemInGalaxySpace

earthPosInUniverseSpace = earthPosInGalaxySpace + originOfGalaxyInUniverseSpace

Any 'space' is something that we make up. They only exist, because we can't measure anything (not position, not size) without measuring it relative to something else.

With 2D sprites, we measure 'size' at the pixel scale. We measure 'position' in a variety of ways, and we frequently convert between them as the need requires:

origin of the entire game world

origin of the area within the game world ("Green Forest")

origin of the subportion of the area that happens to be loaded around us

origin of the camera

These are just several possible coordinate spaces. At the very least, in almost every 2D game, you have 'world space' (what you keep your entity locations in) and 'camera space' (what is visible onscreen). Different people have different names for these - the names don't matter, the concept does.

If you say something is at position (0,0), you probably mean either relative to the game world, or relative to the camera - but it's important to understand which you want. Likely, all your API draw functions take screen-space coordinates. Likely, you'll want to keep all the objects in world-space coordinates. So knowing how to convert between spaces is important.

Thankfully, the formula is very simple:

originInNewSpace = (positionInCurrentSpace + originOfCurrentSpace)

In Johnell's case:

posInWorldSpace = (positionInCameraSpace + originOfCameraSpace)

posInCameraSpace = (positionInWorldSpace - originOfCameraSpace)

This topic is closed to new replies.

Advertisement