I have a top-down character on the main menu. It should rotate according to the current mouse position. Example: If the mouse is above the character, the character should look up.
I tried
-- the position to look at (mouse/finger)
local target_position = camera.screen_to_world(CAMERA_ID, vmath.vector3(action.x, action.y, 0))
-- own position
local my_position = gui.get_position(self.character)
self.rotation_x = my_position.x - target_position.x
self.rotation_y = target_position.y - my_position.y
But this doesn’t work as expected. My character is in the upper right corner of the screen and the rotation is based on a point somewhere in the middle of the screen. I also tried to use the gui.screen_to_local function but with this function I get a similar result.
For context: In-game I use the code mentioned above and it works perfectly but for the main menu (GUI) it doesn’t work.
function init(self)
-- set default values
self.rotation_x = 0
self.rotation_y = 0
end
local function rotate_character(self, x, y)
-- calculate the angle that this object has to rotate to look at the given point
local angle = math.atan2(x, y)
-- set rotation as a quaternion / rotate this object to look at the target position
gui.set_rotation(self.character, vmath.quat_rotation_z(angle))
end
function update(self, dt)
rotate_character(self, self.rotation_x, self.rotation_y)
end
local function gui_to_screen(gui_position)
-- get the game's design resolution (from game.project)
local design_width = tonumber(sys.get_config("display.width"))
local design_height = tonumber(sys.get_config("display.height"))
-- get the actual screen resolution
local screen_width, screen_height = window.get_size()
-- calculate the scale factor
local scale_x = screen_width / design_width
local scale_y = screen_height / design_height
-- map GUI coordinates to screen space
local screen_x = gui_position.x * scale_x
local screen_y = gui_position.y * scale_y
-- return the mapped screen coordinates
return vmath.vector3(screen_x, screen_y, gui_position.z)
end
function on_input(self, action_id, action)
-- on mouse movement
if action_id == nil then
-- the position to look at (mouse/finger)
local target_position = gui_to_screen(vmath.vector3(action.x, action.y, 0))
-- own position
local character_position = gui.get_screen_position(self.character)
self.rotation_x = character_position.x - target_position.x
self.rotation_y = target_position.y - character_position.y
end
end
function init(self)
-- make sure the script will receive user input
msg.post(".", "acquire_input_focus")
self.node = gui.get_node("node") -- get a node
end
local function look_at(target_position)
-- gui node positon
local my_position = gui.get_position(self.node)
-- calculate the angle that this node has to rotate to look at the given point
local angle = math.atan2(my_position.x - target_position.x, target_position.y - my_position.y)
-- set rotation as a quaternion
gui.set_rotation(self.node, vmath.quat_rotation_z(angle))
end
function on_input(self, action_id, action)
-- mouse/finger movement has action_id set to nil
if not action_id then
-- the position to look at (mouse/finger)
local target_position = vmath.vector3(action.x, action.y, 0)
-- rotate this object to look at the target position
look_at(target_position)
end
end
local function gui_to_screen(gui_position)
-- get the game's design resolution (from game.project)
local design_width = tonumber(sys.get_config("display.width"))
local design_height = tonumber(sys.get_config("display.height"))
-- get the actual screen resolution
local screen_width, screen_height = window.get_size()
-- calculate the scale factor
local scale_x = screen_width / design_width
local scale_y = screen_height / design_height
-- map GUI coordinates to screen space
local screen_x = gui_position.x * scale_x
local screen_y = gui_position.y * scale_y
-- return the mapped screen coordinates
return vmath.vector3(screen_x, screen_y, gui_position.z)
end
function on_input(self, action_id, action)
-- on mouse movement
if action_id == nil then
-- the position to look at (mouse/finger)
local target_position = gui_to_screen(vmath.vector3(action.x, action.y, 0))
-- own position
local character_position = gui.get_screen_position(self.character)
-- calculate the angle that this object has to rotate to look at the given point
local angle = math.atan2(character_position.x - target_position.x, target_position.y - character_position.y)
-- set rotation as a quaternion / rotate this object to look at the target position
gui.set_rotation(self.character, vmath.quat_rotation_z(angle))
end
end
…but the gui_to_screen function seems to be necessary otherwise it doesn’t work as expected.