fix: bind callbacks before passing to tween_callback, tighten backpack hitbox
- Godot 4's CallbackTweener doesn't have .bind() — move .bind() call inside tween_callback() for 3 callback sites - Shrink InventoryBackpack Control to 60x60 (offset_right -70) so click area matches the visible BackpackIcon square
This commit is contained in:
@@ -0,0 +1,89 @@
|
|||||||
|
---
|
||||||
|
## Goal
|
||||||
|
- Implement inventory and backpack system in Godot 4.6 point-and-click adventure game per plan at `docs/plans/2026-04-26-001-feat-inventory-backpack-system-plan.md`
|
||||||
|
|
||||||
|
## Constraints & Preferences
|
||||||
|
- Interaction handlers are signals emitted by items, not embedded dictionary data
|
||||||
|
- No multi-step transition queues — FSM transitions interrupt in-flight animations immediately
|
||||||
|
- No sound required
|
||||||
|
- Item cursor as 5th `ActionState` slot (`ITEM`, value 4); right-click cycles WALK→LOOK→TOUCH→TALK→ITEM→WALK
|
||||||
|
- Use colored `ColorRect` boxes as placeholders for all item/backpack visuals
|
||||||
|
- Follow PRD §13 recommended Godot architecture approaches
|
||||||
|
- PRD is engine-agnostic but implementation targets Godot 4.6
|
||||||
|
|
||||||
|
## Progress
|
||||||
|
### Done
|
||||||
|
- Read and analyzed `inventory-prd.md` (791 lines)
|
||||||
|
- Researched existing codebase patterns
|
||||||
|
- Wrote complete plan to `docs/plans/2026-04-26-001-feat-inventory-backpack-system-plan.md` with 6 implementation units
|
||||||
|
- Applied 5 user edits to plan: signal-based interactions, no transition queues, no sound, ActionState ITEM slot, colored boxes
|
||||||
|
- Created directory structure: `inventory/inventory_backpack/`, `inventory/inventory_overlay/`
|
||||||
|
- Generated 12 UIDs for new files
|
||||||
|
- U1 complete: `inventory/ItemDefinition.gd` written (Resource with id, name, combination_category)
|
||||||
|
- U2 complete: `inventory/InventoryManager.gd` written (AutoLoad singleton with signals, queries, mutations, combination emission, selection)
|
||||||
|
- U3 complete: `inventory/inventory_backpack/InventoryBackpack.gd` + `.tscn` (FSM with IDLE/OPEN/SELECTED/ACQUIRE/REMOVE, Tween animations, guard checks)
|
||||||
|
- U4 complete: `inventory/inventory_overlay/InventoryOverlay.gd` + `.tscn` + `InventorySlot.gd` + `.tscn` (full-screen overlay, grid, drag-and-drop, hover, combination)
|
||||||
|
- U5 complete: Modified `ActionState.gd` (ITEM=4), `MainGame.gd` (5-action cycling), `Scene.gd` (overlay guard, ITEM input), `GameScript.gd` (GiveItem step)
|
||||||
|
- U6 complete: Modified `Scene.gd` (give_item/remove_item/strip_items helpers), `SetPiece_.gd` (ITEM action handling)
|
||||||
|
- InventoryManager registered as AutoLoad in `project.godot`
|
||||||
|
- All commits pushed to remote
|
||||||
|
|
||||||
|
### In Progress
|
||||||
|
- (none)
|
||||||
|
|
||||||
|
### Blocked
|
||||||
|
- (none)
|
||||||
|
|
||||||
|
## Key Decisions
|
||||||
|
- **Signal-based interactions**: Items emit signals; `InventoryManager.attempt_combine` emits `combination_attempted`; scene scripts handle results
|
||||||
|
- **No transition queues**: FSM transitions kill in-flight tweens and start fresh; `is_busy` flag prevents concurrency but does not queue
|
||||||
|
- **ActionState ITEM slot**: `ITEM = 4` added to enum; right-click cycles all 5 states; selected item stored in `InventoryManager.selected_item`
|
||||||
|
- **Colored boxes**: `ColorRect` placeholders replace all `Sprite2D` references
|
||||||
|
- **Hand-rolled FSM (PRD Option A)** over AnimationTree: conditional branching maps better to code
|
||||||
|
- **AutoLoad singleton** for InventoryManager following ActionState pattern
|
||||||
|
- **Raw `_gui_input()`** for overlay drag-and-drop instead of Godot's built-in system
|
||||||
|
- **Combined input priority defense**: `MOUSE_FILTER_STOP` background + `_unhandled_input()` gate + explicit `overlay_active` guard flag
|
||||||
|
- **ItemDefinition as Resource** for serializable `.tres` item data
|
||||||
|
- **GridContainer** for static item grid layout
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
- Test all units in Godot editor
|
||||||
|
- Register sample item definitions (`.tres` files)
|
||||||
|
- Wire up signal connections in `Game.tscn` (backpack ↔ overlay ↔ manager)
|
||||||
|
- Create example room script demonstrating `give_item()` usage
|
||||||
|
- Replace colored box placeholders with actual item sprites
|
||||||
|
|
||||||
|
## Critical Context
|
||||||
|
- Godot 4.6 project, 1920x1080 viewport
|
||||||
|
- Branch: `sugary-panda` (worktree), default branch: `master`
|
||||||
|
- Existing autoloads: `ActionState`, `CameraTransition`, `InventoryManager` (new)
|
||||||
|
- Root scene `Game.tscn` uses `SubViewport` for game world, `CanvasLayer` for overlays
|
||||||
|
- `ActionState.gd` enum: `WALK=0, LOOK=1, TOUCH=2, TALK=3, ITEM=4`
|
||||||
|
- `MainGame.gd` has `cursors` array with 4 cursor textures — 5th slot needed for ITEM (currently skips if no item selected)
|
||||||
|
- All code committed and pushed to `origin/sugary-panda`
|
||||||
|
|
||||||
|
## Relevant Files
|
||||||
|
- `inventory-prd.md`: Origin requirements document (791 lines, 14 acceptance criteria)
|
||||||
|
- `docs/plans/2026-04-26-001-feat-inventory-backpack-system-plan.md`: Implementation plan (6 units, edited with 5 user changes)
|
||||||
|
- `inventory/ItemDefinition.gd`: Custom Resource class (DONE)
|
||||||
|
- `inventory/ItemDefinition.gd.uid`: UID file for ItemDefinition (DONE)
|
||||||
|
- `inventory/InventoryManager.gd`: AutoLoad singleton with signals, queries, mutations (DONE)
|
||||||
|
- `inventory/InventoryManager.gd.uid`: UID file for InventoryManager (DONE)
|
||||||
|
- `inventory/inventory_backpack/InventoryBackpack.gd`: FSM script (DONE)
|
||||||
|
- `inventory/inventory_backpack/InventoryBackpack.gd.uid`: UID file (DONE)
|
||||||
|
- `inventory/inventory_backpack/InventoryBackpack.tscn`: HUD backpack scene (DONE)
|
||||||
|
- `inventory/inventory_backpack/InventoryBackpack.tscn.uid`: UID file (DONE)
|
||||||
|
- `inventory/inventory_overlay/InventoryOverlay.gd`: Overlay interaction script (DONE)
|
||||||
|
- `inventory/inventory_overlay/InventoryOverlay.gd.uid`: UID file (DONE)
|
||||||
|
- `inventory/inventory_overlay/InventoryOverlay.tscn`: Full-screen overlay scene (DONE)
|
||||||
|
- `inventory/inventory_overlay/InventoryOverlay.tscn.uid`: UID file (DONE)
|
||||||
|
- `inventory/inventory_overlay/InventorySlot.gd`: Slot behavior script (DONE)
|
||||||
|
- `inventory/inventory_overlay/InventorySlot.gd.uid`: UID file (DONE)
|
||||||
|
- `inventory/inventory_overlay/InventorySlot.tscn`: Single item slot scene (DONE)
|
||||||
|
- `inventory/inventory_overlay/InventorySlot.tscn.uid`: UID file (DONE)
|
||||||
|
- `MainGame.gd`: Modified for 5-action cursor cycling with ITEM
|
||||||
|
- `Scene.gd`: Modified for overlay guard, ITEM action, helper methods
|
||||||
|
- `ActionState.gd`: Modified to add ITEM action
|
||||||
|
- `GameScript.gd`: Modified to add GiveItem/GiveItemDeferred steps
|
||||||
|
- `SetPiece_.gd`: Modified to handle ITEM action
|
||||||
|
- `project.godot`: InventoryManager AutoLoad registered
|
||||||
@@ -72,7 +72,7 @@ func _transition_to_idle() -> void:
|
|||||||
_animating = true
|
_animating = true
|
||||||
tween.tween_property(backpack_icon, "rotation", 0.0, 0.35).set_trans(Tween.TRANS_LINEAR)
|
tween.tween_property(backpack_icon, "rotation", 0.0, 0.35).set_trans(Tween.TRANS_LINEAR)
|
||||||
tween.tween_property(backpack_icon, "position", backpack_icon.position, 0.35).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN)
|
tween.tween_property(backpack_icon, "position", backpack_icon.position, 0.35).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN)
|
||||||
tween.tween_callback(_on_transition_complete).bind(State.IDLE)
|
tween.tween_callback(_on_transition_complete.bind(State.IDLE))
|
||||||
|
|
||||||
func _transition_to_open() -> void:
|
func _transition_to_open() -> void:
|
||||||
var can_open = _check_guards()
|
var can_open = _check_guards()
|
||||||
@@ -88,7 +88,7 @@ func _transition_to_open() -> void:
|
|||||||
_animating = true
|
_animating = true
|
||||||
tween.tween_property(backpack_icon, "rotation", PI / 4, 0.35).set_trans(Tween.TRANS_LINEAR)
|
tween.tween_property(backpack_icon, "rotation", PI / 4, 0.35).set_trans(Tween.TRANS_LINEAR)
|
||||||
tween.tween_property(backpack_icon, "position", Vector2(backpack_icon.position.x + 20, backpack_icon.position.y + 20), 0.35).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN)
|
tween.tween_property(backpack_icon, "position", Vector2(backpack_icon.position.x + 20, backpack_icon.position.y + 20), 0.35).set_trans(Tween.TRANS_SINE).set_ease(Tween.EASE_IN)
|
||||||
tween.tween_callback(_on_transition_complete).bind(State.OPEN)
|
tween.tween_callback(_on_transition_complete.bind(State.OPEN))
|
||||||
tween.tween_callback(overlay_show_requested.emit)
|
tween.tween_callback(overlay_show_requested.emit)
|
||||||
|
|
||||||
func _transition_to_selected() -> void:
|
func _transition_to_selected() -> void:
|
||||||
@@ -105,7 +105,7 @@ func _transition_to_selected() -> void:
|
|||||||
floating_item.visible = true
|
floating_item.visible = true
|
||||||
floating_item.modulate = Color(1, 1, 1, 0)
|
floating_item.modulate = Color(1, 1, 1, 0)
|
||||||
tween.tween_property(floating_item, "modulate", Color(1, 1, 1, 1), 0.5).set_trans(Tween.TRANS_LINEAR)
|
tween.tween_property(floating_item, "modulate", Color(1, 1, 1, 1), 0.5).set_trans(Tween.TRANS_LINEAR)
|
||||||
tween.tween_callback(_on_transition_complete).bind(State.SELECTED)
|
tween.tween_callback(_on_transition_complete.bind(State.SELECTED))
|
||||||
|
|
||||||
func _transition_to_acquire() -> void:
|
func _transition_to_acquire() -> void:
|
||||||
if _state == State.ACQUIRE or _state == State.REMOVE:
|
if _state == State.ACQUIRE or _state == State.REMOVE:
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ layout_mode = 3
|
|||||||
anchors_preset = 2
|
anchors_preset = 2
|
||||||
anchor_right = 1.0
|
anchor_right = 1.0
|
||||||
offset_top = 10.0
|
offset_top = 10.0
|
||||||
offset_right = -10.0
|
offset_right = -70.0
|
||||||
offset_bottom = 70.0
|
offset_bottom = 70.0
|
||||||
script = ExtResource("1")
|
script = ExtResource("1")
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user