25
\$\begingroup\$
  • Most 2D screen/bitmap coordinate systems have the positive Y axis pointing down (with the the origin in the upper left corner).
  • This is counter to how most people think geometrically with the positive Y axis pointing up (with the origin in the center).

How do most games manage the two different 2D coordinate systems? There are two main types of coordinates (screen vs. Cartesian), but there could be many different coordinate spaces: sprite space, world space, view space, screen space, etc...

Background:

I originally made the world coordinates in my game match the 2D screen coordinate convention. This made it very natural to use the graphics drawing routines, but subtle issues arose when using trigonometric functions like atan2(). The results of feeding atan2() 2D screen coordinates are very confusing because atan2() assumes the positive y axis points up.

So I changed my world coordinates to follow the classic Cartesian coordinate system (with the origin at the bottom left of the screen). Reasoning with atan2() is much more straight-forward, but now it is harder to do other types of reasoning:

  • If I click the screen here, what sprite is underneath?
  • Where did I click on that sprite?
  • If a sprite is drawn in the wrong location, what was calculated incorrectly? The screen coordinates or the world coordinates?

I realize conversion from screen to Cartesian coordinates involves simply scaling the y value by -1 with an optional translation of both (x,y) values. I'm more interested in best practices for game design:

  • Do most games just stick with the screen coordinate convention and change their thinking about how things like atan2() should work?
  • When/how are coordinate system conversions done? (Using matrices, OOP abstraction, etc)
  • Are sprite locations stored as the center of the sprite or one of the corners? The sprite's height/width going in the "wrong" direction seems to be a common problem when I draw them.

Although my question is mainly about 2D games, it seems OpenGL uses a coordinate system where the Y axis points up. OpenGL must eventually project those 3D coordinates onto a 2D screen coordinate system. Perhaps some guidance could be found in OpenGL's method...

\$\endgroup\$

4 Answers 4

8
\$\begingroup\$

Having tried every conceivable way of doing it, I have found if it's purely a 2D game, just use the screen drawing system, it will make your life much easier. Sin, Cos, and atan2 need to be used slightly differently, but this inconvenience is easily made up for by the simplicity of knowing which way up, down, clockwise and anti-clockwise are. I would also recommend working in pixels rather than meters for 2D games - it's much easier to think about on-screen distances, and the chances of you wanting to change the whole scale of your game are close to zero.

"How do most games manage the two different 2D coordinate systems?"

  • most 2D games I've seen the source for use the screen system, but each entity should know its world space, let your drawing manager convert this to a screen position. At this point you'll do whatever matrix transformation you need.

"Are sprite locations stored as the center of the sprite or one of the corners?"

  • If you work from the centre it makes rotation more straight forward, although you'll want to know the corners as well.

"Perhaps some guidance could be found in OpenGL's method..."

  • 3D engines are a completely different case. As they have true cameras, the screen position can be wildly different from the world position. For a top-down game you'd be working in the X and Z axes, rather than the X and Y for one thing.
\$\endgroup\$
1
\$\begingroup\$

I may be oversimplifying things here, but my inclination would be to have any 2D/UI subsystem deal strictly in what you dubbed "screen" coordinates. You would have two matrices: ScreenToCartesianTransform and CartesianToScreenTransform. When mouse input events are received, the mouse coordinates would be transformed using CartesianToScreenTransform before being passed to the 2D/UI system's input manager. From there, the UI system would perform hit-testing using the screen coordinate system, and handle (or not handle) the event accordingly. If a mouse input event goes unhandled by the 2D/UI, it could be passed on to the 3D system (if one exists) using the original, untransformed coordinates.

Since the 2D/UI system would deal only in "screen" coordinates, its geometry would need to be transformed via ScreenToCartesianTransform before being processed by the rendering engine.

\$\endgroup\$
1
  • \$\begingroup\$ Actually, depending on which toolkit you're using, the mouse input events may already be in screen coordinates. In that case, you wouldn't transform them for the 2D/UI system, but you would for the 3D system (if one exists). \$\endgroup\$ Aug 9, 2010 at 22:13
0
\$\begingroup\$

I prefer using a display tree like in Flash. I'll have a root node (game view) which contains a child for the world (world node) and one on top for the HUD. Inside the world node will be the nodes for the objects in the game world.

I then simply transform the world node. Along with translation (camera panning) and proportional scaling (camera zooming) I also apply two other transformations:

  • A -1 y-scale to flip the coordinate system.
  • A scaling to convert world units (meters) to screen units (pixels)

I then use y-up / world coordinates in game object drawing code and y-down / screen coordinates in HUD drawing code, which both feel very natural.

To answer questions like "what object am I clicking on" I use display node methods to convert coordinates between coordinate systems (such as globalToLocal and its inverse in Flash).

By the way, atan doesn't really work differently when y is down, you just need to think of all angles as going clockwise instead of counter-clockwise.

\$\endgroup\$
0
\$\begingroup\$

OpenGL, like DirectX, has the X and Z axes along the horizontal plane and Y facing upwards.
I have never had any issues with screen coordinates, and I think the easiest way would simply be to treat it how it is: if something, such as atan2, does not like it, then change parameters being fed.

If you're using relative or local coordinates, such as a scene graph, then a simple function such as ToGlobalCoords() is good. In fact, if you want to learn more about spatial positioning, scene graphs, and localToGlobal, the free extract from Game Engine Architecture is about that.

Sprites are drawn from the top left corner or (0,0) the origin. Reasons why are because of the top left origin of the window.

It seems a little silly to change the window coordinate system, and would make things like input, which plays a larger part to most games than trig does, significantly more difficult. It also alienates you from the norm and any users of your code.

\$\endgroup\$

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .