3D transition Phase B: real item.gd/stand.gd #34

Merged
scruffydude merged 1 commit from task/33-phase-b-item-stand into main 2026-10-03 10:35:34 -04:00
Owner

Fresh 3D item.gd/stand.gd, porting the item_id/stand_id/group-membership/placed_changed-signal architecture from the deleted 2D version. item.gd gets a public try_snap() (vs. the 2D version's internal one) since the drop trigger now lives in player.gd's carry system; wired via a has_method() check to keep the carry system generic.

Test room gets a Stand added so the full pickup→drop→snap flow is provable.

Verified headlessly: direct try_snap() checks (miss/snap/mismatch all correct), and the full flow through the real carry system (raycast pickup, drop, snap) confirmed end to end.

Closes #33

Fresh 3D `item.gd`/`stand.gd`, porting the `item_id`/`stand_id`/group-membership/`placed_changed`-signal architecture from the deleted 2D version. `item.gd` gets a public `try_snap()` (vs. the 2D version's internal one) since the drop trigger now lives in `player.gd`'s carry system; wired via a `has_method()` check to keep the carry system generic. Test room gets a Stand added so the full pickup→drop→snap flow is provable. Verified headlessly: direct `try_snap()` checks (miss/snap/mismatch all correct), and the full flow through the real carry system (raycast pickup, drop, snap) confirmed end to end. Closes #33
Writes fresh 3D item.gd (RigidBody3D) and stand.gd (Node3D), porting
the exact item_id/stand_id/group-membership/placed_changed-signal
architecture already proven across the 2D version (now deleted) -
only the trigger mechanism changes.

item.gd adds a public try_snap() method instead of the 2D version's
internal _try_snap(): 3D distance check against "stands" group
members sharing item_id, snap+freeze+mark-placed within
snap_distance, otherwise just mark not-placed. Public because the
"an item was dropped" trigger now lives in player.gd's carry system
(Phase A), not inside item.gd itself the way the old mouse-drag
handler was.

player.gd::_drop_held_item() calls item.try_snap() via a
has_method() check rather than a hard type dependency - keeps the
carry system generic for any holdable object, not coupled to
item/stand matching specifically.

Test room (player_test.tscn) gets the existing TestBox tagged
item_id="box" and a new Stand node (stand_id="box", simple cylinder
pedestal visual) positioned 2m away, enough to prove the full
pickup -> carry -> drop -> snap flow in 3D.

Win-counting/area-controller work stays out of scope - that's
Phase C/D, once real rooms exist.

Verified headlessly:
- Direct try_snap() checks: far away does not snap; close to the
  matching stand snaps exactly and marks placed, freezing the body;
  a deliberately mismatched stand_id does not snap even at the same
  position.
- Full pickup/drop flow through the real player.gd carry system
  (same raycast+E-key pattern verified in Phase A): walking up,
  picking up via raycast, moving the held item onto the stand, and
  dropping correctly triggers try_snap() through the has_method()
  wiring and snaps exactly onto the stand.

Room layout/feel still can't be judged from this sandbox - this is
architecture validation, not a claim the test room looks or plays
well.

Closes #33

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
scruffydude/project-awry!34
No description provided.