Hello, im developing this game for mobile.
Im using ortographic.camera library, and im developing the onscreen controls.
It works perfectly on PC until i resize, or i try the game on mobile (because on my phone the game is resized)
The problem is that the on_input action.x/action.y are not corresponding to the real gui node position… only on initial state. I think there is something that i dont know where i have to make adjustment on resize of the window… But which kind of adjustment?
I have a gui with 2 nodes: 1 is “CONTROLS”: the static circle with the 4 directional arrows, and the other is “POINTER” on the same position of “CONTROLS” but it follow the dragging touch input.
And this is the initial code that i’m using to make this control in my gui_script:
function init(self)
print("GUI CONTROLS INIT")
msg.post(".", "acquire_input_focus")
self.TOUCH = hash("touch")
self.pointer = gui.get_node("pointer")
self.controls = gui.get_node("controls")
end
function update(self, dt)
if self.dragging then
msg.post("@render:", "draw_line", {
start_point = gui.get_position(self.controls),
end_point = gui.get_position(self.pointer),
color = vmath.vector4(1, 0, 0, 1) } )
end
end
function on_input(self, action_id, action)
if action_id == self.TOUCH and action.pressed and gui.pick_node(self.pointer, action.x, action.y) then
self.dragging = true
print("START")
elseif self.dragging and action.released then
self.dragging = false
gui.set_position(self.pointer, gui.get_position(self.controls))
print("END")
elseif self.dragging then
print("DRAGGGING")
gui.set_position(self.pointer, vmath.vector3(action.x, action.y, gui.get_position(self.pointer).z))
end
end
If you’re resizing the window then you’ll likely run into problems with action.x/y and mapping that to the current projection and zoom level. It works in the default render script where the game area is stretched to fit the entire window dimensions, but as soon as you change projection to something else or start zooming then action.x/y will no longer map to how the game is rendered. For correct translation from screen to world coordinates there’s functions such as camera.screen_to_world() in the lib.
BUT with that said, the gui should render separately from the game world, meaning that for gui the action.x/y should work. I assume it’s the gui.pick_node() call that doesn’t work?
Are you using the render script provided by Defold-Orthographic? Which kind of projection are you using (DEFAULT, FIXED_ZOOM, FIXED_AUTO or a custom one)?
The virtual gamepad example didn’t properly take care of a scaled window when it calculated the relative movement of the analog stick. The button does work properly regardless of how you scale the window. I pushed a fix to the repo for the analog stick. It should now behave correctly even when you resize the window.
I’ll see if I can figure out what kind of problem you’re encountering when using the Defold-Orthographic extension.
I changed the GUI nodes setting anchor, and using gui.get_screen_position to detect the position of the pointer and the controls… It works better, and i added a maximum distance for the pointer…
But there is a problem resizing the window… The nodes are rendered perfectly, but the coordinates from on_input are in a “stretched space”…
I think we’re near to the solution… Here a video example to clarify what i tried to explain.
Ok @britzl , I’m sending to you a project test, I think the ON_INPUT action coordinates refers only to the original GUI size, after windows resizing too (the gui nodes are adjusted correctly, but the on_input coordinates refers to stretched original windows size)
Yes, action.x and action.y will always translate to coordinates that are within the range of the display width and height specified in game.project while action.screen_x and action.screen_y are the coordinates of the mouse/touch in resized window.
If you print action.x when you’ve resized the window to make it wider you see that action.x when hovering over the center of your gui node is the same, but as you go left and right towards the edge of the node the values no longer match with a window that isn’t resized.
In your case it gives you problems since you compare action.x and action.y with the values from gui.get_position() to determine a distance. This is a problem since gui.get_position() always returns the position in the coordinate system of a screen with dimensions from game.project.
My recommendation is that you keep track of the position where the user pressed on your virtual gamepad and use that position when you measure the distance you’ve moved the cursor, because that distance will always be comparable to your max radius. Like I do in my example.
Ah, I see now what’s happening. You have anchoring set on the nodes. In my example I have no anchoring which explains the difference. Let me play around and present a solution.
This is quite a bit more complex than first anticipated.
The reason why it is so complex is that when it comes to something such as a virtual game pad you need to do more than simple gui picking (which always works automatically). With a virtual analog stick we also need to limit the distance the stick can be moved which means that we need to take into consideration the adjust mode of the stick (is it zoomed or stretched) as well as its alignment.
There are some tools that we can use, for instance the action.x vs action.screen_x for scaled or physical touch coordinates. We can also read the display dimensions as specified in game.project and compare these to the current physical dimensions of the screen using the window listener event. Disabling the adjust mode of the gui completely and manually centering the virtual game pad based on actual window size could also be an option.
Ok, @britzl I finally solved the problem… I’m using on the starting point action.x and action.y for the gui.picknode
but for positioning and checking distance i use only screen_x and screen_y translated to GUI coordinates system
-- On windows resized
-- if Adjust mode is zoom instead of fit, use math.max obviously
scal = math.min(newwindowX / configuratedX, newwindowY / configuratedY)
offx = (newwindowX - configuratedX * scal) * 0.5 / scal
offy = (newwindowY - configuratedY * scal) * 0.5 / scal
-- Translate screen coordinates to GUI coordinates system (stretched on windows resize)
x = screen_x / scal - offx
y = screen_y / scal - offy
It works like a charme on GUI (adjust mode per node, Fit and ZOOM)!!
This is my first problem of the first game on Defold: it was tough! But I learned various things that I am sure will help me. Thank you!