Place the player, not the XR origin, at spawn, menu and save #16
Loading…
Reference in a new issue
No description provided.
Delete branch "hiccup444/da-game-hiccup:place-player-not-origin"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
Every placement wrote the marker straight into the
XROrigin3D. That covers the menu anchor, the spawn point and the save restore. With the default OpenXR reference space (Stage,xr/openxr/reference_space= 1) the origin is the centre of the player's play area, not the player. So the player landed offset from every marker by wherever they stood in their room, and faced whichever way they happened to face:None of this showed in flat mode or in the headless suites, because the FlatCamera sits fixed at (0, 1.6, 0) over the origin.
Changes
PlayerRig.place_player(target)moves the origin so that the head, projected to the floor, and its facing land on the target. This is the same idea asXRToolsPlayerBody.teleport(), worked from the camera because the body is off, and stale, while anchored.PlayerRig.player_floor_transform()returns the player's floor point and facing in world space._head_floor_local()takes the camera position flattened to the floor and the yaw of the camera's forward. When the player looks steeply up or down (forward.y beyond 0.75) the facing comes from the head's up vector, which is the rule XR Tools uses for the body. In flat mode it is identity, so desktop placement is unchanged.place_at(marker)andplace_at_transform(t)keep their names and signatures and now go throughplace_player. Every caller, including those on open branches, gets the new behaviour. Their doc comments now describe the new meaning.Game._readyplaces the player at the menu anchor before the first frame. At that point the headset has not reported a head pose, and the XRCamera3D still sits at its default pose over the origin, so that one placement could only put the play-area centre on the anchor. A placement made in XR without a tracked head pose is now kept, and the rig makes it again on the first frame the head is tracked (_redo_untracked_placement(), called from_process). Placements made with tracking live are not repeated. A placement made while the head pose is lost, for example with the headset off, is redone the same way when tracking comes back.Game._save_current_run()storesplayer_floor_transform()under a new key,player_transform.continue_game()readsplayer_transformand falls back to the oldrig_transformthrough the same path._place_pause_panel()fallback for looking straight up or down took its facing from the origin, which is the play area's forward. It now uses the player's facing.place_rigstill sets the origin directly, since its tool description, the snapshot and the e2e are all about the origin. The README no longer calls it the equivalent ofplace_at; the two agree only in flat mode.Old saves. The save format stays at 1. A
run.jsonfrom before this change holds the origin underrig_transform. It loads once with that origin read as the player's floor point. The player lands off by at most how far from the play-area centre they stood when saving, and faces the play area's forward instead of the way they faced. The next save writesplayer_transform.Tests
tests/rig_motion_check.gd, the clean-process rig unit check. The fixture's origin and both cameras are now in the tree. The existing velocity checks are unchanged. New checks run once per camera path: the XR camera with flat mode off, and the FlatCamera with flat mode on. The other camera sits at rest, so reading the wrong one fails.place_at(marker):player_floor_transform()returns the marker;place_atlands the origin on the marker. A stand-in head tracker registered withXRServerthen reports an off-centre, turned head. On the rig's next frame the head is over the marker, facing its -Z, and a later head pose does not move the origin again.XRPositionalTrackernamedheaddrives it the way OpenXR does. Checked on 4.6.3 with OpenXR off; on CI OpenXR fails to start, so there is no real tracker there either.tests/save_check.gd:player_floor_transform()after Continue.player_transformat the player's floor point, and norig_transform.rig_transformstill loads.tests/pause_check.gd: new check. The FlatCamera is turned inside the play space and pitched to -89 degrees, so its flattened forward falls under the fallback cutoff. The pause panel must open 1.3 m out along the player's facing, which differs from the origin's -Z here.--xr-mode off; CI covers Linux.body.enabledon the harness's Nil body.Corrections to the review
SaveGame.load_staterejects the mismatch, buthas_stateonly checks that the file exists. The menu would keep offering Continue, and pressing it would do nothing. That is why this PR reads the old key instead.Game._ready, before the headset has reported one. On its own the fix therefore left the first main menu after launch, the review's first symptom, placed as before. The boot redo above covers it.Left for in-headset checking
Overlap with open PRs
body_floor_transform()and arms anchoring after_processinplayer_rig.gd, and two calls at the top of_process. This PR's functions sit next toplace_at, its one_processline goes afterupdate_arms, and there are no shared names. The branch merges cleanly with #14 as it stands, and the merged tree passes the CI suites plus #14's anchor_check and skeleton_check.body_floor_transform()(body position, body yaw) andplayer_floor_transform()(head floor point, head yaw with the steep-look rule) are related helpers, worth unifying once both land._anchor_arms_to_floor()computes the camera's XZ and yaw itself. The steep-look shoulder yaw agreed on #14 is the same rule_head_floor_local()uses.game.gdandplayer_rig.gd, but its hunks do not touch the lines changed here. It merges cleanly, and the merged tree passes the CI suites plus its traversal_check and skeleton_check. Its traversal placements (place_at(_region.entry_point()),place_at(_level.traversal_anchor())and the abort back to spawn) pick up head placement automatically.tests/traversal_check.gdcomparesrig.originwith the anchor. In flat mode that equals the player's floor point, so it still passes, butplayer_floor_transform()is the better read there.Sibling PRs from the same review: #15, #17, #18 and #19. Their source changes merge cleanly with each other. Several of them add checks at the same spot in
tests/pause_check.gd(and two intests/save_check.gd), so whichever merges second may need a small rebase that keeps both blocks.View command line instructions
Manual merge helper
Use this merge commit message when completing the merge manually.
Checkout
From your project repository, check out a new branch and test the changes.Merge
Merge the changes and update on Forgejo.Warning: The "Autodetect manual merge" setting is not enabled for this repository, you will have to mark this pull request as manually merged afterwards.