GiftBox auto-reset, Balloon pop/respawn, Cake cut/reset, chair snap points. Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
5.5 KiB
Sprint 14 — Garden Party Spec
Goal
Make the GardenParty scene a fully playable sandbox room with three interactive objects (GiftBox auto-reset, Balloon pop/respawn, Cake cut/reset) and character snap-to-chair at the party table.
Scope
In scope:
gift_box.gd: addRESETTINGstate (auto-reset 3 s after opening)balloon.gd: new script — tap to pop, auto-respawn after 5 scake.gd: new script — tap to cut slice, auto-reset after 3 sGardenParty.tscn: replace GiftBox3 with Cake, add Cake node structure, add chair ColorRects under snap points, attach balloon.gd to existing Balloon nodes- Tests: extend
test_gift_box.gd, addtest_balloon.gd, addtest_cake.gd
Out of scope:
- New SFX keys (reuse
object_tapfor all three objects) - Navigation changes (HomeButtonToGarden and HomeButtonReturn already wired)
- Additional characters beyond Bunny1 already in Main.tscn
Object Mechanics
GiftBox — RESETTING state
New state added to the existing State enum:
CLOSED → OPENING → RESETTING → CLOSED
_on_lid_opened(): state →RESETTING, gift fades in (existing tween), inline 3 s tween interval runs in parallel →_start_close_lid()_start_close_lid(): lid tweens back (fade-in alpha 0→1, slide y back to 0) →_on_reset_complete()_on_reset_complete(): state →CLOSEDOPENstate removed —RESETTINGcovers "gift visible + waiting"- New internal methods:
_start_close_lid(),_on_reset_complete() - Constant:
RESET_DELAY: float = 3.0
Balloon
New file: scripts/objects/balloon.gd
New scene attachment: balloon.gd attached to existing Balloon1 / Balloon2 nodes in
GardenParty.tscn.
IDLE → POPPING → POPPED → RESPAWNING → IDLE
State transitions:
- Touch input on balloon while
IDLE→_start_pop() _start_pop():AudioManager.play_sfx("object_tap"), state →POPPING, scale tween toVector2.ZERO(0.15 s, EASE_IN, TRANS_BACK) →_on_pop_complete()_on_pop_complete(): state →POPPED, starts 5 s tween interval →_start_respawn()_start_respawn(): state →RESPAWNING, scale tween toVector2.ONE(0.3 s, EASE_OUT, TRANS_BACK) →_on_respawn_complete()_on_respawn_complete(): state →IDLE
Input: _input(event) — same touch-rect pattern as GiftBox, half-size 20 px (balloon is
small).
Constants: POP_DURATION, RESPAWN_DURATION, RESPAWN_DELAY.
Cake
New file: scripts/objects/cake.gd
New node structure in GardenParty.tscn (replaces GiftBox3 at x=820, y=464):
Cake (Node2D, cake.gd)
├── Base (ColorRect, ~80×40 px, warm brown)
└── Slice (ColorRect, ~30×40 px, slightly offset + rotated, lighter brown)
WHOLE → CUTTING → CUT → RESETTING → WHOLE
State transitions:
- Touch input on Cake while
WHOLE→_start_cutting() _start_cutting():AudioManager.play_sfx("object_tap"), state →CUTTING, tweenSlice.modulate.a1→0 (0.3 s, EASE_OUT) →_on_cut_complete()_on_cut_complete(): state →CUT, 3 s tween interval →_start_reset()_start_reset(): state →RESETTING, tweenSlice.modulate.a0→1 (0.3 s, EASE_IN) →_on_reset_complete()_on_reset_complete(): state →WHOLE
Input: touch rect BUTTON_HALF_WIDTH = 40, BUTTON_HALF_HEIGHT = 20.
Constants: CUT_DURATION, RESET_DELAY = 3.0, RESET_DURATION.
Scene Changes (GardenParty.tscn)
| Change | Detail |
|---|---|
Remove GiftBox3 |
Was at position Vector2(820, 464) |
Add Cake |
Node2D at Vector2(820, 464), cake.gd, child nodes Base + Slice |
Attach balloon.gd |
To existing Balloon1 and Balloon2 ColorRect nodes |
Add ChairLeft |
ColorRect ~60×20 px, brown, under SnapTableLeft (x=530, y=480) |
Add ChairRight |
ColorRect ~60×20 px, brown, under SnapTableRight (x=750, y=480) |
Navigation and snap-point logic unchanged.
Tests
test_gift_box.gd (extend existing)
| Test | Assertion |
|---|---|
test_state_becomes_resetting_after_lid_opened |
Call _on_lid_opened() → state == State.RESETTING |
test_state_becomes_closed_after_reset_complete |
Call _on_reset_complete() → state == State.CLOSED |
test_balloon.gd (new, extends GutTest)
| Test | Assertion |
|---|---|
test_initial_state_is_idle |
state == State.IDLE |
test_start_pop_sets_popping |
Call _start_pop() → state == State.POPPING |
test_on_pop_complete_sets_popped |
Call _on_pop_complete() → state == State.POPPED |
test_on_respawn_complete_sets_idle |
Call _on_respawn_complete() → state == State.IDLE |
test_cake.gd (new, extends GutTest)
| Test | Assertion |
|---|---|
test_initial_state_is_whole |
state == State.WHOLE |
test_start_cutting_sets_cutting |
Call _start_cutting() → state == State.CUTTING |
test_on_cut_complete_sets_cut |
Call _on_cut_complete() → state == State.CUT |
test_on_reset_complete_sets_whole |
Call _on_reset_complete() → state == State.WHOLE |
Architecture Notes
- All three objects follow the same state-machine pattern as existing objects (
cradle.gd,gift_box.gd, etc.) — no new abstractions. - Tween-based animations are not unit-tested (visual only). State transitions triggered by
tween.finishedcallbacks are tested by calling the callbacks directly. AudioServer.get_driver_name() == "Dummy"guard is already inAudioManager.play_sfx()— no additional guard needed in new scripts.balloon.gdscales the Node2D itself (no child sprite node needed at placeholder stage).