Explanations about different coordinates

Hello all,

I’m new to game development, so all the world coordinates, screen coordinates confused me. Can anyone point me to somewhere I could learn more about them? Such as why do we need different coordinates (silly question I know)?
And the positions of game objects or GUI nodes are in which coordinates?
(For example I can get GUI node position by Gui.get_position but when I move a game object to that position, it’s not the same right?)

Thanks!

1 Like

Hi!

So, here’s a few coordinate systems:

  1. GUI positions (and screen_x and screen_y from input actions) are in the Screen system of coordinates, which is (0, 0) in the left-bottom corner and (screen_width, screen_height) in the top-right corner
  2. Game objects are in the World system of coordinates. This is something that you define in your render script when you configure your projection matrix (and view matrix if you move the camera). It’s usually still (0, 0) in the left-bottom corner and (screen_width / some_scale, screen_height / some_scale) in the right-top corner. If you want to convert from Screen to World, you should save that scale factor somewhere. If you also move your camera around, then you’ll also have to offset your values by that.
  3. There’s also action.x and action.y, which are in a legacy coordinate system (which I call Design coordinates), which are (0, 0) in the left-bottom corner and (design_width, design_height) in the right-top corner, the screen resolution you defined in game.project, regardless of the actual size of the window. I generally never use action.x and action.y and use action.screen_x and action.screen_y instead, except for gui.pick_node() that uses Design coordinates for some (probably legacy) reason.
11 Likes

Thanks a lot!

So this is why I found it’s so confusing when I read all the different questions on this topic.

I assume there must be some reasons for all these coordinate systems?

In a really simple 2D game, all the different coordinates may be the same, so it seems like there is no reason for all of this. The problem comes when you move the camera. If you move your camera to the left by 200 pixels, usually you don’t want your interface to be shown 200 pixels off the screen! You want to keep your interface in the same place on screen but see a different part of the game world. So, you essentially draw your GUI using a different camera view that doesn’t move around.

If it was only translation, this wouldn’t be a big deal, you could just offset the GUI, but your world camera can also be rotated in 3 dimensions and scaled (zoomed) at the same time.

The reason for the “Design coordinates” for GUI is a little different. They exist because of how the GUI can scale to fit different window/screen sizes. Say you have GUI nodes anchored to different sides of the screen. If you resize the window, the positions of these nodes will change. This is a real problem if you were using those coordinates in your script! Say you have a node anchored to the right side of the screen and you are animating it’s position to the center of the screen. In the middle of the animation, you resize the window to be much wider. All of a sudden the node’s current position changes, and the target position is not in the center of the screen anymore. To solve this, Defold gives you “design coordinates”, which stay the “same” (from a certain point of view) no matter what. Yes, it’s a minor hassle when you have to convert to and from them to screen coordinates, but you don’t need that very often.

8 Likes

Bookmarking this because even though I’ve got 2 years experience with Defold I find @dapetcu21’s and @ross.grams explanations really useful. :+1:

5 Likes

Same here. I’ll definitely use this for future reference.

1 Like

I agree. We should put this in a manual as well! … making a note …

7 Likes

Thanks all for the answers!

Correct me if I’m wrong, but here are a few things I think that is true too:

  • The coordinate system in the editor (main.collection) is in the World coordinate system (except for the GUI collection if you put one there)
  • Touch or mouse over the screen belongs to the Screen coordinate system (because we get them by using action.x/action.y). Usually you will need to convert them to the World coordinate system, both RenderCam and Orthographic cameras support this.

I also find out something interesting (which contribute to my confusion) while using the Orthographic camera.

Suppose that you have a go and go’s parent. Go’s parent has a scale different than 1 (0.5 in my case). Then if you use the screen_to_world to translate position from screen to world, then use

go.set_position(new_world_pos, 'go')

then go won’t be at the place you think it is in world space (not same positions in the screen space). In my case it’s haft way from (0, 0) to wherever I clicked in the screen.
If you set go’s parent scale to 1 and go to 0.5 instead of the other way around then it will work just fine.

I don’t know why but it took me 1 whole day to figured it out.

Yes, but as you’ve found out, it’s vital to understand that the position, rotation, and scale of objects and components are “Local”. They are relative to the parent. If you have one object that is the child of another, it’s position will be an offset relative to its parent’s position. Likewise for rotation and scale. And these transformations stack up down the tree if you have “grandchildren”, “great-grandchildren”, etc. So only the top-level game objects that have no parent are in “Global” world coordinates.

The regular “go.get_position()”, “go.get_rotation()”, and “go.get_scale()” functions get the Local position/rotation/scale of the game object. There are other “go.” functions to get the Global world position, rotation, scale, or the full transform matrix of game objects if you need them. But keep in mind, there’s no “go.set_world_position”, you would have to use the world transform matrix to calculate the matching local position yourself. In other words, if you want to set the world position of an object (like putting it under the mouse cursor), don’t give it a parent that has any transform.

This sounds complicated, but it really is intuitive. Child objects are “physically” attached to their parent. A watch would be a “child” of your arm—It moves along with your arm no matter how your arm moves, but the watch’s “Local” position relative to your arm doesn’t change.


Almost right. “action.x” and “action.y” from input are in GUI/“Design” coordinates. “action.screen_x” and “action.screen_y” are screen coordinates.

There is a mistake in dapetcu’s original post. GUI positions are NOT in Screen coordinates. The are in the GUI/“Design” coordinate system (the same coordinates as action.x and action.y).

You can easily check this. Make a gui with a script and add it to your main collection. Add a box node and anchor it to the right side of the screen. Add this to the script:

function update(self, dt)
	local node = gui.get_node("box")
	local guiPos = gui.get_position(node)
	local screenPos = gui.get_screen_position(node)
	print("GUI pos = " .. tostring(guiPos) .. ", Screen pos = " .. tostring(screenPos))
end

At first when you run the game they will both be the same, but when you stretch the window horizontally, the GUI pos will stay the same and the Screen pos will change.

You can also try printing out action.x/y and action.screen_x/y in your input function to see how they change when you resize the window.

7 Likes