A top-left readout for performance work: smoothed FPS and frame time, the worst
frame in a rolling two-second window, the active view, player speed, a frame counter
and the player's position in metres from the project origin.
- **F3** toggles it, through the console variable so a packaged build
can be checked without a rebuild ().
- **On automatically** for and , so the performance capture never
depends on pressing a key first; **off in the built demo**, because a player should
not see an FPS counter over Hollywood Boulevard.
- The first two seconds are a **warm-up window** excluded from the worst-frame figure.
Without it the readout showed 'worst 400 ms' for a healthy run: the startup shader
and streaming hitches dominated the rolling maximum.
Measured cost on the self-test route at 1440p: 2.64 -> 2.77 ms average, about 5 %,
still 6x the floor. The release-check number stays the overlay-off run; the overlay-on
series is committed beside it as Docs/perf/0.2.0-walk-frametimes-overlay.csv.
Docs: controls (F3 row, overlay section, switch table), release checks (cost row),
architecture building block view (HUD and input list).
One pawn, both rigs (ADR-9): a skeletal body hidden in first person, a
collision-tested spring arm, and a toggle that swaps the active camera and the
body's visibility. Shipped default stays first person; -thirdperson starts the
pawn in the third-person rig so the review shot is reproducible, and the
screenshot run passes it.
Three defects found and two fixed:
- The skin material had no SkeletalMesh usage flag, so Unreal silently substituted
the default grey. That is why the body rendered as clay.
- render_screenshots.sh still called ./Engine/... on this branch (the fix lives on
the facade branch and never reached main); applied here so the shots generate.
- OPEN: the idle clip is bound and PlayAnimation is called - the run logs the clip
name - but the body still renders in bind pose, arms out. Recorded with that
evidence in TODO.md rather than called done.
Shot 5 (demo-third-person) added and documented; camera collision is implemented
but unproven, since the spawn has open space behind it.
Consolidated from the qa-input-collision-fix-0.1.0 work, applied onto main so
only the changes main genuinely lacks are carried (main already merged the
walkable-demo/collision work independently).
- fix(input): populate the UE 5.8 FInputMappingContextMappingData
DefaultKeyMappings field in ue_create_input_assets.py (the runtime reads
GetMappings()->DefaultKeyMappings.Mappings; the script previously wrote only
the deprecated 'mappings' array, so the cooked game had 0 runtime mappings
and every key silently did nothing — in packaged AND PIE). Regenerated
IMC_Default.uasset. WASD/mouse/Space/R/Escape verified working.
- fix(build): drop editor-only APIs that break the game target build —
UStaticMesh::PostEditChange() (GigLineAssetTools) and AActor::GetActorLabel()
(character ground probe). GigLine and GigLineEditor now both compile clean.
- tools: OS-level uinput input harness (input_emulation.py + input_test.py) and
run_pie.sh for PIE isolation; document the PIE-vs-packaged input test in
Docs/build.md. Removed the temporary SIM/EI/screenshot diagnostics from the
character.
The reported fall-through was a misdiagnosis: the player never fell. The
imported Terrain_DEM had only a bounding-box simple collision proxy, so a
downward trace anywhere in the block hit the terrain at Z 819 (the mesh
bbox max) and the street sat under an invisible 8 m lid. Standing on that
box looked plausible, which is why it read as working.
- add UGigLineAssetTools (C++): force CTF_UseComplexAsSimple on a static
mesh. UE 5.8 dropped bUseComplexAsSimpleCollision and Python cannot set
the flag; the builder also saves the asset, since the flag lives there
and a map-only save silently reverts it.
- spawn (-13336, -1150, 600): inside the carved corridor (the cut is a
10.7 m half-width around the road centreline), lands on the road at 456.
- fix ResetToStart returning to the mid-air PlayerStart captured in
BeginPlay: StartLocation is now captured on the first grounded frame.
- HighResShot 1280x720 instead of "1280 720", which is a multiplier.
- add -qaselftest: scripted walk/reset/pause on a core ticker plus a
swept ground transect. Results: walk 746 cm/2 s with Z steady, reset
0 cm from spawn, pause/unpause 1/0, transect 84 samples 0 holes.
- rebase onto main, keeping the frontage materials and placement fixes.
Tools/ue_build_demo_map.py builds /Game/Hollywood/DemoMap: sun, sky, the hero
facade on the building line, six site meshes imported with collision, and a
player start on the north sidewalk. Tools/ue_import_site.py imports the site
FBXs; terrain, road and sidewalks use complex-as-simple so a simple hull cannot
ramp over the kerbs. Art/blender/site/export_site_fbx.py exports one FBX per
object so each can carry its own collision.
Reset (R) and pause (Escape) join the character and the input context: reset
restores the spawn transform and clears momentum, pause is a real game pause that
releases the cursor. DefaultInput.ini captures the mouse on launch.
Three placement defects found by measuring the imported actors rather than
trusting the plan: the spawn was on the wrong sidewalk because the FBX flip
inverts north, a mirror I added to the exporter double-corrected an already
correct sidewalk, and the street meshes only carry part of the north walk - the
rest is terrain.
AGigLineCharacter: 1.75 m capsule, 1.60 m eye camera, 4 m/s walk, mouse look
scaled in degrees per second (no double DeltaTime), jump. Loaded ahead of a
Blueprint so the demo is playable with no assets wired by hand.
Tools/ue_create_input_assets.py builds /Game/Input headlessly: five 1D actions
and an 11-mapping context. One action per direction instead of per-key modifiers,
because modifier objects do not survive the save path here: a mapping's modifier
array serialises None, and dimensioning a 2D move with per-key axis masks would
need exactly those modifiers. The cost is four action assets rather than two.
Also adds a fourth review camera at eye height and documents it; its approval is
pending.