Rework the UI on Crusenho's pack; credit it in the game, not just the repo
ci / verify (push) Successful in 48s
ci / verify (push) Successful in 48s
Crusenho's Complete UI Essential Pack is CC BY 4.0 -- redistributable and
commercial-friendly, confirmed from the License.txt the pack itself ships --
so unlike the two bdragon packs a subset is committed: twelve PNGs, 48 KB,
under assets/sprites/ui/. Only what is used, because each committed PNG costs
a Godot .import sidecar and a directory nothing references is one nobody
prunes.
UiTheme builds a Theme in code from it -- button states, panels, line edits --
and every screen roots itself through UiTheme.themed_root(). The HUD's bars are
the pack's frame with a tinted fill, drawn as three horizontal slices because
Godot's nine-patch lives on nodes and the HUD is drawn rather than built from
controls. Inventory slots use the pack's slot art at exactly twice the source
size; a non-integer scale on a 1px border reads as a wobble along every edge.
The credits screen is the other half of the request and it is a licence
obligation, not a nicety: two packs are now CC BY, which asks for attribution
"in any reasonable manner", and a markdown file in a source repo is not
reasonable for someone who downloaded a build. Settings -> Credits shows every
source with its terms and a link to the licence text. test_credits.gd asserts
CREDITS.md and docs/ASSETS.md name every entry, so the three cannot drift.
Two things found by actually looking at the screen, which is the point:
- The FIRST version of this styled nothing. A Control inherits its theme from
Control ANCESTORS only, and the chain breaks at the first plain Node or
CanvasLayer -- which is every screen here. get_window().theme set the
property, changed nothing, and read as correct. check.sh, 458 tests and a
clean smoke run all passed with the entire interface unstyled. The theme
test now instantiates every screen and asks what its buttons resolve.
- The settings screen showed Fire bound to the right mouse button, because
the test suite was writing the player's real user://settings.cfg --
rebinding calls save() and nothing had redirected the path. Settings.path
is now redirectable, the fixture points it at a scratch file, and a test
asserts the default is still the player's own.
tools/screenshot.tscn is what found both. It boots the client windowed and
saves the menus, the HUD, settings and credits. Manual, needs a display, and
the only thing in the project that can tell you the interface rendered.
check.sh clean, 460 tests, SMOKE PASS, all four diagnostics green.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,86 @@
|
||||
extends Node
|
||||
## Boot the client windowed, capture a few screens, and quit.
|
||||
##
|
||||
## SHOT_DIR=/tmp/shots godot --path . res://tools/screenshot.tscn
|
||||
##
|
||||
## This exists because UI is the one part of the game the rest of the tooling
|
||||
## cannot check. `check.sh` proves it parses, the suite proves the theme
|
||||
## resolves, the smoke test proves nothing errors -- and all three passed
|
||||
## while the entire interface rendered unstyled, because Godot's theme
|
||||
## inheritance breaks at the first non-Control parent and nothing had ever
|
||||
## looked at the screen.
|
||||
##
|
||||
## Needs a real display, so it is not part of any automated gate. Run it after
|
||||
## touching anything under src/ui/ and open the files.
|
||||
|
||||
const GAME := preload("res://src/game.tscn")
|
||||
## Frame numbers, not seconds: the point is a deterministic sequence, and a
|
||||
## windowed client at 60fps gets there in about four seconds.
|
||||
const AT_MENU := 30
|
||||
const ENTER_GAME := 34
|
||||
const AT_GAME := 200
|
||||
const OPEN_MENU := 210
|
||||
const AT_INGAME_MENU := 240
|
||||
const OPEN_SETTINGS := 250
|
||||
const AT_SETTINGS := 280
|
||||
const OPEN_CREDITS := 290
|
||||
const AT_CREDITS := 320
|
||||
const DONE := 330
|
||||
|
||||
var _frame: int = 0
|
||||
var _game: Node = null
|
||||
var _menu: Control = null
|
||||
var _dir: String = "user://"
|
||||
|
||||
|
||||
func _ready() -> void:
|
||||
GameOpts.parse()
|
||||
Engine.physics_ticks_per_second = SimConfig.TICK_RATE
|
||||
Settings.load_and_apply()
|
||||
var from_env := OS.get_environment("SHOT_DIR")
|
||||
if not from_env.is_empty():
|
||||
_dir = from_env
|
||||
get_window().size = Vector2i(1280, 720)
|
||||
_menu = preload("res://src/ui/main_menu.gd").new()
|
||||
add_child(_menu)
|
||||
|
||||
|
||||
func _process(_delta: float) -> void:
|
||||
_frame += 1
|
||||
match _frame:
|
||||
AT_MENU:
|
||||
_grab("menu")
|
||||
ENTER_GAME:
|
||||
_menu.queue_free()
|
||||
Net.host(27455)
|
||||
Net.start_local_client()
|
||||
_game = GAME.instantiate()
|
||||
add_child(_game)
|
||||
AT_GAME:
|
||||
_grab("game")
|
||||
OPEN_MENU:
|
||||
_game.get_node("GameMenu").open()
|
||||
AT_INGAME_MENU:
|
||||
_grab("menu_ingame")
|
||||
OPEN_SETTINGS:
|
||||
_game.get_node("GameMenu").close()
|
||||
_game.get_node("SettingsScreen").open()
|
||||
AT_SETTINGS:
|
||||
_grab("settings")
|
||||
OPEN_CREDITS:
|
||||
_game.get_node("SettingsScreen").visible = false
|
||||
_game.get_node("CreditsScreen").open()
|
||||
AT_CREDITS:
|
||||
_grab("credits")
|
||||
DONE:
|
||||
Net.shutdown()
|
||||
get_tree().quit(0)
|
||||
|
||||
|
||||
func _grab(shot_name: String) -> void:
|
||||
var path := "%s/shot_%s.png" % [_dir, shot_name]
|
||||
var err := get_viewport().get_texture().get_image().save_png(path)
|
||||
if err != OK:
|
||||
printerr("could not write %s (error %d)" % [path, err])
|
||||
return
|
||||
print("saved ", path)
|
||||
@@ -0,0 +1 @@
|
||||
uid://bnuqy4w5whjce
|
||||
@@ -0,0 +1,6 @@
|
||||
[gd_scene load_steps=2 format=3]
|
||||
|
||||
[ext_resource type="Script" path="res://tools/screenshot.gd" id="1"]
|
||||
|
||||
[node name="Screenshot" type="Node"]
|
||||
script = ExtResource("1")
|
||||
Reference in New Issue
Block a user