118 lines
4.4 KiB
GDScript3
118 lines
4.4 KiB
GDScript3
|
|
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
|