Thank you @britzl
Here is a main.script which does most of what I want. I still haven’t figured out how to detect if the game is running on a phone or browser so that this code may be ignored but, this at least solves things for desktop:
There were several tricky things I had to solve:
- When resizing a window by mouse clicking and dragging, constant window resize messages get sent, trying to handle a resize action at that time leads to very bad behavior. Therefore, we have to detect when the mouse button is not pressed down - signaling that a resize operation is not still ongoing.
- We cannot handle the window resize logic in the window_callback because the mouse button may still be down, so we unfortunately have to use the update function. What a mess.
- I have not found a way to avoid passing around 4 global variables just to accomplish this. Passing around self to every function seems worse.
- DefOS is required, and we have to use both defos.get_view_size() and defos.get_window_size() in order to know how what to use for defos.set_view_size(), because defos.set_view_size() needs the x and y from the window size and the width and height from the view size.
Edit: heavily refactored to be better written code.
-- Constants
local DEFAULT_ZOOM = 2
local ALLOWED_ZOOMS = {4, 3, 2, 1}
local SMALLEST_ZOOM = 1
-- State variables
local is_window_resized = false
local is_touch_pressed = false
local view_width, view_height
-- Initialization
function init(self)
window.set_listener(window_callback)
msg.post(".", "acquire_input_focus")
msg.post("@render:", "use_fixed_projection", { near = -1, far = 1, zoom = DEFAULT_ZOOM })
end
-- Window event callback
function window_callback(self, event, data)
if event == window.WINDOW_EVENT_FOCUS_LOST then
print("Window focus lost")
elseif event == window.WINDOW_EVENT_FOCUS_GAINED then
print("Window focus gained")
elseif event == window.WINDOW_EVENT_ICONFIED then
print("Window iconified")
elseif event == window.WINDOW_EVENT_DEICONIFIED then
print("Window deiconified")
elseif event == window.WINDOW_EVENT_RESIZED then
print("Window resized: ", data.width, data.height)
is_window_resized = true
view_width = data.width
view_height = data.height
end
end
-- Input event handler
function on_input(self, action_id, action)
if action_id == hash("touch") and action.pressed then
is_touch_pressed = true
print("Touch detected!")
elseif action.released then
is_touch_pressed = false
end
end
-- Handle window resizing
function on_window_resized()
is_window_resized = false
local base_width = sys.get_config_int("display.width") / DEFAULT_ZOOM
local base_height = sys.get_config_int("display.height") / DEFAULT_ZOOM
local view_x, view_y, view_width, view_height = defos.get_view_size()
local zoom_to_use = SMALLEST_ZOOM
for _, zoom in ipairs(ALLOWED_ZOOMS) do
if view_width >= base_width * zoom and view_height >= base_height * zoom then
zoom_to_use = zoom
break
end
end
if zoom_to_use == SMALLEST_ZOOM then
local window_x, window_y, window_width, window_height = defos.get_window_size()
defos.set_view_size(window_x, window_y, base_width * zoom_to_use, base_height * zoom_to_use)
end
msg.post("@render:", "use_fixed_projection", { zoom = zoom_to_use })
end
-- Update function
function update(self, dt)
if is_window_resized and not is_touch_pressed then
on_window_resized()
end
end