extends SceneTree # Forgejo #228: the HUD must not be three times larger on a PC than on a # phone. # # The layout is authored in CANVAS units. With stretch "canvas_items" and # aspect "expand" over a 1920x1080 base, a 720x1280 phone scales by 0.375 and # gets 1920x3413 canvas units, while ANY 16:9-or-wider screen lands on # 1920x1080 units however many pixels it really has. The canvas is three # times shorter, so an unscaled 148-unit button goes from 4.3% of the # screen's height to 13.7% of it. # # Nothing collides - that was checked pair by pair on both canvases and the # same six pairs overlap on each, all of them same-slot alternatives. The # fault is purely that everything is enormous. # # Covers: # A. on a phone the HUD is left exactly as authored # B. on a desktop canvas a control takes a similar FRACTION of the screen # rather than three times more # C. the shrink is bounded, so a landscape phone keeps thumb-sized targets # D. it follows a resize rather than only applying once at startup const PHONE: Vector2i = Vector2i(720, 1280) const DESKTOP: Vector2i = Vector2i(1920, 1080) const BIG_DESKTOP: Vector2i = Vector2i(2560, 1440) var scene: Node var hud: Node var button: Control var frames: int = 0 var stage: int = 0 var phone_fraction: float = 0.0 func _initialize() -> void: var gs: Node = root.get_node("GameState") gs.buildings.clear() gs.reset_new_game() gs.intro_active = false scene = load("res://world/Main.tscn").instantiate() root.add_child(scene) current_scene = scene hud = scene.get_node("UI/HudScale") button = scene.get_node("UI/MapButton") func _fraction() -> float: # Height of a HUD control as a share of the screen's height - the number # that actually differs between the two, and the one a player sees. # Rendered height, not the layout rect: the rect keeps its authored size # and the node is scaled, so scale is where the shrink actually lives. return (button.size.y * button.scale.y) / button.get_viewport_rect().size.y func _process(_delta: float) -> bool: frames += 1 if frames < 10: return false frames = 0 match stage: 0: root.size = PHONE stage = 1 return false 1: # --- A. authored size on the shape it was authored for ------- var k: float = hud.hud_scale() if not is_equal_approx(k, 1.0): return _fail("the phone HUD is being scaled by %.3f, but it is the authored shape" % k) phone_fraction = _fraction() print("phone %s: canvas %.0f tall, scale %.2f, control is %.1f%% of the screen" % [ PHONE, button.get_viewport_rect().size.y, k, phone_fraction * 100.0]) root.size = DESKTOP stage = 2 return false 2: # --- B. a similar share of a desktop screen ------------------ var pc_fraction: float = _fraction() var ratio: float = pc_fraction / maxf(phone_fraction, 0.0001) print("desktop %s: canvas %.0f tall, scale %.2f, control is %.1f%% of the screen (%.2fx the phone)" % [ DESKTOP, button.get_viewport_rect().size.y, hud.hud_scale(), pc_fraction * 100.0, ratio]) if ratio > 1.75: return _fail("a HUD control is %.2fx its phone share on a desktop screen - that is the bug" % ratio) # --- C. and not shrunk into uselessness ---------------------- if hud.hud_scale() < 0.4: return _fail("the HUD shrank to %.2f, past anything pressable" % hud.hud_scale()) root.size = BIG_DESKTOP stage = 3 return false 3: # --- D. follows the resize ----------------------------------- var big: float = _fraction() print("big desktop %s: control is %.1f%% of the screen" % [BIG_DESKTOP, big * 100.0]) if absf(big - phone_fraction) / maxf(phone_fraction, 0.0001) > 0.75: return _fail("a bigger desktop screen did not keep the control proportional (%.1f%% vs %.1f%%)" \ % [big * 100.0, phone_fraction * 100.0]) # Back to the phone: the HUD must return, not stay shrunk. root.size = PHONE stage = 4 return false 4: if not is_equal_approx(hud.hud_scale(), 1.0): return _fail("returning to the phone shape left the HUD at %.3f" % hud.hud_scale()) if absf(_fraction() - phone_fraction) > 0.001: return _fail("the HUD did not come back to its authored size on resize") print("resizing back to the phone restored the authored size") print("TEST_HUD_SCALES_TO_SCREEN: PASS") quit(0) return true return false func _fail(message: String) -> bool: print("TEST_HUD_SCALES_TO_SCREEN: FAIL (%s)" % message) quit(1) return true