Positioning sprites on devices

I’m trying to try a few things while studying Defold, but I’m not getting what I want.
I have taken the Mobile game template from Defold and made a few simple changes. I want to get the Defold logo (sprite) to be in the lower right corner but I can’t get it.
I have declared in main.script the Fixed Fit projection.

Centering a sprite is easy, but when I try to put it in a corner of the screen it doesn’t show up as it should (when I say put it in a corner I mean that its center coincides with one of the corners of the device).
When trying to put the sprite in the lower left corner, it is positioned further to the left and lower, so that it is almost invisible. I’ve used both “sys.get_config_number” and “window.get_size()” and neither option seems functional. I have attached the project below so that anyone who wants to test it can tell me what I am doing wrong. I really appreciated.

Mobile Template.zip

If the aspect ratio of your device is different from the Width and Height in game.project then the fixed fit will make sure that the area covered by Width x Height will fit inside the display of your device. This means that you either have additional space to the left and right or top and bottom. Like in the screenshots here:

If you want to position something in the lower left corner you will have better luck using a GUI component, since the GUI always covers the entire screen, regardless of aspect ratio.

1 Like

I understand your explanation. The point is that a game object is not a GUI component and I want to reposition the game object, which contains a sprite.

Ok, then you need a way to calculate the world position of the lower left corner of the screen. Ie. you want a screen to world conversion of the 0x0 point. You have an example of it here:

Thank you @britzl I’ve included the
defold-orthographic library into my project, but the Stretch projection is used by default in their render script. How can I change it to fixed projection?
I’ve tried with this line: msg.post("@render:", "use_fixed_projection", { near = -1, far = 1, zoom = 2 }) but nothing changed…

I suggest you to read its doc and manuals
britzl/defold-orthographic: Orthographic camera functionality for the Defold game engine (github.com)

1 Like

Thank you @Dat_Indie
I’ve read it, and now I’m writing this message to set up my projection:

msg.post( "camera", "use_projection", { projection = hash("FIXED_ZOOM") })

But when I try to convert screen to world coordinates the result is not accurate.

I’ve a simple game object with a sprite, and I want to position the center of the sprite in the bottom-left corner of the device. Here is my code:

local v3_val = camera.screen_to_world( hash("/camera"), vmath.vector3(0, 0, 0) )
x0, y0 = v3_val.x, v3_val.y

go.set_position( vmath.vector3(x0, y0, 0), "go1" ) -- game object with Defold logo

and the result:

You could try projection FIXED_AUTO and the following code

local function get_actual_size()
	local display_width = sys.get_config_int("display.width")
	local display_height = sys.get_config_int("display.height")
	local window_width, window_height = window.get_size()
	local sx = window_width / display_width
	local sy = window_height / display_height
	local scale = math.min(sx, sy)
	return {
		width = scale == sx and display_width or window_width / scale,
		height = scale == sy and display_height or window_height / scale,
	}
end

function init(self)
	local display_width = sys.get_config_int("display.width")
	local display_height = sys.get_config_int("display.height")
	local actual_size = get_actual_size()
	local bottom_left = vmath.vector3((display_width - actual_size.width) / 2, (display_height - actual_size.height) / 2, 0)
	go.set_position(bottom_left, "go1")
end
1 Like

Thank you @Chung_Xa I really appreciate your help, but I still without solution. What if I want the FIXED_ZOOM?

Sr, I’m not quite understand how FIX_ZOOM works. However I see there’s camera.window_to_world() api. You could try it.

Ok, I will show some tests trying to position the center of the logo in the bottom-left (0, 0, 0) corner of the screen:

With camera.screen_to_world()

local v3_val = camera.screen_to_world( hash("/camera"), vmath.vector3(0, 0, 0) )
local x0, y0 = v3_val.x, v3_val.y
go.set_position( vmath.vector3(x0, y0, 0), "go1" ) -- logo

The result:

With camera.window_to_world()

local v3_val = camera.window_to_world( hash("/camera"), vmath.vector3(0, 0, 0) )
local x0, y0 = v3_val.x, v3_val.y
go.set_position( vmath.vector3(x0, y0, 0), “go1” ) – logo

The same result:

With camera.screen_to_world_bounds()

local v4_val = camera.screen_to_world_bounds( hash("/camera") )
local xLeft, yTop, xRight, yBottom = v4_val.x, v4_val.y, v4_val.z, v4_val.w
go.set_position( vmath.vector3(xLeft, yBottom, 0), "go1" ) -- logo

and the result is exactly the same as the above two options:

what do you mean? you are using my method?

No, I’m not… I’m using FIXED_AUTO projection as you said,but without your method, just the library.
Finally I’ll include the result with camera.screen_to_world_bounds()

BTW: I used your method and the logo was positioned near from the center of the screen

Can you attached your source code here again?

Sure …

Mobile game

As far as I see that the camera.window_to_world() works well but the defOS rechanges the window size. It makes the position look incorrect.

About my method, since the coord origin is at center of screen, the bottom_left could be calculated like this:

function init(self)
	msg.post( "camera", "use_projection", { projection = hash("FIXED_AUTO") })
	local actual_size = get_actual_size()
	local bottom_left = vmath.vector3(-actual_size.width / 2, -actual_size.height / 2, 0)
	go.set_position(bottom_left, "go1")
end

I’ve updated the sample-screen-to-world-coordinates project so that it also shows how to anchor game objects to the corners of the screen.

The sample project will also let you change the camera component zoom and also set the equivalent of Fixed Fit Projection mentioned in the render manual:

6 Likes

Thank you @britzl
I’ll test it … Forgive my ignorance, but isn’t there a way to achieve this positioning relative to the edges of the screen without having a camera component in the project?

Using your code @Chung_Xa :
(I’ve included the library defold-orthographic to this project)

local function get_actual_size()
	local display_width = sys.get_config_int("display.width")
	local display_height = sys.get_config_int("display.height")
	local window_width, window_height = window.get_size()
	local sx = window_width / display_width
	local sy = window_height / display_height
	local scale = math.min(sx, sy)
	return {
		width = scale == sx and display_width or window_width / scale,
		height = scale == sy and display_height or window_height / scale,
	}
end

msg.post( "camera", "use_projection", { projection = hash("FIXED_AUTO") })
local actual_size = get_actual_size()
local bottom_left = vmath.vector3(-actual_size.width / 2, -actual_size.height / 2, 0)
go.set_position(bottom_left, "go1")

I get this:

The game object I’m trying to position in the bottom-left corner have this sprite:(both have 0,0,0 in their initial positions)
circle

As you can see is not exactly in the corner, but a little up-wards in y axis.

Sure. You would then need to get the view and projection that is used in the render script instead of the one used by the camera. You can do a small modification of your render script and save the view and projection in a module or perhaps a global variable or something end then use it instead.