Game engine worlds exist in a virtual space. There is no magnetic field to point us North. No gravity to keep us on the ground. So how do we know which way is up?
Let’s start with the basics. If you open a game engine and create an object in your world, chances are that the object’s very first parameter is its position in the world - perhaps only surpassed by its name. In the physical world, one of the fundamental laws is that an object must be somewhere, in order to exist. Unless you are planning on making a game which is purely conceptual - which happens more often than you’d think - it helps to have some grounding in reality.
Your object’s locative parameter is typically separated into three values: an X, Y and Z, to mark out three dimensions. More 2D orientated game engines will just use an X and a Y value. These are coordinates, the same as you would find on any line graph, used to reference each point in your world as if on a uniform grid.
So let’s start here with 2D coordinates. Anyone who was taught to read a basic line graph knows that you could plot a point on a graph at (2,3) by first counting two along the X axis, then three along the Y axis. But we make a few unspoken assumptions as we do this. Counting along from where? In which direction? And which axis is which? For a 2D Cartesian graph, these are all standard. Given a graph with two lines, we count from the origin (0,0) where the two lines intersect; we count vertically towards the top of the page for the Y axis and horizontally to the right for the X axis. This means that most graphs dealing with positive values will have their origin in the bottom left, while the X and Y axis stretch rightwards and upwards respectively.
This presumably answers our riddle then, for 2D at least. Which way is up? Easy - towards the top of whatever page our world or graph is on, along the y axis.
But is it? Unfortunately, the first hurdle we have entering the digital space is an issue of hardware. The design of almost every screen breaks one of our graphing assumptions immediately: that we count towards the top of the page. The standard for TV screens, monitors, and tablets is to plot their origin (0,0) at the top-left of the screen,such that the Y axis is counting from screen-top to screen-bottom; unlike a graph’s bottom-left origin. The blame for this typically falls on western writers - coughs in blog - since the written word is read from left-to-right and top-to-bottom. So any mathematicians or graph enjoyers often have to deal with an inverted Y axis, whenever they plot anything on a screen programmatically.
The effect of this screen standard is most evident in 2D game engines, such as Love2D, RPGMaker, GameMaker, which all adhere to an origin point in the top left. So the X axis runs left-to-right along the top of the screen, while the Y axis runs top-to-bottom along the left side of the screen. The general rule for these screen-based coordinate systems is that objects appearing on the screen should have two positive values, while negative values either don’t exist at all or won’t show in the game world. To reinforce this, each of these game worlds exists within a bounded space, whether that be called a canvas, map, or room. Whatever is not in this container is not in the game world.
This seems like a logical system. The hardware coordinates are plotted from the top left, so adhering to a bottom-left or centralised origin seems unnecessary, in spite of the mathematical graphing standard.
So a better answer to our question might be: up is down. For 2D at least.
But what happens when we implement a third dimension? The most appropriate case to start with is the Defold engine. Defold is primarily orientated towards 2D game development, yet is fundamentally a 3D world space, with full 3D capability. The opposite could be said to be true of Unity, a primarily 3D game engine, with settings to enable a 2D editor mode. Yet despite approaching 3D from different angles, their implementation of world coordinates is nevertheless very similar.
Both Defold and Unity 2D stray from our preconceived notion of screen-based 2D engines, instead having a Y axis which runs from bottom-to-top, plus a standard X axis (left-to-right), just like a graph! Each also uses a centralised origin, creating four quadrants, allowing for both positive and negative positional values.
Although both act as 2D engines, we are still able to see the X, Y, and Z values for each object. For both of these engines, the 2D objects still exist in a 3D space, even though their editor viewport snaps to a front-facing graph-based coordinate system. The editor viewport shows the game world from a perspective perfectly parallel to the Z axis. This means that the Z axis still influences the size of smaller objects further away and whether objects appear in front of each other, if they have overlapping XY coordinates. Unity’s 2D template has an orthographic projection camera enabled by default and Defold as an optional parameter, removing the perspective shrinkage of closer and further away objects.
Despite the insertion of 2D objects into a 3D world, ‘up’ remains to be towards the top of the screen.
Yet I have overlooked an engine well known for its ability to handle both 2D and 3D development, Godot. This engine creates a firm divide between the second and third dimensions. If you create a 3D node, you will encounter an XYZ coordinate system very similar to Defold and Unity - X is horizontal left-to-right, Y is vertical bottom-to-top. If you create a 2D node however, the Godot editor will show you an entirely 2D world. Objects in this 2D world have only X and Y coordinates, and more importantly the Y axis is counting top-to-bottom again, returning to our hardware focussed screen-based coordinate system. Arguably, Godot still has a Z axis in its 2D space, in the form of the ‘Z Index’ which can be used to order shapes in overlapping XY positions. However this is optional, since ordering can be handled instead by ‘Y Sorting’: placing higher Y positioned objects in front of lower ones for a 2.5D effect. In the Godot editor these contradictory 2D and 3D coordinate systems are kept safely apart, only mixing when the one is injected into the other as a texture, creating what might be described as a window or viewport between the dimensionally disparate worlds.
So does the lack of conformity between game engine world coordinates stem exclusively from a 2D issue, between screen hardware standards and mathematical graphs? Unfortunately not. Because, for the same reason that there isn’t a right or wrong way to settle whether the Y axis should travel upwards or downwards in virtual space, nor is there a clear decider for the direction of the Z axis.
Unity, Godot 3D, and Defold all have the same XY grid, front-facing towards the developer: X is horizontal left-to-right, Y is vertical bottom-to-top. But although we may understand the term front-facing or billboarded, it raises a question in Z. Are you the origin, or is the main character in your world the origin?
Unity counts the Z, or depth, axis inwards into the screen, while Defold and Godot count it outwards towards the person outside the screen. There are arguments for both. Unity’s Z relies on our external intuition navigating external 3D space. We, the game developer, are using a device with a screen on the front. This device has some thickness or depth behind the screen, which we know from having seen the object in its entirety. If the X axis is comparable to the horizontal base of our screen and the Y the vertical side, it makes sense that the thickness of our screen should constitute the Z. There are certainly pitfalls in this argument, if you happen to be developing on a very flat screen or in VR, since the depth of the device is either negligible or inverted. Yet for the vast majority of screens this is the case. The XYZ dimensions of the game world are contained within the XYZ dimensions of your device. A comparable idea would be of your screen as a window, with forwards being the way you are looking, out the window. In this system, the world extends away from you as the origin.
It seems Unity’s Z is intuitive for us as humans in our 3D world, so why use Defold or Godot’s depth? Sometimes what makes sense for us in the 3D world doesn’t always translate well to practicality in the digital space. For the same reason we use a mouse, stylus, or finger to select objects on a screen rather than trying to grab at them with the full force of our prehensile grip. In the case of us grabbing at a screen, the issue is that we cannot wrap our fingers around something contained within a 2D screen. The same might be said for our depth axis issue.
In the three 3D engines we have looked at so far, we have already touched on a use for the Z axis, even in 2D games. Unlike in reality, objects in a game engine can overlap spatially. To decide which of these objects should be displayed to us, first we must have some form of ordering. Z values can be used by all three engines to achieve this. Godot and Defold prioritise this, opting to use the computer as the origin of their axes, with the Z axis reaching out towards us.
Although not as rigidly coded in hardware as our screen-based top-left origin, the concept of windows on a computer screen being ordered by an outwards increasing Z value is heavily ingrained in every major operating system and many softwares. This OS standard may have been the more intuitive approach during their conception. When televisions and monitors were far bulkier, they were more comparable to a box: a hollow container which held a digital space inside of it. What we have today is a flatter screen, more comparable in depth to a painting or window, depicting an infinitesimal digital world beyond it. It makes far more sense if you visualise peering into a finite open box that the side directly opposite the opening should be the base from which you start any sort of counting, rather than from the opening itself.
With this digital history and operating system infrastructure, it is understandable that Godot and Defold adhere to the same principle. The background of a screen should be marked as the fixed point of origin, while objects moving out of the screen should have a greater priority and magnitude as they become more visible to the user. Bearing in mind the significance of 2D development in Defold and Godot, the Z axis’ direction should prioritise resolving the 2D conflict of overlapping intuitively. Whereas the more 3D orientated Unity imitates the forward direction of the user, as if the world space were a continuation of 3D reality.
As well as deriving coordinates directly from the vast history of mathematical graphing, screen hardware, and operating systems, there are still plenty of other well-used coordinate systems around. So far we have been comparing our digital world coordinates to points on a graph. This is a mathematical approach, however we can also compare with the practical physical renditions of space used to map 3D reality. There are many different types of map, many using non-uniform coordinates like longitude and latitude to account for the earth’s curvature. Ordnance survey maps work best as a parallel for tracking real world coordinates in XY. The basic principle of the system is the same as our graph-based approach: a fundamentally 3D world rendered as 2D, using a grid split into XY coordinates. Funnily enough our OS map depth works the same way as our computer OS. Ordnance survey maps have additional labelling for height, or depth, increasing outwards from the map towards the reader. Yet the clear difference between typical graphs and maps is that the former is viewed front-on, while the latter top-down. This change in perspective is such that XY handles lateral and depth movement, while Z is used for height.
For anyone still keeping track: up is now Z.
Of the game engines supported by Planetary Processing, only Unreal Engine 5 uses a top-down coordinate system. There are multiple possible reasons for adopting this perspective. Using our earlier logic however, Unreal is the engine least targeted towards 2D development. It certainly has the capability for 2D, with the inbuilt Paper2D plugin, but none of it is as immediately accessible, either from a dropdown or template. Unreal’s default templates are all 3D. In fact, the ‘Top Down’ template pack orientates the gamer that way, by setting the perspective to a sharp angle high above the player character avatar, looking down at the XY defined ground.
In this case, it might be worth considering the Unreal world ordinate system to be like a map then, or like a graph laid flat. Or it might not be. Because that will inevitably lead to confusion.
Throughout our investigation our X axis has been fairly standard: horizontal, left-to-right, and reliable. Yet if we use a top-down perspective in Unreal, our X axis will be none of these. In terms of positive XY values, Unreal uses a bottom-right origin. The X axis direction is inverted and rotated, when compared with our top-down map or graph.
Here we start to see an issue with a primarily 3D digital space. We could ‘resolve’ this mismatch in a few different ways: rotate our perspective 90 degrees clockwise and invert the X axis; or rotate our perspective to look at the axes from below, then rotate our perspective 90 degrees anticlockwise; or stop working within the confines of real space and swap the Unreal X and Y axes. None of these seem like an ideal visualisation, each being so removed from our starting orientation or difficult to apply to a map in reality. Does this mean maps and Unreal coordinates incomparable then?
Or is there a great issue here? Should Z never be up?
With the other game engines we looked at, their 2D front-facing elements made it an easy translation to our bottom-left origin XY graph. Because we viewed them first as 2D, when we looked at them in 3D, our perspective was fundamentally the same for each: our X axis running horizontally left-to-right consistently, our Y running vertical and our Z running deep, sometimes with one of the latter two inverted.
Unreal makes two changes to this. The Z is denoting vertical height, while Y has instead become a horizontal axis. This first change is not too significant, effectively achieving our top-down map approach. It happens to be the same approach the 3D modelling software Blender uses for its world coordinates. Yet Unreal’s second change, which is less intuitive to our map comparison, is using the X axis as our forward axis.
Although there was a lot of back and forth, most game engines did agree that the addition of the third axis, Z, should handle the inwards, outwards, forwards, backwards, depth dimension. In making Z the height instead in Unreal, the question becomes which of the X and Y axes should act for depth? The Y axis would seem the most intuitive, if we stick with our graph and map model. These are primarily viewed front-on or top-down, giving the Y axis either an upwards or forwards direction away from the viewer. Since we are using Z as our upwards direction, by elimination our top-down Y direction should be forwards, while X remains a lateral movement for both views.
So why use X as forward? Ironically it actually makes more sense in terms of 2D graphing logic, if not human experience. When explaining the basic mode of using a graph, we said “you could plot a point on a graph at (2,3) by counting two along the X axis and three along the Y axis”. Our first movement is two steps along the X axis, so we might presume that our default direction from our starting origin point is our forward direction. But for any crabs, who love to walk sideways, there is also a more expanded reasoning.
The reason why we count along the X axis first on a graph is a question of order, because in our notation the X value comes before the Y value (2,3). The same can be said for the algebraic ordering of these letters from the alphabet …WXYZ. We don’t often physically count along three dimensional space, but the same method is used for the Z value (2,3,4); we would count two in X, three in Y, and four in Z, in that order.
Yet if we were limited to one dimensional axis any non-crab humans would have to accept that it should align with a human’s primary direction of movement, forward. So if we reduce our 2D coordinates to a 1D ordinate, in the same way as we reduce a 3D coordinate (2,3,4) to a 2D coordinate (2,3), we are left with a 1D ordinate (2) which can be navigated to by a movement two steps in the X axis.
Moving parallel along an axis in a single direction to (0,3) in the Y axis or (0,0,4) in Z, to achieve movement in a single dimension, would not work in this scenario. By notating their values as 2nd and 3rd, we indicate the existence of the unused 1st dimension, which would make the world itself at least two dimensions. Therefore, in a 1D world ordinate system, the positive movement in the X axis has to be, for want of a better word, forward.
To circle back to game development, instead of just dimensional logic patterns, it is slightly easier in programming to use the first of three parameter values. Additionally we might consider that there are entire genres of games for which X is forward. In a standard side-scroller, a character traverses the world with forward movement along the X axis. There is certainly some logic as to why Unreal’s models default facing forwards along the X axis.
Although not a game engine itself, we briefly touched on Blender and how that uses 3D coordinates in the same way as a game world. It is especially pertinent when talking about Unreal, since they both use Z for height. Unlike Unreal however, Blender retains a top-down horizontal X axis, perpendicular to the forward direction.
As well as being primarily an animation tool, Blender can be used for creating 3D models. This is one of the main reasons why the question of world coordinate systems arises in the first place in game development circles. A game engine using a consistent coordinate system for its world is mostly self-contained, so there is no conflict. Yet most game engines have 3D modelling which is rudimentary compared to what is already in-built for animation programs and specially designed modelling softwares. As a result many 3D artists will import model assets from one of these programs into their game engine of choice. Unfortunately because of the mismatch between world coordinates they can appear upside down, flat on their face or back, or simply facing the wrong direction. The issue with this is that their position parameters will always end up being slightly offset, even if you centre them to the new world, since in correcting their imported position you will have created an offset. This offset can cause issues if you want to do any programmatic positioning which encompasses both these assets and those native to your engine.
An even bigger problem arises when importing models from multiple different softwares, since they have systems as various as game engines. To quickly cover a few: Houdini and Maya have a front-facing, Z outwards towards the viewer, graph-based XY, same as Godot and Defold; Cinema 4D has the same again but with its Z inwards away from the viewer, matching Unity; and SketchUp is top-down graph/map-based like Blender.
So far we have been looking primarily at directions and dimensions, trying to work out which way is up, but while on the topic of game world coordinates it would be remiss not to mention game world units. We have talked about counting along axes, but what do these numbers mean? In the physical world, an object has a set size and that size can be measured in units, such as cm, metres, inches, yards, miles and so on. In the digital world size is a bit simpler. Most game engines only use one set of units. For 2D spaces these are usually equivalent to pixels, while for 3D a generic unit is used. This unit is most commonly equated with a metre.
As with the coordinate system, units are not an issue until you start introducing foreign elements to your game engine. Fortunately, more modern file formats have the option for saving metric units directly to a 3D model. Of our supported game engines, only Unreal uses centimetres as the default scale for its world units.
Being able to pre-emptively correct exported models before importing them into your game is normally the main reason for learning different coordinate systems. However any interaction between one world space and another will often require coordinate values to be swapped or inverted. This is the case for the Planetary Processing multiplayer engine too. The Planetary Processing online game dashboard map is a 2D depiction of your game world with centralised origin, X axis counting left-to-right, and Y axis counting bottom-to-top, like a map or graph. We call each square on the coordinate grid a chunk.
Planetary Processing multiplayer is compatible with lots of different game engines yet it is clear that each engine has slightly different game world axes. In order for your online game dashboard map to accurately represent your world, the coordinate values of your game engine need to match those of the Planetary Processing map. The most prevalent coordinate values being sent from your game to the Planetary Processing server are going to be the XYZ positions or movements of your main player character.
Engines which use a 2D exclusive world space such as Love2D or Godot’s Node2D will mostly be using a screen-based coordinate system. For these, the conversion to Planetary Processing coordinates is a simple negation of the Y value, to make their top-left origin into a bottom-left origin.
Engines with a 3D world space but which implement 2D such as Unity, Godot, or Defold, match our graph-based system exactly - no changes needed!
Engines implementing a 3D world space require more care, since the Planetary Processing map itself is only 2D. The map technically has no Z axis, and hence no depth. The layering of entity icons on the game dashboard map oscillates to prevent stacked entities from becoming completely hidden. As a general rule however, despite no mechanical result, we tend to treat the Z axis as if it were coming outwards from the map towards the viewer. This is such that, if the map were a top-down representation of 3D space, the Z axis would be incrementing upwards with the height of the world.
Most 3D game engines (Defold, Unity, and Godot) have front-facing XY coordinates with X as horizontal and Y as vertical. To convert these to top-down XY coordinates, the easiest method is to swap the game engine’s Y value with their Z value; as if rotating the XY grid by ninety degrees, pivoting around the stationary X axis.
Because front-facing XYs are so common, the demo game server code, which is loaded onto every new game, will do a Y<->Z swap by default in the `player.lua` file. However, this is not always enough. Although the final Y-become-Z value can be effectively discarded after the conversion from 3D to 2D, the other Z-become-Y value is retained. So the direction of the original Z axis, pre-swap, affects whether the resulting Y value becomes positive or negative.
* Disclaimer: The default demo code has been altered since this article was published *
We have already gone over the disparity between the inwards and outwards facing Z axes between Defold, Godot, and Unity. For the purpose of the Planetary Processing conversion, Unity requires no additional changes, besides the Y<->Z swap, since the resulting Y faces upwards.
In Godot 3D and Defold, their original Z values must be inverted when sending coordinates to the Planetary Processing game server, to prevent the new resulting Y from counting downwards.
Unreal can be a bit trickier when using the default game server demo code. Since the Y<->Z swap in the demo is a generalised adjustment, converting front-facing XY systems to top-down; it does not account for Unreal already having a top-down XY face. The easiest solution to this is to edit the `player.lua` file in the game server demo code directly to remove the unnecessary conversion, so that the player movement received on the server uses regular XYZ values.
* Disclaimer: The default demo code has been altered since this article was published *
Fortunately, no other changes or conversions need to be made when developing in Unreal because the Planetary Processing plugin itself handles Unreal’s unusual X-as-forward orientation. The plugin has two inbuilt functions which swap the X and Y values when positional data is being transferred: ConvertVectorToServerCoordsMessageData() for player coordinates being sent to the server and GetLocationVector() for entity coordinates being sent from the server.
So which way is up? Well for us here at Planetary Processing, looking at a top-down 2D map, it is progression along the Y axis, but at the same time. from the perspective of your player character inside the 3D game world itself. the Z axis might be considered to be up.
The nature of ‘up’ is influenced not only by perspective but also orientation of the XYZ axes. Every game engine dictates its world coordinates and its units individually, however they wish. This decision is often a reflection on how the engine is intended to be viewed by the player, whether 2D, 3D, top-down, or front-facing.
We have mainly discussed world coordinate systems in terms of dimensionality, influenced by their useability and game development culture. If you want to get deeper into the mathematics and engineering of it, there are some lower level programmatic reasons as to why things like the 3D depth axis might be inverted between engines, relating to vector maths and cross product calculations. If you are interested in exploring this, search for articles about left and right handed coordinate systems for more details.
We hope this article has helped you better understand your own game world coordinates and how they influence not only the absolute position of objects but also your players’ perspective on your game.