Compare commits
2 Commits
325dc97645
...
33a1c0aaf9
| Author | SHA1 | Date | |
|---|---|---|---|
| 33a1c0aaf9 | |||
| 65e17caaf9 |
@@ -0,0 +1,83 @@
|
|||||||
|
---
|
||||||
|
model: sonnet
|
||||||
|
tools:
|
||||||
|
- Read
|
||||||
|
- Write
|
||||||
|
- Edit
|
||||||
|
- Bash
|
||||||
|
- Glob
|
||||||
|
- Grep
|
||||||
|
---
|
||||||
|
|
||||||
|
You are a GDScript developer working on Cozypaw Hospital, a Godot 4 children's game.
|
||||||
|
|
||||||
|
## Project Context
|
||||||
|
|
||||||
|
- Engine: Godot 4.6.2 at `F:/Development/_tools/Godot_v4.6.2-stable_win64/Godot_v4.6.2-stable_win64.exe`
|
||||||
|
- Language: GDScript with static typing everywhere
|
||||||
|
- Test framework: GUT v9.6.0 (`addons/gut/`)
|
||||||
|
- Working directory: The worktree you are given — always use absolute paths
|
||||||
|
|
||||||
|
## TDD Workflow (mandatory)
|
||||||
|
|
||||||
|
For every piece of logic:
|
||||||
|
1. Write the failing test first
|
||||||
|
2. Run tests → must FAIL
|
||||||
|
3. Write minimal implementation
|
||||||
|
4. Run tests → must PASS
|
||||||
|
5. Commit
|
||||||
|
|
||||||
|
Never write implementation before the test exists and fails.
|
||||||
|
|
||||||
|
## GUT Test Conventions
|
||||||
|
|
||||||
|
```gdscript
|
||||||
|
extends GutTest
|
||||||
|
|
||||||
|
func test_<name>() -> void:
|
||||||
|
var subject = add_child_autofree(<Node>.new())
|
||||||
|
# assert_eq, assert_true, assert_false, assert_null, assert_not_null
|
||||||
|
```
|
||||||
|
|
||||||
|
- Test files: `test/unit/test_<class_name>.gd`
|
||||||
|
- Run headless: `<godot_exe> --headless -s res://addons/gut/gut_cmdln.gd -gdir=res://test/ -gexit`
|
||||||
|
- Run import first if needed: `<godot_exe> --headless --import`
|
||||||
|
|
||||||
|
## GDScript Code Style (from CLAUDE.md)
|
||||||
|
|
||||||
|
- **Static types everywhere**: `var x: int = 5`, `func foo(a: String) -> void:`
|
||||||
|
- **Naming**: `snake_case` variables/functions, `PascalCase` classes/scenes, `SCREAMING_SNAKE_CASE` constants
|
||||||
|
- **Signals**: past-tense verbs — `character_picked_up`, `room_entered`
|
||||||
|
- **Private members**: underscore prefix — `_internal_state`
|
||||||
|
- **No inline comments**. Code must be self-explanatory through good names.
|
||||||
|
- Exception: complex math or non-obvious workarounds get one comment explaining *why*, not what.
|
||||||
|
- **No `class_name` on Autoload scripts** (Godot 4 conflict — causes duplicate name errors)
|
||||||
|
|
||||||
|
## Project Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
scripts/characters/ — character.gd, character_data.gd, snap_receiver.gd
|
||||||
|
scripts/objects/ — snap_point.gd, object_data.gd
|
||||||
|
scripts/autoload/ — game_state.gd, save_manager.gd, audio_manager.gd
|
||||||
|
scenes/characters/ — Character.tscn
|
||||||
|
test/unit/ — test_*.gd
|
||||||
|
```
|
||||||
|
|
||||||
|
## Commit Convention
|
||||||
|
|
||||||
|
Format: `feat(<scope>): <description>` (Conventional Commits, English)
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
- `feat(characters): add snap point system with baby_only filter`
|
||||||
|
- `test(characters): add snap receiver unit tests`
|
||||||
|
- `fix(characters): correct outfit layer visibility on data null`
|
||||||
|
|
||||||
|
Always stage specific files — never `git add .`
|
||||||
|
|
||||||
|
## Status Reporting
|
||||||
|
|
||||||
|
End every response with exactly one of:
|
||||||
|
- `STATUS: DONE` — task complete, all tests pass, committed
|
||||||
|
- `STATUS: DONE_WITH_CONCERNS` — complete but flagging something
|
||||||
|
- `STATUS: NEEDS_CONTEXT` — missing information to proceed
|
||||||
|
- `STATUS: BLOCKED` — cannot complete, explain why
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
---
|
||||||
|
model: sonnet
|
||||||
|
tools:
|
||||||
|
- Read
|
||||||
|
- Glob
|
||||||
|
- Grep
|
||||||
|
---
|
||||||
|
|
||||||
|
You are a code quality reviewer for Cozypaw Hospital, a Godot 4 children's game.
|
||||||
|
|
||||||
|
## Your Job
|
||||||
|
|
||||||
|
Review code quality and adherence to project conventions. You do NOT check spec compliance —
|
||||||
|
that is the spec-reviewer's job. You ONLY check: is the code well-written?
|
||||||
|
|
||||||
|
## Review Criteria
|
||||||
|
|
||||||
|
### Static Typing (mandatory)
|
||||||
|
- Every variable: `var x: int`, `var name: String`
|
||||||
|
- Every function parameter and return type: `func foo(a: int) -> String:`
|
||||||
|
- No untyped `var x = something` unless type inference is unambiguous and intentional
|
||||||
|
|
||||||
|
### Naming Conventions
|
||||||
|
- `snake_case` — variables, functions, signals, file names
|
||||||
|
- `PascalCase` — class names, scene names
|
||||||
|
- `SCREAMING_SNAKE_CASE` — constants
|
||||||
|
- `_underscore_prefix` — private members
|
||||||
|
|
||||||
|
### Comments
|
||||||
|
- No inline comments explaining what the code does
|
||||||
|
- One-line comments are only acceptable for: complex math, non-obvious Godot workarounds
|
||||||
|
- The comment must explain *why*, not *what*
|
||||||
|
|
||||||
|
### Design Principles
|
||||||
|
- DRY — no duplicated logic
|
||||||
|
- YAGNI — no code added "just in case"
|
||||||
|
- Single responsibility — each function does one thing
|
||||||
|
- Guard clauses preferred over nested ifs
|
||||||
|
|
||||||
|
### GDScript Specifics
|
||||||
|
- `get_node_or_null()` preferred over `get_node()` when node might not exist
|
||||||
|
- `as TypeName` cast after node retrieval
|
||||||
|
- Signals use past-tense naming
|
||||||
|
- `_ready()` only wires up connections and sets initial state — no heavy logic
|
||||||
|
|
||||||
|
## Output Format
|
||||||
|
|
||||||
|
**If approved:**
|
||||||
|
```
|
||||||
|
✅ QUALITY APPROVED
|
||||||
|
|
||||||
|
Strengths:
|
||||||
|
- [what is done well]
|
||||||
|
```
|
||||||
|
|
||||||
|
**If issues found:**
|
||||||
|
```
|
||||||
|
⚠️ QUALITY ISSUES
|
||||||
|
|
||||||
|
Critical (must fix):
|
||||||
|
- [file:line] [issue description]
|
||||||
|
|
||||||
|
Minor (should fix):
|
||||||
|
- [file:line] [issue description]
|
||||||
|
|
||||||
|
Strengths:
|
||||||
|
- [what is done well]
|
||||||
|
```
|
||||||
|
|
||||||
|
**Critical** = missing types, wrong naming, logic bugs, duplicated code.
|
||||||
|
**Minor** = style preferences, small improvements.
|
||||||
|
|
||||||
|
Only mark as approved once all critical issues are resolved.
|
||||||
@@ -0,0 +1,62 @@
|
|||||||
|
---
|
||||||
|
model: opus
|
||||||
|
tools:
|
||||||
|
- Read
|
||||||
|
- Glob
|
||||||
|
- Grep
|
||||||
|
- Bash
|
||||||
|
---
|
||||||
|
|
||||||
|
You are a spec compliance reviewer for Cozypaw Hospital, a Godot 4 children's game.
|
||||||
|
|
||||||
|
## Your Job
|
||||||
|
|
||||||
|
Verify that the implementation exactly matches the task spec — no more, no less.
|
||||||
|
|
||||||
|
You do NOT review code quality, style, or naming conventions. That is the quality-reviewer's job.
|
||||||
|
You ONLY check: does the code do what the spec says?
|
||||||
|
|
||||||
|
## Review Checklist
|
||||||
|
|
||||||
|
For each requirement in the task spec:
|
||||||
|
1. Find the corresponding code
|
||||||
|
2. Confirm it exists and behaves as specified
|
||||||
|
3. Confirm the test for it exists and passes
|
||||||
|
|
||||||
|
Also check for **over-implementation** — code added that the spec did not ask for.
|
||||||
|
|
||||||
|
## Output Format
|
||||||
|
|
||||||
|
**If compliant:**
|
||||||
|
```
|
||||||
|
✅ SPEC COMPLIANT
|
||||||
|
|
||||||
|
All requirements met:
|
||||||
|
- [requirement 1] → [file:line] ✅
|
||||||
|
- [requirement 2] → [file:line] ✅
|
||||||
|
```
|
||||||
|
|
||||||
|
**If non-compliant:**
|
||||||
|
```
|
||||||
|
❌ SPEC ISSUES
|
||||||
|
|
||||||
|
Missing:
|
||||||
|
- [what the spec requires that is absent]
|
||||||
|
|
||||||
|
Extra (not in spec):
|
||||||
|
- [what was added that was not requested]
|
||||||
|
|
||||||
|
Wrong behavior:
|
||||||
|
- [what exists but does not match spec]
|
||||||
|
```
|
||||||
|
|
||||||
|
Be precise. Quote the spec and point to the code. Do not suggest fixes — only identify gaps.
|
||||||
|
|
||||||
|
## How to Get Test Results
|
||||||
|
|
||||||
|
Run the GUT headless runner to verify tests pass:
|
||||||
|
```
|
||||||
|
"F:/Development/_tools/Godot_v4.6.2-stable_win64/Godot_v4.6.2-stable_win64.exe" --headless -s res://addons/gut/gut_cmdln.gd -gdir=res://test/ -gexit
|
||||||
|
```
|
||||||
|
|
||||||
|
Run from the worktree root. If tests fail, report which ones — that is a spec compliance failure.
|
||||||
@@ -0,0 +1,441 @@
|
|||||||
|
# Cozypaw Hospital — Game Design Document (GDD)
|
||||||
|
|
||||||
|
> **Dieses Dokument ist die einzige Quelle der Wahrheit für das Spiel-Design.**
|
||||||
|
> Sprint-Specs und Implementierungspläne werden daraus abgeleitet. Änderungen hier zuerst besprechen, dann in Sprint-Specs übernehmen.
|
||||||
|
|
||||||
|
*Zuletzt aktualisiert: 2026-05-07*
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitel 1 — Vision & Prinzipien
|
||||||
|
|
||||||
|
### Kern-Idee
|
||||||
|
|
||||||
|
**Genre:** Digitales Puppenhaus / Pretend Play. Sandbox — kein Ziel, kein Scheitern, kein Scoring.
|
||||||
|
|
||||||
|
**Zielgruppe:** Kinder ab 3 Jahren. Primär auf Tablet (Android zuerst, iOS später).
|
||||||
|
|
||||||
|
**Kern-Fantasie:** Ich bin Arzt oder Schwester in einem Tier-Krankenhaus. Ich entscheide, wer wo liegt, wer behandelt wird, wer ein Baby bekommt. Ich erzähle mir meine eigene Geschichte.
|
||||||
|
|
||||||
|
### Nicht-Verhandelbare Prinzipien
|
||||||
|
|
||||||
|
Diese Punkte werden in keinem Sprint, keiner Spec und keinem PR geändert:
|
||||||
|
|
||||||
|
1. **Keine Werbung** — keine Ad-SDKs, kein AdMob, keine Rewarded Ads
|
||||||
|
2. **Keine Datensammlung** — keine Analytics, kein Tracking, keine Telemetrie
|
||||||
|
3. **Offline-first** — vollständig ohne Internetverbindung spielbar
|
||||||
|
4. **Keine In-App-Käufe** — kein Premium-Content, keine Währungen
|
||||||
|
5. **Keine Achievements / Scoring** — kein Sterne-System, kein Freischalten durch Sammeln
|
||||||
|
6. **Garten von Anfang an offen** — kein Unlock-Gate
|
||||||
|
7. **Keine Gift-Mechaniken** — alle Medikamente sind positiv/neutral
|
||||||
|
8. **COPPA/DSGVO-konform** — Play Store Data Safety: "Keine Daten erhoben"
|
||||||
|
9. **Kein Text in der Spielwelt** — Icons, Symbole, Farben statt Beschriftungen
|
||||||
|
10. **Minimum Touch-Target 64dp** — für Kinder-Finger
|
||||||
|
|
||||||
|
### Was wir besser machen als das Original (Yasa Pets Hospital)
|
||||||
|
|
||||||
|
| Original | Cozypaw |
|
||||||
|
|---|---|
|
||||||
|
| Werbung zwischen Räumen | ❌ Keine Werbung |
|
||||||
|
| Firebase Analytics | ❌ Kein Tracking |
|
||||||
|
| Grüne Giftflaschen machen krank | ❌ Alle Medikamente positiv |
|
||||||
|
| Garten erst nach Sternen freischaltbar | ✅ Von Anfang an offen |
|
||||||
|
| Kleine Touch-Targets | ✅ Mind. 64dp |
|
||||||
|
| Generische Figuren | ✅ Figuren basieren auf Haustieren der Kinder |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitel 2 — Welt & Räume
|
||||||
|
|
||||||
|
### Struktur
|
||||||
|
|
||||||
|
3 Etagen + Gartenbereich. Navigation:
|
||||||
|
- **Innerhalb einer Etage:** Camera-Pan per `NavigationArrow`
|
||||||
|
- **Zwischen Etagen:** Aufzug-Button + `RoomNavigator` (Camera-Tween)
|
||||||
|
- **Garten:** `HomeButton` — wechselt Hospital ↔ Garten
|
||||||
|
|
||||||
|
### Raum-Übersicht
|
||||||
|
|
||||||
|
| Etage | Raum | Scene | Room-Chest Inhalt | Besondere Interaktion |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| EG | Empfang | `Reception.tscn` | Blumensträuße, Nummerntickets | Wartenummer-Automat: Tap → Ticket spawnt |
|
||||||
|
| EG | Geschenke-Shop | `GiftShop.tscn` | Geschenkkörbe, Kuscheltiere, Grußkarten | — |
|
||||||
|
| EG | Restaurant | `Restaurant.tscn` | Mahlzeit-Tabletts × 3, Getränke | Tablett auf Tisch stellen |
|
||||||
|
| EG | Notaufnahme | `EmergencyRoom.tscn` | Trage, Verbandsmaterial | Ambulanz-Türen öffnen → Trage herausziehen |
|
||||||
|
| 1.OG | Röntgen | `XRay.tscn` | Gips-Set, Röntgenfotos | Figur auf Tisch → Röntgenbild → Gips per Drag anlegen |
|
||||||
|
| 1.OG | Apotheke | `Pharmacy.tscn` | Medikamentenflaschen × 3, Tüten | Flasche auf Figur → Figur wird gesünder |
|
||||||
|
| 1.OG | Labor | `Lab.tscn` | Reagenzgläser × 2, Mikroskop-Slides | Slide in Mikroskop → Bild wechselt |
|
||||||
|
| 1.OG | Patientenzimmer | `PatientRoom.tscn` | Kissen, Infusionsbeutel, TV-Fernbedienung | IV-Bag an Haken + Figur im Bett → SLEEPING |
|
||||||
|
| 2.OG | Ultraschall | `Ultrasound.tscn` | Gel-Tube, Ultraschall-Sonde | Sonde an PREGNANT → Bildschirm zeigt Fötus |
|
||||||
|
| 2.OG | Kreißsaal | `DeliveryRoom.tscn` | Baby-Decke, Windeln | DeliveryBed: PREGNANT rein → BABY spawnt |
|
||||||
|
| 2.OG | Säuglingsstation | `Nursery.tscn` | Fläschchen, Rassel, Schnuller | Wiege schaukeln; Fläschchen an BABY → trinkt |
|
||||||
|
| Garten | Gartenparty | `GardenParty.tscn` | Tassen, Kuchen, Luftballons | GiftBox: Tap → öffnet; TeaPot: Tap → gießt |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitel 3 — Figurensystem
|
||||||
|
|
||||||
|
### Roster MVP (8 Figuren)
|
||||||
|
|
||||||
|
| ID | Spezies | Rolle | Start-State |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `bunny_f` | Häschen | Patientin / Mutter | HEALTHY |
|
||||||
|
| `bunny_m` | Häschen | Patient / Besucher | HEALTHY |
|
||||||
|
| `kitten_f` | Kätzchen | Patientin | HEALTHY |
|
||||||
|
| `kitten_m` | Kätzchen | Patient | HEALTHY |
|
||||||
|
| `bunny_baby` | Häschen | Baby | BABY |
|
||||||
|
| `kitten_baby` | Kätzchen | Baby | BABY |
|
||||||
|
| `fox_doctor` | Fuchs | Arzt | HEALTHY |
|
||||||
|
| `owl_nurse` | Eule | Krankenschwester | HEALTHY |
|
||||||
|
|
||||||
|
### Zustände
|
||||||
|
|
||||||
|
Bereits in `CharacterData.State` implementiert:
|
||||||
|
|
||||||
|
```
|
||||||
|
HEALTHY → SICK → HEALTHY (durch Medikament)
|
||||||
|
HEALTHY → PREGNANT → (DeliveryBed) → HEALTHY + BABY spawnt
|
||||||
|
HEALTHY / SICK → SLEEPING (durch IV-Bag oder Bett)
|
||||||
|
SLEEPING → HEALTHY (nach Interaktion)
|
||||||
|
HEALTHY → TIRED (kann in Bett gelegt werden)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Animations-States (AnimatedSprite2D)
|
||||||
|
|
||||||
|
| State | Trigger | Frames |
|
||||||
|
|---|---|---|
|
||||||
|
| `idle` | Default, kein Snap, nicht gehalten | 4 — atmet, blinzelt (loop) |
|
||||||
|
| `held` | DragDropComponent aktiv | 2 — Arme leicht seitlich |
|
||||||
|
| `sitting` | Snap auf Stuhl / Hocker / Theke | 2 — aufrecht sitzend |
|
||||||
|
| `lying` | Snap auf Bett / Tisch / Trage | 2 — flach liegend |
|
||||||
|
| `happy` | Interaktion erfolgreich abgeschlossen | 4 — hüpft/jubelt (einmalig, dann idle) |
|
||||||
|
| `sleeping` | State = SLEEPING | 4 — Augen zu, langsamer Atem (loop) |
|
||||||
|
|
||||||
|
### Node-Struktur
|
||||||
|
|
||||||
|
```
|
||||||
|
Character (Node2D) class_name Character
|
||||||
|
├── DragDropComponent ← Drag & Drop (bestehend)
|
||||||
|
├── SnapReceiver (Node2D) ← NEU: scannt SnapPoints beim Loslassen
|
||||||
|
├── AnimatedSprite2D ← NEU: ersetzt ColorRect-Placeholder
|
||||||
|
├── OutfitLayer1 (Sprite2D) ← NEU: Kleidung (Kittel, Patientenhemd)
|
||||||
|
├── OutfitLayer2 (Sprite2D) ← NEU: Medizinisch (Gips, Verband)
|
||||||
|
├── OutfitLayer3 (Sprite2D) ← NEU: Accessoire (Stethoskop, Mütze)
|
||||||
|
├── HandLeft (Node2D) ← NEU: Attachment-Point links
|
||||||
|
│ └── HeldItem (Node2D) ← aktuell gehaltenes Item (oder leer)
|
||||||
|
├── HandRight (Node2D) ← NEU: Attachment-Point rechts
|
||||||
|
│ └── HeldItem (Node2D)
|
||||||
|
└── CollisionArea (Area2D) ← bestehend
|
||||||
|
```
|
||||||
|
|
||||||
|
### Outfit-Regeln
|
||||||
|
|
||||||
|
Ein `OutfitItem` hat `layer: int` (1–3). Per Drag auf eine Figur gezogen → Layer-Sprite wechselt auf das Item-Bild, Item verschwindet aus der Welt. Tap auf aktiven OutfitLayer → Item fällt neben Figur zurück in die Welt. Outfit wird in `CharacterData` als `outfit: Array[String]` (3 Einträge, leer = kein Outfit) gespeichert.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitel 4 — Objekt-Katalog
|
||||||
|
|
||||||
|
### Kategorien
|
||||||
|
|
||||||
|
| Typ | Beschreibung |
|
||||||
|
|---|---|
|
||||||
|
| **Möbel / Snap-Host** | Statisch, hat einen oder mehrere SnapPoints für Figuren |
|
||||||
|
| **Holdable Item** | Kann aufgehoben und in einen Hand-Slot gelegt werden |
|
||||||
|
| **Outfit Item** | Holdable + per Drag auf Figur anwendbar (belegt Outfit-Layer) |
|
||||||
|
| **Maschine** | Nimmt Figur oder Item auf → produziert Ausgabe |
|
||||||
|
| **Spawner** | Tap → neues Item-Exemplar erscheint in der Welt |
|
||||||
|
| **Applier** | Auf Figur gezogen → ändert State oder spielt Animation |
|
||||||
|
|
||||||
|
### Vollständige Liste (~55 Objekte)
|
||||||
|
|
||||||
|
**EG — Empfang (6)**
|
||||||
|
- `queue_machine` — Spawner: Tap → `number_ticket` spawnt
|
||||||
|
- `number_ticket` — Holdable
|
||||||
|
- `reception_desk` — Snap-Host (Pose: `sitting`)
|
||||||
|
- `waiting_chair` × 3 — Snap-Host (Pose: `sitting`)
|
||||||
|
|
||||||
|
**EG — Geschenke-Shop (4)**
|
||||||
|
- `gift_basket` — Holdable
|
||||||
|
- `plush_toy` — Holdable
|
||||||
|
- `greeting_card` — Holdable
|
||||||
|
- `shop_counter` — Snap-Host (Pose: `sitting`)
|
||||||
|
|
||||||
|
**EG — Restaurant (5)**
|
||||||
|
- `meal_tray_1/2/3` — Holdable (3 Mahlzeit-Varianten)
|
||||||
|
- `drink_cup` — Holdable
|
||||||
|
- `dining_table` — Snap-Host (Pose: `sitting`)
|
||||||
|
|
||||||
|
**EG — Notaufnahme (4)**
|
||||||
|
- `ambulance` — Maschine: Türen öffnen → Trage sichtbar *(bereits impl.)*
|
||||||
|
- `stretcher` — Holdable + Snap-Host (Pose: `lying`)
|
||||||
|
- `bandage_roll` — Outfit Item (Layer 2: Verband)
|
||||||
|
- `er_table` — Snap-Host (Pose: `lying`)
|
||||||
|
|
||||||
|
**1.OG — Röntgen (5)**
|
||||||
|
- `xray_machine` — Maschine: Figur auf Tisch → Röntgenbild *(bereits impl.)*
|
||||||
|
- `xray_photo` — Holdable (result item, spawnt nach Röntgen)
|
||||||
|
- `cast_machine` — Maschine: Figur rein → legt Gips-Outfit an
|
||||||
|
- `cast_arm` — Outfit Item (Layer 2: Gips)
|
||||||
|
- `xray_table` — Snap-Host (Pose: `lying`)
|
||||||
|
|
||||||
|
**1.OG — Apotheke (4)**
|
||||||
|
- `medicine_bottle_red/blue/yellow` — Applier: auf Figur → State = HEALTHY + `happy`
|
||||||
|
- `medicine_bag` — Holdable
|
||||||
|
- `pharmacy_counter` — Snap-Host (Pose: `sitting`)
|
||||||
|
|
||||||
|
**1.OG — Labor (4)**
|
||||||
|
- `microscope` — Maschine: Slide in Slot → Bild wechselt
|
||||||
|
- `test_tube` × 2 — Holdable
|
||||||
|
- `microscope_slide` — Holdable → passt in `microscope`-Slot
|
||||||
|
- `lab_stool` — Snap-Host (Pose: `sitting`)
|
||||||
|
|
||||||
|
**1.OG — Patientenzimmer (6)**
|
||||||
|
- `patient_bed` × 2 — Snap-Host (Pose: `lying`) *(bereits impl.)*
|
||||||
|
- `iv_bag` — Holdable + Applier: in IV-Hook gehängt + Figur im Bett → State = SLEEPING
|
||||||
|
- `iv_hook` — Slot an patient_bed, nimmt `iv_bag` auf
|
||||||
|
- `tv_remote` — Holdable
|
||||||
|
- `pillow` — Holdable
|
||||||
|
- `bedside_table` — Snap-Host (Pose: `sitting`)
|
||||||
|
|
||||||
|
**2.OG — Ultraschall (5)**
|
||||||
|
- `ultrasound_machine` — Maschine *(bereits impl.)*
|
||||||
|
- `ultrasound_probe` — Holdable + Applier: auf PREGNANT-Figur auf Tisch → Bildschirm zeigt Fötus
|
||||||
|
- `gel_tube` — Holdable
|
||||||
|
- `exam_table` — Snap-Host (Pose: `lying`)
|
||||||
|
- `ultrasound_screen` — reagiert auf Probe-Nähe (Kind des ultrasound_machine)
|
||||||
|
|
||||||
|
**2.OG — Kreißsaal (4)**
|
||||||
|
- `delivery_bed` — Maschine: PREGNANT eingerastet → BABY spawnt *(bereits impl.)*
|
||||||
|
- `baby_blanket` — Holdable
|
||||||
|
- `diaper` — Outfit Item für BABY (Layer 1)
|
||||||
|
- `baby_scale` — Snap-Host (Pose: `lying`, nur BABY-Figuren)
|
||||||
|
|
||||||
|
**2.OG — Säuglingsstation (5)**
|
||||||
|
- `cradle` × 2 — Snap-Host (Pose: `lying`) *(bereits impl.)*
|
||||||
|
- `baby_bottle` — Holdable + Applier: auf BABY → `happy`-Animation + Trink-SFX
|
||||||
|
- `rattle` — Holdable
|
||||||
|
- `pacifier` — Outfit Item für BABY (Layer 3)
|
||||||
|
- `incubator` — Snap-Host (Pose: `lying`, nur BABY-Figuren)
|
||||||
|
|
||||||
|
**Garten (7)**
|
||||||
|
- `gift_box` × 3 — Tap → öffnet sich *(bereits impl.)*
|
||||||
|
- `tea_pot` — Tap → gießt *(bereits impl.)*
|
||||||
|
- `tea_cup` × 2 — Holdable
|
||||||
|
- `cake` — Holdable
|
||||||
|
- `balloon` × 2 — Holdable
|
||||||
|
- `garden_table` — Snap-Host (Pose: `sitting`)
|
||||||
|
- `garden_chair` × 2 — Snap-Host (Pose: `sitting`)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitel 5 — Core Systems
|
||||||
|
|
||||||
|
### 5.1 Snap-Point System
|
||||||
|
|
||||||
|
`SnapPoint` ist ein `Node2D` an Möbeln:
|
||||||
|
```gdscript
|
||||||
|
class_name SnapPoint extends Node2D
|
||||||
|
@export var pose: String = "sitting" # "sitting" | "lying"
|
||||||
|
@export var species_filter: Array[String] = [] # leer = alle; ["BABY"] = nur Babys
|
||||||
|
var occupant: Character = null
|
||||||
|
```
|
||||||
|
|
||||||
|
`SnapReceiver` sitzt auf jeder Figur. Bei `drag_released` scannt er alle `SnapPoint`-Nodes im Radius 80px. Nächster freier Snap (unter Berücksichtigung `species_filter`) gewinnt: Figur teleportiert auf SnapPoint-Position, Animation wechselt zu `pose`. Beim erneuten Aufnehmen (`drag_picked_up`) gibt SnapPoint `occupant` frei → Animation zurück zu `held`.
|
||||||
|
|
||||||
|
### 5.2 Hand-Slot System
|
||||||
|
|
||||||
|
`HandLeft` und `HandRight` sind `Node2D`-Nodes an der Figur. Bei `drag_released` eines Holdable Items prüft das Item ob es sich in Reichweite (~60px) eines leeren Hand-Slots befindet. Wenn ja: Item wird Kind des Hand-Slots, `global_position` relativ zum Slot, reist mit Figur mit. Zweiter Drag vom Hand-Slot löst das Item. Maximum 1 Item pro Hand.
|
||||||
|
|
||||||
|
### 5.3 Outfit Layer System
|
||||||
|
|
||||||
|
Drei `Sprite2D`-Nodes über dem Basis-Sprite der Figur. `OutfitItem` hat:
|
||||||
|
```gdscript
|
||||||
|
@export var outfit_layer: int = 1 # 1 | 2 | 3
|
||||||
|
@export var outfit_sprite: Texture2D
|
||||||
|
```
|
||||||
|
Per Drag auf Figur → Layer-Sprite zeigt `outfit_sprite`, Item verschwindet aus Welt. Tap auf aktiven Layer → Item fällt neben Figur, Layer-Sprite wird leer. Gespeichert in `CharacterData.outfit: Array[String]` (3 Item-IDs).
|
||||||
|
|
||||||
|
### 5.4 Room Chest System
|
||||||
|
|
||||||
|
Jeder Raum hat einen `RoomChest`-Node:
|
||||||
|
```gdscript
|
||||||
|
class_name RoomChest extends Node2D
|
||||||
|
@export var item_ids: Array[String] = []
|
||||||
|
```
|
||||||
|
Tap auf Chest → öffnet sich, zeigt Items als Icon-Reihe (tappbar). Tap auf Icon → Item-Instanz spawnt neben Chest. Items die in die Chest-Zone (~100px) zurückgezogen werden despawnen. Gehaltene oder eingerastete Items werden nie automatisch entfernt. Chest-State (welche Items spawnt, wo) wird per SaveManager persistiert.
|
||||||
|
|
||||||
|
### 5.5 Applier-Logik
|
||||||
|
|
||||||
|
Items mit `apply_on_drop: bool = true` triggern `apply_to(character: Character)` wenn auf eine Figur gedroppt. Mapping:
|
||||||
|
|
||||||
|
| Item | Effekt |
|
||||||
|
|---|---|
|
||||||
|
| `medicine_bottle_*` | `set_state(HEALTHY)` + `happy`-Animation + `sfx_medicine` |
|
||||||
|
| `iv_bag` (in IV-Hook, Figur im Bett) | `set_state(SLEEPING)` |
|
||||||
|
| `baby_bottle` auf BABY | `happy`-Animation + `sfx_baby_coo` |
|
||||||
|
| `bandage_roll` | Outfit Layer 2: Verband-Sprite |
|
||||||
|
| `cast_arm` | Outfit Layer 2: Gips-Sprite |
|
||||||
|
| `diaper` | Outfit Layer 1 für BABY |
|
||||||
|
| `pacifier` | Outfit Layer 3 für BABY |
|
||||||
|
|
||||||
|
### 5.6 Maschinen-Interaktion
|
||||||
|
|
||||||
|
Maschinen haben einen `receive_slot: SnapPoint`. Zusätzliche Bedingungen lösen Ausgaben aus:
|
||||||
|
|
||||||
|
| Maschine | Bedingung | Ausgabe |
|
||||||
|
|---|---|---|
|
||||||
|
| `xray_machine` | Figur auf `xray_table` | Röntgenbild-Animation → `xray_photo` spawnt |
|
||||||
|
| `ultrasound_machine` | PREGNANT auf `exam_table` + `ultrasound_probe` in HandSlot | Fötus-Bild auf `ultrasound_screen` |
|
||||||
|
| `microscope` | `microscope_slide` in Slot | Bild-Wechsel auf Screen |
|
||||||
|
| `queue_machine` | Tap | `number_ticket` spawnt |
|
||||||
|
| `iv_hook` | `iv_bag` eingehängt + Figur in `patient_bed` | `set_state(SLEEPING)` |
|
||||||
|
| `delivery_bed` | PREGNANT eingerastet + 2s | BABY spawnt, Mutter → HEALTHY *(bereits impl.)* |
|
||||||
|
| `cast_machine` | Figur eingerastet | `cast_arm`-Outfit (Layer 2) auf Figur, Figur → HEALTHY |
|
||||||
|
| `baby_scale` | BABY-Figur eingerastet | `happy`-Animation + `sfx_happy` |
|
||||||
|
| `ultrasound_machine` | PREGNANT auf `exam_table` + `ultrasound_probe` in HandSlot | Fötus-Bild auf `ultrasound_screen` |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitel 6 — UI & Navigation
|
||||||
|
|
||||||
|
### HUD (immer sichtbar)
|
||||||
|
|
||||||
|
- **Aufzug-Button** — Etagen-Wechsel, 64dp, links oder rechts je nach Raum
|
||||||
|
- **HomeButton** — Hospital ↔ Garten, 64dp *(bereits impl.)*
|
||||||
|
- **Settings-Button** — oben rechts, 48dp
|
||||||
|
- **Kein Score, kein Timer, keine Sterne, kein Text**
|
||||||
|
|
||||||
|
### Navigation
|
||||||
|
|
||||||
|
| System | Status |
|
||||||
|
|---|---|
|
||||||
|
| Camera-Pan innerhalb Etage | `NavigationArrow` *(bereits impl.)* |
|
||||||
|
| Etagen-Wechsel | `ElevatorButton` + `RoomNavigator` *(bereits impl.)* |
|
||||||
|
| Hospital ↔ Garten | `HomeButton` *(bereits impl.)* |
|
||||||
|
|
||||||
|
### Room Chest UI
|
||||||
|
|
||||||
|
Tap auf Chest → Icon-Reihe erscheint direkt in der Spielwelt über/neben der Chest (kein separater Screen). Tap außerhalb → Chest schließt. Icons haben 64dp Mindestgröße.
|
||||||
|
|
||||||
|
### Settings-Menü
|
||||||
|
|
||||||
|
- Lautstärke Musik (Slider)
|
||||||
|
- Lautstärke SFX (Slider)
|
||||||
|
- Savegame zurücksetzen (mit Bestätigung)
|
||||||
|
- Später: Sprache
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitel 7 — Audio Design
|
||||||
|
|
||||||
|
### Musik
|
||||||
|
|
||||||
|
| Bereich | Stil | Loop-Länge |
|
||||||
|
|---|---|---|
|
||||||
|
| EG | Fröhlich, Empfangs-Feeling | ~2 min |
|
||||||
|
| 1.OG | Ruhig, Glockenspiel-Elemente | ~2 min |
|
||||||
|
| 2.OG | Sanft, Schlaflied-Atmosphäre | ~2 min |
|
||||||
|
| Garten | Beschwingt, Party-Feeling | ~2 min |
|
||||||
|
|
||||||
|
Cross-Fade bei Etagen-Wechsel (AudioManager bereits impl.). Default-Lautstärke: 60%.
|
||||||
|
|
||||||
|
### SFX-Katalog
|
||||||
|
|
||||||
|
| ID | Trigger |
|
||||||
|
|---|---|
|
||||||
|
| `sfx_pickup` | Figur oder Item aufheben |
|
||||||
|
| `sfx_place` | Figur oder Item ablegen (kein Snap) |
|
||||||
|
| `sfx_snap` | Figur rastet in SnapPoint ein |
|
||||||
|
| `sfx_happy` | `happy`-Animation startet |
|
||||||
|
| `sfx_chest_open` | RoomChest öffnet |
|
||||||
|
| `sfx_item_spawn` | Item spawnt aus Chest |
|
||||||
|
| `sfx_medicine` | Medikament auf Figur angewendet |
|
||||||
|
| `sfx_pour` | TeaPot gießt |
|
||||||
|
| `sfx_gift_open` | GiftBox öffnet |
|
||||||
|
| `sfx_cradle_rock` | Wiege schaukelt |
|
||||||
|
| `sfx_xray_scan` | Röntgengerät aktiv |
|
||||||
|
| `sfx_ambulance` | Ambulanz-Türen öffnen |
|
||||||
|
| `sfx_baby_coo` | Baby-Interaktion (Fläschchen, Schaukeln) |
|
||||||
|
| `sfx_bunny_sniff` | Häschen-Figur aufgehoben |
|
||||||
|
| `sfx_kitten_meow` | Kätzchen-Figur aufgehoben |
|
||||||
|
| `sfx_fox_yip` | Fuchs-Figur aufgehoben |
|
||||||
|
| `sfx_owl_hoot` | Eulen-Figur aufgehoben |
|
||||||
|
|
||||||
|
**Quellen:** freesound.org, opengameart.org (Creative Commons)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitel 8 — Save/Load
|
||||||
|
|
||||||
|
### Format v2
|
||||||
|
|
||||||
|
Erweiterung des bestehenden `SaveManager` + `GameState`. Migration: v1-Saves werden beim Laden auf v2 hochkonvertiert (fehlende Felder → Defaults).
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"version": 2,
|
||||||
|
"current_floor": 0,
|
||||||
|
"characters": {
|
||||||
|
"bunny_f": {
|
||||||
|
"position": [640, 360],
|
||||||
|
"state": "HEALTHY",
|
||||||
|
"outfit": ["white_coat", "", "stethoscope"],
|
||||||
|
"held_left": "medicine_bottle_blue",
|
||||||
|
"held_right": "",
|
||||||
|
"snap_point": "floor1/xray/xray_table/snap_0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"room_chests": {
|
||||||
|
"floor0/reception/chest": {
|
||||||
|
"spawned_items": [
|
||||||
|
{"id": "number_ticket", "pos": [200, 300]}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Auto-Save:** nach jeder Interaktion (Pick-up, Place, Snap, Outfit-Wechsel, State-Änderung).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Kapitel 9 — Sprint-Plan (Gesamt)
|
||||||
|
|
||||||
|
| Sprint | Titel | Kern-Deliverable |
|
||||||
|
|---|---|---|
|
||||||
|
| 0 | Setup | Git, Godot, Android-Export |
|
||||||
|
| 1–2 | Proof of Concept | Ein Raum, eine Figur, Drag & Drop |
|
||||||
|
| 3–4 | Core Systems | RoomNavigator, SaveManager, Settings |
|
||||||
|
| 5–7 | Erdgeschoss | Reception, GiftShop, Restaurant, EmergencyRoom |
|
||||||
|
| 8–10 | 1. Obergeschoss | XRay, Pharmacy, Lab, PatientRoom |
|
||||||
|
| 11–13 | 2. Obergeschoss | Ultrasound, DeliveryRoom, Nursery |
|
||||||
|
| **14** | **Zuhause & Garten** | **GardenParty, HomeButton, GiftBox, TeaPot ✅** |
|
||||||
|
| **15** | **Character System v2** | **AnimatedSprite2D (6 States), SnapReceiver, HandSlots, OutfitLayers** |
|
||||||
|
| **16** | **Snap-Point System** | **SnapPoint an allen Möbeln in allen 12 Räumen** |
|
||||||
|
| **17** | **Hand-Slots + Outfits** | **Item-Holding, OutfitItem-Typ, Apply-Logik, Save-Extension** |
|
||||||
|
| **18** | **Room Chests + Items** | **RoomChest-Node, alle ~55 Objekte verteilt** |
|
||||||
|
| **19** | **Maschinen & Applier** | **XRay-Foto, Ultraschall-Fötus, Mikroskop, Wartenummer, IV-Bag, Medizin** |
|
||||||
|
| **20** | **Sound & Musik** | **Kompletter SFX-Katalog, Musik-Loops** |
|
||||||
|
| **21** | **Polish** | **Tutorial-Hint, Animations-Feinschliff, Settings-Erweiterung** |
|
||||||
|
| **22** | **Release** | **Icon, Splash, Play Store, Familien-Testing** |
|
||||||
|
|
||||||
|
Sprints 0–14 ✅ abgeschlossen. Sprints 15–22 stehen aus.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Appendix — Asset-Strategie
|
||||||
|
|
||||||
|
**Empfehlung: Hybrid**
|
||||||
|
- Kinder malen Helden-Figuren (Häschen, Kätzchen) auf Papier → einscannen → digitalisieren
|
||||||
|
- Freelancer für Hintergründe und generische Objekte
|
||||||
|
- Tier-Geräusche: freesound.org (Creative Commons)
|
||||||
|
|
||||||
|
**Asset-Formate:**
|
||||||
|
- Sprites: PNG mit Transparenz, 2× (für Retina-Displays)
|
||||||
|
- Animationen: SpriteSheet oder einzelne Frames in `AnimatedSprite2D`
|
||||||
|
- Audio: OGG für Loops, WAV für kurze SFX
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Dieses Dokument wird nur bei Produkt-Entscheidungen aktualisiert, nie bei rein technischen Implementierungsdetails.*
|
||||||
Reference in New Issue
Block a user