diff --git a/docs/ui-baseline/smoke/01-main.png b/docs/ui-baseline/smoke/01-main.png index c5860e6..bc86592 100644 Binary files a/docs/ui-baseline/smoke/01-main.png and b/docs/ui-baseline/smoke/01-main.png differ diff --git a/docs/ui-baseline/smoke/02-log-panel.png b/docs/ui-baseline/smoke/02-log-panel.png index ee988fd..65152d0 100644 Binary files a/docs/ui-baseline/smoke/02-log-panel.png and b/docs/ui-baseline/smoke/02-log-panel.png differ diff --git a/docs/ui-baseline/smoke/11-gold-exchange-panel.png b/docs/ui-baseline/smoke/11-gold-exchange-panel.png index 7b0ea76..819f1e6 100644 Binary files a/docs/ui-baseline/smoke/11-gold-exchange-panel.png and b/docs/ui-baseline/smoke/11-gold-exchange-panel.png differ diff --git a/docs/ui-baseline/smoke/12-land-menu.png b/docs/ui-baseline/smoke/12-land-menu.png index 754714a..5458cda 100644 Binary files a/docs/ui-baseline/smoke/12-land-menu.png and b/docs/ui-baseline/smoke/12-land-menu.png differ diff --git a/docs/ui-baseline/smoke/17-dog-panel.png b/docs/ui-baseline/smoke/17-dog-panel.png index 504cc8a..eb6d615 100644 Binary files a/docs/ui-baseline/smoke/17-dog-panel.png and b/docs/ui-baseline/smoke/17-dog-panel.png differ diff --git a/docs/ui-baseline/smoke/18-zoom-in.png b/docs/ui-baseline/smoke/18-zoom-in.png index df4194c..491dc78 100644 Binary files a/docs/ui-baseline/smoke/18-zoom-in.png and b/docs/ui-baseline/smoke/18-zoom-in.png differ diff --git a/docs/ui-baseline/smoke/19-zoom-out.png b/docs/ui-baseline/smoke/19-zoom-out.png index 89eb676..d3f16d5 100644 Binary files a/docs/ui-baseline/smoke/19-zoom-out.png and b/docs/ui-baseline/smoke/19-zoom-out.png differ diff --git a/godot/FarmGodot/scripts/bootstrap.gd b/godot/FarmGodot/scripts/bootstrap.gd index e04885d..f97bdcc 100644 --- a/godot/FarmGodot/scripts/bootstrap.gd +++ b/godot/FarmGodot/scripts/bootstrap.gd @@ -15,6 +15,8 @@ const LOADING_BAR_SIZE := Vector2( LOADING_BAR_TARGET_WIDTH * LOADING_BAR_SOURCE_SIZE.y / LOADING_BAR_SOURCE_SIZE.x ) const LOADING_BAR_POSITION := Vector2((DESIGN_SIZE.x - LOADING_BAR_SIZE.x) * 0.5, 792.0) +const LOADING_BAR_SLOT_REGION := Rect2(190.0, 83.0, 738.0, 68.0) +const LOADING_FILL_SOURCE_REGION := Rect2(57.0, 55.0, 1003.0, 113.0) const STARTUP_ASSET_PATHS := [ "res://scenes/ui/game_scene.tscn", "res://assets/egret/common/common.png", @@ -71,6 +73,7 @@ var _api_client: ApiClient var _loading_layer: Control var _loading_fill_clip: Control var _loading_percent_label: Label +var _loading_fill_size := Vector2.ZERO var _preloaded_resources: Array[Resource] = [] @@ -170,34 +173,36 @@ func _build_loading_ui() -> void: bar_group.add_child(bar_bg) var fill_texture := load(LOADING_BAR_FILL_PATH) as Texture2D + var fill_rect := _loading_fill_rect() + _loading_fill_size = fill_rect.size _loading_fill_clip = Control.new() _loading_fill_clip.name = "FillClip" - _loading_fill_clip.position = Vector2.ZERO - _loading_fill_clip.size = Vector2.ZERO + _loading_fill_clip.position = fill_rect.position + _loading_fill_clip.size = Vector2(0.0, fill_rect.size.y) _loading_fill_clip.clip_contents = true _loading_fill_clip.mouse_filter = Control.MOUSE_FILTER_IGNORE bar_group.add_child(_loading_fill_clip) var fill := TextureRect.new() fill.name = "Fill" - fill.texture = fill_texture + fill.texture = _make_atlas_texture(fill_texture, LOADING_FILL_SOURCE_REGION) fill.expand_mode = TextureRect.EXPAND_IGNORE_SIZE fill.stretch_mode = TextureRect.STRETCH_SCALE - fill.size = LOADING_BAR_SIZE + fill.size = fill_rect.size fill.mouse_filter = Control.MOUSE_FILTER_IGNORE _loading_fill_clip.add_child(fill) _loading_percent_label = Label.new() _loading_percent_label.name = "Percent" - _loading_percent_label.position = Vector2.ZERO - _loading_percent_label.size = LOADING_BAR_SIZE + _loading_percent_label.position = fill_rect.position + _loading_percent_label.size = fill_rect.size _loading_percent_label.horizontal_alignment = HORIZONTAL_ALIGNMENT_CENTER _loading_percent_label.vertical_alignment = VERTICAL_ALIGNMENT_CENTER _loading_percent_label.mouse_filter = Control.MOUSE_FILTER_IGNORE - _loading_percent_label.add_theme_font_size_override("font_size", 30) + _loading_percent_label.add_theme_font_size_override("font_size", 24) _loading_percent_label.add_theme_color_override("font_color", Color.WHITE) _loading_percent_label.add_theme_color_override("font_outline_color", Color.html("#5b2a0e")) - _loading_percent_label.add_theme_constant_override("outline_size", 4) + _loading_percent_label.add_theme_constant_override("outline_size", 3) bar_group.add_child(_loading_percent_label) @@ -208,6 +213,31 @@ func _fit_cover_size(source_size: Vector2, target_size: Vector2) -> Vector2: return source_size * scale +func _loading_bar_scale() -> float: + return LOADING_BAR_SIZE.x / LOADING_BAR_SOURCE_SIZE.x + + +func _loading_fill_rect() -> Rect2: + var scale := _loading_bar_scale() + var slot_position := LOADING_BAR_SLOT_REGION.position * scale + var slot_size := LOADING_BAR_SLOT_REGION.size * scale + var fill_size := Vector2( + slot_size.x, + slot_size.x * LOADING_FILL_SOURCE_REGION.size.y / LOADING_FILL_SOURCE_REGION.size.x + ) + var fill_position := slot_position + Vector2(0.0, (slot_size.y - fill_size.y) * 0.5) + return Rect2(fill_position, fill_size) + + +func _make_atlas_texture(texture: Texture2D, region: Rect2) -> Texture2D: + if texture == null: + return null + var atlas := AtlasTexture.new() + atlas.atlas = texture + atlas.region = region + return atlas + + func _preload_startup_assets() -> void: var total := maxi(STARTUP_ASSET_PATHS.size(), 1) for index in range(STARTUP_ASSET_PATHS.size()): @@ -257,7 +287,10 @@ func _asset_progress(value: float, total: int) -> float: func _set_loading_progress(progress: float) -> void: var normalized := clampf(progress, 0.0, 1.0) if _loading_fill_clip != null and is_instance_valid(_loading_fill_clip): - _loading_fill_clip.size = Vector2(LOADING_BAR_SIZE.x * normalized, LOADING_BAR_SIZE.y) + var fill_size := _loading_fill_size + if fill_size == Vector2.ZERO: + fill_size = _loading_fill_rect().size + _loading_fill_clip.size = Vector2(fill_size.x * normalized, fill_size.y) if _loading_percent_label != null and is_instance_valid(_loading_percent_label): _loading_percent_label.text = "%d%%" % roundi(normalized * 100.0) diff --git a/godot/FarmGodot/tools/verify_loading_screen.gd b/godot/FarmGodot/tools/verify_loading_screen.gd index 0707737..5ca4f76 100644 --- a/godot/FarmGodot/tools/verify_loading_screen.gd +++ b/godot/FarmGodot/tools/verify_loading_screen.gd @@ -8,6 +8,8 @@ const BAR_SOURCE_SIZE := Vector2(1117.0, 223.0) const BAR_WIDTH := 500.0 const BAR_SIZE := Vector2(BAR_WIDTH, BAR_WIDTH * BAR_SOURCE_SIZE.y / BAR_SOURCE_SIZE.x) const BAR_POSITION := Vector2((DESIGN_SIZE.x - BAR_SIZE.x) * 0.5, 792.0) +const BAR_SLOT_REGION := Rect2(190.0, 83.0, 738.0, 68.0) +const FILL_SOURCE_REGION := Rect2(57.0, 55.0, 1003.0, 113.0) var _failures: Array[String] = [] @@ -37,12 +39,25 @@ func _run() -> void: _expect(bar != null and _near(bar.size.x, BAR_SIZE.x), "loading progress bar width should use adapted source ratio") _expect(bar != null and _near(bar.size.y, BAR_SIZE.y), "loading progress bar height should use adapted source ratio") var clip := layer.get_node_or_null("ProgressBar/FillClip") as Control + var fill := layer.get_node_or_null("ProgressBar/FillClip/Fill") as TextureRect var percent := layer.get_node_or_null("ProgressBar/Percent") as Label + var fill_rect := _fill_rect() + _expect(clip != null and _near(clip.position.x, fill_rect.position.x), "loading fill should align to frame inner slot x") + _expect(clip != null and _near(clip.position.y, fill_rect.position.y), "loading fill should align to frame inner slot y") + _expect(fill != null and _near(fill.size.x, fill_rect.size.x), "loading fill visual width should fit frame inner slot") + _expect(fill != null and _near(fill.size.y, fill_rect.size.y), "loading fill visual height should fit frame inner slot") + _expect(fill != null and fill.texture is AtlasTexture, "loading fill should use cropped atlas region") + if fill != null and fill.texture is AtlasTexture: + var atlas := fill.texture as AtlasTexture + _expect(_near(atlas.region.position.x, FILL_SOURCE_REGION.position.x) and _near(atlas.region.position.y, FILL_SOURCE_REGION.position.y), "loading fill atlas should crop transparent source margin") + _expect(_near(atlas.region.size.x, FILL_SOURCE_REGION.size.x) and _near(atlas.region.size.y, FILL_SOURCE_REGION.size.y), "loading fill atlas should use source visual bounds") + _expect(percent != null and _near(percent.position.x, fill_rect.position.x), "loading percent text should align to fill x") + _expect(percent != null and _near(percent.position.y, fill_rect.position.y), "loading percent text should align to fill y") bootstrap.call("_set_loading_progress", 0.5) - _expect(clip != null and _near(clip.size.x, BAR_SIZE.x * 0.5), "loading fill width should match 50 percent") + _expect(clip != null and _near(clip.size.x, fill_rect.size.x * 0.5), "loading fill width should match 50 percent") _expect(percent != null and percent.text == "50%", "loading percent text should show 50%") bootstrap.call("_set_loading_progress", 1.0) - _expect(clip != null and _near(clip.size.x, BAR_SIZE.x), "loading fill width should match 100 percent") + _expect(clip != null and _near(clip.size.x, fill_rect.size.x), "loading fill width should match 100 percent") _expect(percent != null and percent.text == "100%", "loading percent text should show 100%") bootstrap.queue_free() if not _failures.is_empty(): @@ -66,3 +81,15 @@ func _near(value: float, expected: float) -> bool: func _cover_size(source_size: Vector2, target_size: Vector2) -> Vector2: var scale := maxf(target_size.x / source_size.x, target_size.y / source_size.y) return source_size * scale + + +func _fill_rect() -> Rect2: + var scale := BAR_SIZE.x / BAR_SOURCE_SIZE.x + var slot_position := BAR_SLOT_REGION.position * scale + var slot_size := BAR_SLOT_REGION.size * scale + var fill_size := Vector2( + slot_size.x, + slot_size.x * FILL_SOURCE_REGION.size.y / FILL_SOURCE_REGION.size.x + ) + var fill_position := slot_position + Vector2(0.0, (slot_size.y - fill_size.y) * 0.5) + return Rect2(fill_position, fill_size)