chore: initialize project structure for Sprint 0
This commit is contained in:
51
.gitignore
vendored
Normal file
51
.gitignore
vendored
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
# Godot 4 project files to ignore
|
||||||
|
|
||||||
|
# Godot generated files
|
||||||
|
.godot/
|
||||||
|
.import/
|
||||||
|
|
||||||
|
# Godot-specific ignores
|
||||||
|
export.cfg
|
||||||
|
export_presets.cfg
|
||||||
|
|
||||||
|
# Imported translations (automatically generated from CSV files)
|
||||||
|
*.translation
|
||||||
|
|
||||||
|
# Mono-specific ignores (falls C# verwendet wird)
|
||||||
|
.mono/
|
||||||
|
data_*/
|
||||||
|
mono_crash.*.json
|
||||||
|
|
||||||
|
# System/IDE files
|
||||||
|
.DS_Store
|
||||||
|
Thumbs.db
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
|
.idea/
|
||||||
|
.vscode/
|
||||||
|
*.tmp
|
||||||
|
|
||||||
|
# Build outputs
|
||||||
|
builds/
|
||||||
|
export/
|
||||||
|
*.apk
|
||||||
|
*.aab
|
||||||
|
*.ipa
|
||||||
|
|
||||||
|
# Android keystore (NIEMALS ins Repo!)
|
||||||
|
*.keystore
|
||||||
|
*.jks
|
||||||
|
android/release.keystore
|
||||||
|
|
||||||
|
# Secrets
|
||||||
|
secrets.cfg
|
||||||
|
.env
|
||||||
|
.env.local
|
||||||
|
|
||||||
|
# Logs
|
||||||
|
*.log
|
||||||
|
logs/
|
||||||
|
|
||||||
|
# OS-spezifisch
|
||||||
|
desktop.ini
|
||||||
192
CLAUDE.md
Normal file
192
CLAUDE.md
Normal file
@@ -0,0 +1,192 @@
|
|||||||
|
# CLAUDE.md — Cozypaw Hospital
|
||||||
|
|
||||||
|
> Dieses Dokument ist der Primär-Kontext für Claude Code. Beim Start lesen und die hier dokumentierten Konventionen einhalten.
|
||||||
|
|
||||||
|
## Projekt in einem Satz
|
||||||
|
|
||||||
|
Cozypaw Hospital ist ein werbefreies 2D-Sandbox-Spiel für Kinder (3+) im Stil von Yasa Pets Hospital — ein dreistöckiges Tier-Krankenhaus mit Häschen und Kätzchen als digitale Puppenstube, gebaut in Godot 4 für Android und iOS.
|
||||||
|
|
||||||
|
## Aktueller Status
|
||||||
|
|
||||||
|
- **Phase:** Sprint 0 (Setup)
|
||||||
|
- **Repo:** git.race-cave.cloud/steven/Cozypaw-Hospital (self-hosted Gitea)
|
||||||
|
- **Godot-Projekt:** noch nicht initialisiert
|
||||||
|
- **Nächster Meilenstein:** Godot 4 installieren, Android-Export einrichten, Proof-of-Concept-Raum
|
||||||
|
|
||||||
|
Der vollständige 16-Wochen-Sprintplan liegt in `docs/development-plan.md`. Immer dort nachschlagen, bevor neue Features beschlossen werden.
|
||||||
|
|
||||||
|
## Tech-Stack (fix)
|
||||||
|
|
||||||
|
- **Engine:** Godot 4.x (keine Unity, keine Alternativen mehr zur Debatte)
|
||||||
|
- **Sprache:** GDScript (statisch typisiert, wo möglich)
|
||||||
|
- **Zielplattformen:** Android zuerst, iOS später
|
||||||
|
- **VCS:** Git mit self-hosted Gitea
|
||||||
|
- **Asset-Strategie:** Hybrid — Kinder malen Helden-Figuren, Freelancer macht Hintergründe
|
||||||
|
|
||||||
|
## Nicht-verhandelbare Produkt-Prinzipien
|
||||||
|
|
||||||
|
Diese Punkte sind Teil der Produkt-DNA. Niemals vorschlagen, davon abzuweichen — auch nicht "nur für Testing" oder "vorübergehend":
|
||||||
|
|
||||||
|
1. **Keine Werbung.** Keine Ad-SDKs, keine Rewarded Ads, kein AdMob, nichts.
|
||||||
|
2. **Keine Datensammlung.** Keine Analytics (Firebase, GA, Sentry, etc.), kein Tracking, keine Telemetrie, keine Crash-Reports ohne Opt-in.
|
||||||
|
3. **Offline-first.** Das Spiel muss vollständig ohne Internetverbindung funktionieren.
|
||||||
|
4. **Keine In-App-Käufe.** Keine Premium-Features, keine Diamonds, kein Gacha.
|
||||||
|
5. **Keine externen Links** ohne Parental Gate (derzeit: gar keine).
|
||||||
|
6. **Keine "Gift"-Mechaniken** (im Original: grüne Flaschen, die Tiere krank machen). Alle Medikamente sind neutral/positiv.
|
||||||
|
7. **Sandbox-Charakter.** Kein Scheitern, keine Zeitlimits, kein Scoring, keine Achievements.
|
||||||
|
8. **COPPA/DSGVO-konform.** Play-Store-Data-Safety: "Keine Daten erhoben" — und das auch tatsächlich einhalten.
|
||||||
|
|
||||||
|
## Architektur-Überblick
|
||||||
|
|
||||||
|
### Scene-Hierarchie (geplant)
|
||||||
|
|
||||||
|
```
|
||||||
|
Main (Node2D)
|
||||||
|
├── Hospital (Node2D)
|
||||||
|
│ ├── Floor0 — Empfang, GiftShop, Restaurant, Emergency
|
||||||
|
│ ├── Floor1 — XRay, Pharmacy, Lab, PatientRooms
|
||||||
|
│ └── Floor2 — Ultrasound, DeliveryRoom, Nursery
|
||||||
|
├── Home (Node2D) — GardenParty
|
||||||
|
├── Characters (Autoload)
|
||||||
|
└── UI (CanvasLayer)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Core Systems (als Autoloads)
|
||||||
|
|
||||||
|
- `GameState` — globaler Zustand, Positionen aller Figuren/Objekte
|
||||||
|
- `SaveManager` — JSON-Persistenz in `user://savegame.json`, Auto-Save nach jeder Interaktion
|
||||||
|
- `AudioManager` — Musik- und SFX-Steuerung mit Cross-Fade zwischen Räumen
|
||||||
|
- `InputManager` — Touch/Drag-Abstraktion
|
||||||
|
|
||||||
|
### Datenmodell-Konvention
|
||||||
|
|
||||||
|
Character- und Object-States immer als `Resource`-Subklassen (nicht als dict), damit Godot-Editor damit arbeiten kann und Serialisierung sauber läuft.
|
||||||
|
|
||||||
|
## Verzeichnisstruktur
|
||||||
|
|
||||||
|
```
|
||||||
|
cozypaw-hospital/
|
||||||
|
├── project.godot
|
||||||
|
├── scenes/
|
||||||
|
│ ├── main/
|
||||||
|
│ ├── rooms/{floor0,floor1,floor2,home}/
|
||||||
|
│ ├── characters/
|
||||||
|
│ ├── objects/
|
||||||
|
│ └── ui/
|
||||||
|
├── scripts/
|
||||||
|
│ ├── autoload/
|
||||||
|
│ ├── characters/
|
||||||
|
│ ├── objects/
|
||||||
|
│ └── systems/
|
||||||
|
├── assets/
|
||||||
|
│ ├── sprites/{characters,rooms,objects,ui}/
|
||||||
|
│ ├── audio/{music,sfx,voices}/
|
||||||
|
│ └── fonts/
|
||||||
|
├── localization/
|
||||||
|
├── addons/
|
||||||
|
├── docs/
|
||||||
|
└── builds/ # nicht im Git
|
||||||
|
```
|
||||||
|
|
||||||
|
## Konventionen
|
||||||
|
|
||||||
|
### Commits (Conventional Commits)
|
||||||
|
|
||||||
|
- `feat:` neues Feature
|
||||||
|
- `fix:` Bugfix
|
||||||
|
- `refactor:` Refactoring ohne Funktionsänderung
|
||||||
|
- `assets:` Asset-Updates (Sprites, Sounds)
|
||||||
|
- `docs:` Dokumentation
|
||||||
|
- `chore:` Build, Config, Tooling
|
||||||
|
|
||||||
|
Mit Scope: `feat(reception): add waiting number system`
|
||||||
|
|
||||||
|
Commit-Messages in **Englisch** (auch wenn die Doku auf Deutsch ist).
|
||||||
|
|
||||||
|
### Branching
|
||||||
|
|
||||||
|
- `main` — stabiler Stand, releasebar
|
||||||
|
- `develop` — aktive Entwicklung
|
||||||
|
- `feature/<name>` — einzelne Features
|
||||||
|
- `sprint/<nr>-<name>` — Sprint-Branches
|
||||||
|
|
||||||
|
Keine direkten Pushes auf `main`. Merges aus `develop` nur, wenn Build grün und auf echtem Tablet getestet.
|
||||||
|
|
||||||
|
### GDScript Code-Style
|
||||||
|
|
||||||
|
- **Typisierung:** Statische Typen überall wo möglich (`var x: int = 5`)
|
||||||
|
- **Nomenklatur:** `snake_case` für Variablen/Funktionen, `PascalCase` für Klassen und Scenes, `SCREAMING_SNAKE_CASE` für Konstanten
|
||||||
|
- **Signals:** Zukunftsform-Verben: `character_picked_up`, `room_entered`
|
||||||
|
- **Private Member:** Unterstrich-Präfix: `_internal_state`
|
||||||
|
|
||||||
|
### Dokumentation
|
||||||
|
|
||||||
|
Stevens Präferenz (aus bisheriger Arbeit): **Keine Inline-Kommentare im Code.** Stattdessen konsolidierte Dokumentation als Header-Block am Dateianfang. Code soll selbsterklärend sein durch gute Namen. Diese Regel gilt auch für GDScript-Dateien.
|
||||||
|
|
||||||
|
Ausnahme: Komplexe mathematische Berechnungen oder nicht-offensichtliche Workarounds dürfen einen einzigen Kommentar haben, der das *Warum* erklärt (nicht das Was).
|
||||||
|
|
||||||
|
### Tests
|
||||||
|
|
||||||
|
Für ein Spiel dieser Größe keine Unit-Tests nötig. Stattdessen:
|
||||||
|
- **Scene-Tests** manuell auf echtem Android-Tablet pro Sprint
|
||||||
|
- **Smoke-Test-Checkliste** in `docs/smoke-tests.md` (wird im Laufe der Entwicklung gepflegt)
|
||||||
|
- **Kinder als UAT** — wöchentliches Zeigen der Builds
|
||||||
|
|
||||||
|
## UI/UX-Regeln
|
||||||
|
|
||||||
|
- **Touch-Targets:** Minimum 48dp, besser 64dp
|
||||||
|
- **Keine Text-UI** für Spiel-Interaktionen (Kinder unter 6 Jahren lesen nicht). Icons, Symbole, Farben.
|
||||||
|
- **Zurück-Button** immer sichtbar, groß und an festem Platz
|
||||||
|
- **Musik-Default:** 60%, nicht 100%
|
||||||
|
- **Idle-Animationen:** Jede Figur atmet/blinzelt auch im Stand
|
||||||
|
- **Sound-Feedback** für jede Interaktion (Ploppen, Quietschen, etc.)
|
||||||
|
|
||||||
|
## Out of Scope (bewusst nicht gemacht)
|
||||||
|
|
||||||
|
- ❌ Multiplayer, Online-Features, Cloud-Saves
|
||||||
|
- ❌ Prozedurale Generierung
|
||||||
|
- ❌ Physik-Engine (nicht nötig für Puppenhaus-Interaktionen)
|
||||||
|
- ❌ Character-Editor / Customization
|
||||||
|
- ❌ Level-System, Achievements, Scoring
|
||||||
|
- ❌ Tutorial (außer dezenter Hinweis beim allerersten Start)
|
||||||
|
- ❌ Rechtschreibung/Text-Eingabe durch Kinder
|
||||||
|
|
||||||
|
## Wie Claude Code arbeiten soll
|
||||||
|
|
||||||
|
### Proaktiv sein
|
||||||
|
- Bei Godot-spezifischen Fragen: Godot-4-Docs konsultieren, nicht Godot-3-Patterns nutzen (Syntax hat sich geändert).
|
||||||
|
- Bei neuen Scenes: An der oben definierten Verzeichnisstruktur orientieren.
|
||||||
|
- Code immer mit statischen Typen schreiben.
|
||||||
|
|
||||||
|
### Keine Überraschungen
|
||||||
|
- Keine neuen Dependencies / Addons hinzufügen ohne explizite Rücksprache.
|
||||||
|
- Keine Änderungen am `.gitignore`, `README.md` oder dieser Datei ohne explizite Aufforderung.
|
||||||
|
- Keine automatischen Commits. Stevens Workflow: Er committed selbst nach Review.
|
||||||
|
|
||||||
|
### Bei Unsicherheit nachfragen
|
||||||
|
- Wenn unklar, ob ein Feature in den Sandbox-Charakter passt → fragen.
|
||||||
|
- Wenn unklar, wie etwas visuell/interaktiv funktionieren soll → fragen, nicht raten.
|
||||||
|
|
||||||
|
### Sprach-Konvention
|
||||||
|
- **Code & Commits:** Englisch
|
||||||
|
- **Dokumentation & Gespräch:** Deutsch
|
||||||
|
- **Spiel-Inhalte (UI, ggf. Texte):** Später lokalisiert — primär Deutsch, dann Englisch
|
||||||
|
|
||||||
|
## Referenz-Dokumente
|
||||||
|
|
||||||
|
- `docs/development-plan.md` — 16-Wochen-Sprintplan mit Details
|
||||||
|
- `README.md` — öffentliche Projektbeschreibung
|
||||||
|
- `docs/` — alle weiteren Design-Docs (werden im Laufe der Sprints ergänzt)
|
||||||
|
|
||||||
|
## Kontext zum Entwickler (Steven)
|
||||||
|
|
||||||
|
- Java-Entwickler, kommt aus dem Backend/Enterprise-Umfeld
|
||||||
|
- Präferiert clean, concise technical work — keine Verbose-Erklärungen
|
||||||
|
- Kommuniziert primär auf Deutsch
|
||||||
|
- Baut das Spiel für seine eigenen Kinder (nicht für einen kommerziellen Launch)
|
||||||
|
- Hat parallel laufende Projekte (All-in Creative Print, RaceCave) — dieses Projekt ist Abendbeschäftigung, nicht Vollzeit
|
||||||
|
- Arbeitet gerne mit klaren Conventions und durchdachter Struktur statt Ad-hoc-Lösungen
|
||||||
|
|
||||||
|
## Versions-Log dieser Datei
|
||||||
|
|
||||||
|
- 2026-04-17: Initiale Version, Sprint 0 gestartet
|
||||||
111
README.md
Normal file
111
README.md
Normal file
@@ -0,0 +1,111 @@
|
|||||||
|
# 🏥 Cozypaw Hospital
|
||||||
|
|
||||||
|
> Ein werbefreies Sandbox-Spiel für Kinder — ein kuscheliges Krankenhaus voller Häschen und Kätzchen.
|
||||||
|
|
||||||
|
## Über das Projekt
|
||||||
|
|
||||||
|
Cozypaw Hospital ist eine digitale Puppenstube: Kinder erkunden ein dreistöckiges Krankenhaus mit niedlichen Tier-Figuren, bewegen Gegenstände, erzählen Geschichten. Keine Ziele, kein Scheitern, keine Werbung, keine Datensammlung.
|
||||||
|
|
||||||
|
Inspiriert von Yasa Pets Hospital, aber liebevoll eigenständig gemacht — und ohne die Probleme des Originals (pervasive Werbung, Datentracking, fragwürdige Spielmechaniken).
|
||||||
|
|
||||||
|
## Features
|
||||||
|
|
||||||
|
- 🏥 Dreistöckiges Krankenhaus mit 12 interaktiven Räumen
|
||||||
|
- 🐰 Häschen und 🐱 Kätzchen als Figuren
|
||||||
|
- 🎨 Handgezeichneter Cartoon-Stil
|
||||||
|
- 📴 Offline-first, keine Internetverbindung nötig
|
||||||
|
- 🚫 Keine Werbung, keine In-App-Käufe, keine Analytics
|
||||||
|
- 👨👩👧👦 Designed für Kinder ab 3 Jahren
|
||||||
|
|
||||||
|
## Tech Stack
|
||||||
|
|
||||||
|
- **Engine:** Godot 4.x
|
||||||
|
- **Sprache:** GDScript
|
||||||
|
- **Zielplattformen:** Android, iOS
|
||||||
|
- **Version Control:** Git (self-hosted Gitea)
|
||||||
|
|
||||||
|
## Projektstruktur
|
||||||
|
|
||||||
|
```
|
||||||
|
cozypaw-hospital/
|
||||||
|
├── project.godot # Godot-Projektdatei
|
||||||
|
├── scenes/ # Alle .tscn Scene-Dateien
|
||||||
|
│ ├── main/ # Haupt-Scene, Menüs
|
||||||
|
│ ├── rooms/ # Räume (Empfang, Apotheke, etc.)
|
||||||
|
│ ├── characters/ # Figuren-Scenes
|
||||||
|
│ ├── objects/ # Interaktive Objekte
|
||||||
|
│ └── ui/ # UI-Elemente, HUD
|
||||||
|
├── scripts/ # GDScript-Dateien
|
||||||
|
│ ├── autoload/ # Globale Singletons
|
||||||
|
│ ├── characters/ # Character-Logik
|
||||||
|
│ ├── objects/ # Objekt-Logik
|
||||||
|
│ └── systems/ # Core Systems (Save, Audio, etc.)
|
||||||
|
├── assets/
|
||||||
|
│ ├── sprites/ # 2D-Grafiken
|
||||||
|
│ ├── audio/ # Sounds und Musik
|
||||||
|
│ ├── fonts/ # Schriftarten
|
||||||
|
│ └── ui/ # UI-Grafiken
|
||||||
|
├── localization/ # CSV-Dateien für Übersetzungen
|
||||||
|
├── addons/ # Godot-Plugins
|
||||||
|
├── docs/ # Dokumentation, Design-Docs
|
||||||
|
└── builds/ # Build-Outputs (nicht im Git)
|
||||||
|
```
|
||||||
|
|
||||||
|
## Entwicklung
|
||||||
|
|
||||||
|
### Voraussetzungen
|
||||||
|
|
||||||
|
- Godot 4.x ([Download](https://godotengine.org/download))
|
||||||
|
- Git
|
||||||
|
- Android Studio + SDK (für Android-Export)
|
||||||
|
- Xcode + Apple Developer Account (für iOS-Export, später)
|
||||||
|
|
||||||
|
### Einrichtung
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Repo klonen
|
||||||
|
git clone https://git.race-cave.cloud/steven/Cozypaw-Hospital.git
|
||||||
|
cd Cozypaw-Hospital
|
||||||
|
|
||||||
|
# Projekt in Godot öffnen
|
||||||
|
godot -e
|
||||||
|
```
|
||||||
|
|
||||||
|
### Branching-Strategie
|
||||||
|
|
||||||
|
- `main` — stabiler Stand, jederzeit releasebar
|
||||||
|
- `develop` — aktuelle Entwicklung
|
||||||
|
- `feature/<name>` — einzelne Features (z.B. `feature/reception-room`)
|
||||||
|
- `sprint/<nummer>` — Sprint-Branches (z.B. `sprint/01-proof-of-concept`)
|
||||||
|
|
||||||
|
### Commits
|
||||||
|
|
||||||
|
Conventional Commits Format:
|
||||||
|
- `feat:` neues Feature
|
||||||
|
- `fix:` Bugfix
|
||||||
|
- `refactor:` Refactoring ohne Funktionsänderung
|
||||||
|
- `assets:` Asset-Updates (Sprites, Sounds)
|
||||||
|
- `docs:` Dokumentation
|
||||||
|
- `chore:` Build, Config, etc.
|
||||||
|
|
||||||
|
Beispiel: `feat(rooms): add reception room with waiting number system`
|
||||||
|
|
||||||
|
## Sprint-Fortschritt
|
||||||
|
|
||||||
|
- [x] Sprint 0: Repo-Setup
|
||||||
|
- [ ] Sprint 1-2: Proof of Concept
|
||||||
|
- [ ] Sprint 3-4: Core Systems
|
||||||
|
- [ ] Sprint 5-7: Erdgeschoss
|
||||||
|
- [ ] Sprint 8-10: 1. Obergeschoss
|
||||||
|
- [ ] Sprint 11-13: 2. Obergeschoss
|
||||||
|
- [ ] Sprint 14: Zuhause & Garten
|
||||||
|
- [ ] Sprint 15: Polish & Sound
|
||||||
|
- [ ] Sprint 16+: Release-Vorbereitung
|
||||||
|
|
||||||
|
## Lizenz
|
||||||
|
|
||||||
|
Privates Familienprojekt. Alle Rechte vorbehalten.
|
||||||
|
|
||||||
|
## Kontakt
|
||||||
|
|
||||||
|
Steven — [git.race-cave.cloud/steven](https://git.race-cave.cloud/steven)
|
||||||
0
addons/.gitkeep
Normal file
0
addons/.gitkeep
Normal file
0
assets/audio/music/.gitkeep
Normal file
0
assets/audio/music/.gitkeep
Normal file
0
assets/audio/sfx/.gitkeep
Normal file
0
assets/audio/sfx/.gitkeep
Normal file
0
assets/audio/voices/.gitkeep
Normal file
0
assets/audio/voices/.gitkeep
Normal file
0
assets/fonts/.gitkeep
Normal file
0
assets/fonts/.gitkeep
Normal file
0
assets/sprites/characters/.gitkeep
Normal file
0
assets/sprites/characters/.gitkeep
Normal file
0
assets/sprites/objects/.gitkeep
Normal file
0
assets/sprites/objects/.gitkeep
Normal file
0
assets/sprites/rooms/.gitkeep
Normal file
0
assets/sprites/rooms/.gitkeep
Normal file
0
assets/sprites/ui/.gitkeep
Normal file
0
assets/sprites/ui/.gitkeep
Normal file
0
docs/.gitkeep
Normal file
0
docs/.gitkeep
Normal file
386
docs/development-plan.md
Normal file
386
docs/development-plan.md
Normal file
@@ -0,0 +1,386 @@
|
|||||||
|
# Entwicklungsplan: Tier-Krankenhaus (Arbeitstitel)
|
||||||
|
|
||||||
|
> Ein Sandbox-Spiel für Kinder im Stil von *Yasa Pets Hospital* — aber **werbefrei, ohne Datensammlung, ohne grüne Giftflaschen** und liebevoll selbst gemacht.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. Produkt-Vision
|
||||||
|
|
||||||
|
**Kernprinzip:** Digitale Puppenstube. Keine Ziele, kein Scheitern, kein Zeitdruck. Die Kinder erzählen sich mit den Figuren Geschichten.
|
||||||
|
|
||||||
|
**Was bleibt vom Original:**
|
||||||
|
- 3-Etagen-Krankenhaus im Querschnitt (Sidescroller-Puppenhaus)
|
||||||
|
- Häschen- und Kätzchen-Figuren
|
||||||
|
- Drag & Drop von Figuren zwischen Räumen
|
||||||
|
- ~40–60 interaktive Objekte
|
||||||
|
- Gartenparty als Bonusbereich
|
||||||
|
|
||||||
|
**Was wir besser machen:**
|
||||||
|
- ❌ **Keine Werbung** (Kinder spielen ungestört)
|
||||||
|
- ❌ **Keine Datensammlung** (keine Analytics, kein Tracking)
|
||||||
|
- ❌ **Keine "grünen Giftflaschen"** — ersetzt durch harmlose Mechaniken
|
||||||
|
- ✅ **Offline-first** (keine Internetpflicht)
|
||||||
|
- ✅ **Gartenbereich von Anfang an offen** (keine Sammellogik mit Sternen)
|
||||||
|
- ✅ **Größere Touch-Targets** (mind. 48dp/64px, Kritikpunkt am Original)
|
||||||
|
- ✅ **Figuren basierend auf Fotos eurer eigenen Haustiere / Wünschen der Kinder** (das ist der eigentliche Kicker)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. Tech-Stack-Empfehlung: Godot 4.x
|
||||||
|
|
||||||
|
### Warum Godot
|
||||||
|
|
||||||
|
| Kriterium | Godot 4 | Unity | libGDX | Flutter/Flame |
|
||||||
|
|---|---|---|---|---|
|
||||||
|
| Kosten | **Kostenlos, MIT-Lizenz** | Kostenlos bis Umsatzschwelle | Kostenlos | Kostenlos |
|
||||||
|
| 2D-Eignung | **Exzellent** | Gut | Gut | Mittel |
|
||||||
|
| Android-Export | **Out-of-the-box** | Ja | Ja (nativ) | Ja |
|
||||||
|
| iOS-Export | Ja (Mac nötig) | Ja (Mac nötig) | Ja (Mac nötig) | Ja (Mac nötig) |
|
||||||
|
| Engine-Größe | ~100 MB | ~10 GB | Sehr klein | Mittel |
|
||||||
|
| Lernkurve (Java-Dev) | **3-5 Tage** | 1-2 Wochen | Vertraut | 1 Woche (Dart) |
|
||||||
|
| Perfekt für Sandbox | **Ja** (Node-Tree!) | Ja | Eher Code-zentrisch | Mittel |
|
||||||
|
|
||||||
|
**Godot-Killer-Feature für dieses Spiel:** Die Scene-Node-Hierarchie bildet dein Krankenhaus 1:1 ab:
|
||||||
|
|
||||||
|
```
|
||||||
|
Hospital (Node2D)
|
||||||
|
├── Floor1 (Node2D)
|
||||||
|
│ ├── Reception (Node2D)
|
||||||
|
│ │ ├── Desk (StaticBody2D)
|
||||||
|
│ │ ├── QueueDisplay (Sprite2D)
|
||||||
|
│ │ └── InteractiveObjects/*
|
||||||
|
│ ├── GiftShop
|
||||||
|
│ ├── Restaurant
|
||||||
|
│ └── EmergencyRoom
|
||||||
|
├── Floor2 (XRay, Pharmacy, Lab, PatientRooms)
|
||||||
|
├── Floor3 (Delivery, Nursery, Ultrasound)
|
||||||
|
├── Home (GardenParty)
|
||||||
|
└── Characters (Autoload)
|
||||||
|
├── Bunny1
|
||||||
|
├── Bunny2
|
||||||
|
└── Kitten1
|
||||||
|
```
|
||||||
|
|
||||||
|
### Voraussetzungen
|
||||||
|
|
||||||
|
- **Entwicklungs-Rechner:** Dein Arbeitsplatz reicht
|
||||||
|
- **Android-Export:** Android Studio SDK + JDK (einmalig einrichten)
|
||||||
|
- **iOS-Export:** Mac + Xcode + Apple Developer Account (€99/Jahr) — **oder:** Android zuerst, iOS später nachziehen
|
||||||
|
- **Version Control:** Git (Godot-Projekte sind git-freundlich, `.import/` und `.godot/` in `.gitignore`)
|
||||||
|
|
||||||
|
### Empfohlene VS Code Setup (alternativ zum Godot-Editor)
|
||||||
|
|
||||||
|
- Godot-Editor für Scenes und visuelle Arbeit
|
||||||
|
- VS Code mit `godot-tools` Extension für GDScript
|
||||||
|
- Git Workflow wie gewohnt
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. Architektur
|
||||||
|
|
||||||
|
### 3.1 Scene-Struktur
|
||||||
|
|
||||||
|
Drei zentrale Scene-Typen:
|
||||||
|
|
||||||
|
**1. `Room.tscn`** (Basisscene)
|
||||||
|
- Hintergrundbild
|
||||||
|
- Spawnpoints für Figuren
|
||||||
|
- Array von `InteractiveObject`-Nodes
|
||||||
|
- Camera-Grenzen
|
||||||
|
|
||||||
|
**2. `InteractiveObject.tscn`**
|
||||||
|
- Sprite mit mehreren Zuständen (z.B. Röntgengerät: idle/scanning/result)
|
||||||
|
- `DraggableArea2D` für Drag-Erkennung
|
||||||
|
- `Action`-Signal (z.B. wenn Häschen draufgelegt wird)
|
||||||
|
- Sound-Trigger
|
||||||
|
|
||||||
|
**3. `Character.tscn`**
|
||||||
|
- AnimatedSprite2D (idle, walking, happy, sick, sleeping)
|
||||||
|
- `DraggableComponent`
|
||||||
|
- State-Enum: healthy / sick / pregnant / baby / tired
|
||||||
|
|
||||||
|
### 3.2 Datenmodell
|
||||||
|
|
||||||
|
```gdscript
|
||||||
|
# character_data.gd (Resource)
|
||||||
|
class_name CharacterData extends Resource
|
||||||
|
|
||||||
|
@export var id: String
|
||||||
|
@export var display_name: String
|
||||||
|
@export var species: String # "bunny", "kitten"
|
||||||
|
@export var age: String # "baby", "adult", "pregnant"
|
||||||
|
@export var current_room: String
|
||||||
|
@export var position: Vector2
|
||||||
|
@export var state: String # "idle", "sick", "sleeping"
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3.3 Save-System
|
||||||
|
|
||||||
|
Godot hat `FileAccess` und Resource-Serialisierung built-in:
|
||||||
|
|
||||||
|
```gdscript
|
||||||
|
# save_manager.gd
|
||||||
|
func save_game():
|
||||||
|
var state = {
|
||||||
|
"characters": get_tree().get_nodes_in_group("characters").map(
|
||||||
|
func(c): return c.to_dict()
|
||||||
|
),
|
||||||
|
"objects": get_tree().get_nodes_in_group("savable_objects").map(
|
||||||
|
func(o): return o.to_dict()
|
||||||
|
),
|
||||||
|
"version": 1
|
||||||
|
}
|
||||||
|
var file = FileAccess.open("user://savegame.json", FileAccess.WRITE)
|
||||||
|
file.store_string(JSON.stringify(state))
|
||||||
|
```
|
||||||
|
|
||||||
|
Auto-Save nach jeder Interaktion (die Kinder werden die App einfach schließen).
|
||||||
|
|
||||||
|
### 3.4 Core Systems
|
||||||
|
|
||||||
|
| System | Komplexität | Notizen |
|
||||||
|
|---|---|---|
|
||||||
|
| Drag & Drop | Mittel | `_unhandled_input` + `Area2D.input_event` |
|
||||||
|
| Raum-Navigation | Niedrig | Scene-Switch oder Camera-Pan |
|
||||||
|
| Zustand von Objekten | Niedrig | Enum + Sprite-Wechsel |
|
||||||
|
| Sound | Niedrig | `AudioStreamPlayer2D` pro Raum |
|
||||||
|
| Save/Load | Niedrig | JSON in `user://` |
|
||||||
|
| Tutorial | Mittel | Einmaliger Hinweis beim ersten Start |
|
||||||
|
| Settings-Menü | Niedrig | Lautstärke, Sprache, Reset |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. Content-Umfang
|
||||||
|
|
||||||
|
### 4.1 Räume (12 Stück)
|
||||||
|
|
||||||
|
| Etage | Raum | Objekte | Besonderheit |
|
||||||
|
|---|---|---|---|
|
||||||
|
| EG | Empfang | Tresen, Wartebereich, Nummernanzeige | Einstiegspunkt |
|
||||||
|
| EG | Geschenke-Shop | Blumen, Kuscheltiere, Karten | Einfach |
|
||||||
|
| EG | Restaurant | 3 Menüs, Tische | Essen als Interaktion |
|
||||||
|
| EG | Notaufnahme | Krankenwagen, OP-Tisch | Dramaturgie |
|
||||||
|
| 1.OG | Röntgen | Röntgengerät, Gips-Station | Coolster Raum für Kinder |
|
||||||
|
| 1.OG | Apotheke | Medikamente (alle gut!) | Ohne "Gift"-Mechanik |
|
||||||
|
| 1.OG | Labor | Mikroskop, Reagenzgläser | Lerneffekt |
|
||||||
|
| 1.OG | Patientenzimmer | 2-3 Betten, TV | Ruhe |
|
||||||
|
| 2.OG | Ultraschall | Gerät, Liege | Süß |
|
||||||
|
| 2.OG | Kreißsaal | OP-Equipment | Sensibel, aber wichtig |
|
||||||
|
| 2.OG | Säuglingsstation | Wiegen, Babys | Kern-Magie |
|
||||||
|
| Extern | Zuhause/Garten | Wiege, Tisch, Geschenke | Gemütlich |
|
||||||
|
|
||||||
|
### 4.2 Figuren (8 Stück für MVP)
|
||||||
|
|
||||||
|
- 2× Erwachsene Häschen (männlich/weiblich)
|
||||||
|
- 2× Erwachsene Kätzchen
|
||||||
|
- 2× Baby-Häschen / Baby-Kätzchen
|
||||||
|
- 2× Ärzte/Pfleger (andere Tierart? → Eule, Fuchs?)
|
||||||
|
|
||||||
|
### 4.3 Interaktive Objekte (~50)
|
||||||
|
|
||||||
|
Typen:
|
||||||
|
- **Geräte** (Röntgen, Ultraschall, Ambulanz) → mehrere Zustände
|
||||||
|
- **Verbrauchsgegenstände** (Pflaster, Medikamente, Essen) → spawn-able
|
||||||
|
- **Möbel** (Betten, Tische, Stühle) → statisch mit Sitz-Slot für Figuren
|
||||||
|
- **Dekoration** (Pflanzen, Bilder) → nur visuell
|
||||||
|
|
||||||
|
### 4.4 Sound
|
||||||
|
|
||||||
|
- Hintergrundmusik pro Etage (ruhige, fröhliche Loops)
|
||||||
|
- Soundeffekte: Krankenwagen-Sirene, Röntgen-Piep, Babygeräusche, Kassenklingel
|
||||||
|
- **Tier-Geräusche** (wichtig!): Häschen-Schnuffeln, Kätzchen-Miau
|
||||||
|
|
||||||
|
**Quelle:** [freesound.org](https://freesound.org), [opengameart.org](https://opengameart.org) — Creative Commons.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. Asset-Strategie (der kritische Teil)
|
||||||
|
|
||||||
|
Hier scheitern die meisten Hobby-Gamedev-Projekte. Drei realistische Wege:
|
||||||
|
|
||||||
|
### Option A: Eigene Kinder als Illustratoren (mein Favorit 💡)
|
||||||
|
- Deine Kinder malen die Häschen, Objekte und Räume auf Papier
|
||||||
|
- Du digitalisierst (Scan + Photoshop/GIMP/Krita → PNG mit Transparenz)
|
||||||
|
- **Vorteil:** Emotionale Bindung, einzigartiger Look, Kinder sind stolz
|
||||||
|
- **Nachteil:** Konsistenz-Herausforderung, mehr Nacharbeit
|
||||||
|
- **Zeitaufwand:** 20-30 Stunden Digitalisierung
|
||||||
|
|
||||||
|
### Option B: Asset-Packs kaufen
|
||||||
|
- [itch.io](https://itch.io/game-assets/tag-2d) — oft €10–50 pro Pack
|
||||||
|
- [Kenney.nl](https://kenney.nl) — kostenlos, hochwertig, aber limitiertes Tier-Angebot
|
||||||
|
- Kombination aus 2–3 Packs + eigene Anpassungen
|
||||||
|
- **Kosten:** €50–200
|
||||||
|
- **Zeitaufwand:** 5–10 Stunden
|
||||||
|
|
||||||
|
### Option C: Freelancer
|
||||||
|
- Fiverr/Upwork: Cartoon-Illustrator mit 2D-Spiele-Erfahrung
|
||||||
|
- 2D-Charakter-Set (8 Figuren, 4 Animationen): €300–800
|
||||||
|
- Hintergründe (12 Räume): €500–1500
|
||||||
|
- **Gesamt:** €800–2300
|
||||||
|
- **Zeitaufwand:** 2–3 Wochen Koordination
|
||||||
|
|
||||||
|
### Option D: KI-gestützt mit Nachbearbeitung
|
||||||
|
- Midjourney / DALL-E / Stable Diffusion für Konzepte
|
||||||
|
- Manuelle Nacharbeit in Krita/GIMP für Konsistenz
|
||||||
|
- **Achtung:** Urheberrecht und Konsistenz-Probleme über Figuren hinweg
|
||||||
|
- **Kosten:** €20 Midjourney-Monat
|
||||||
|
- **Zeitaufwand:** 30–50 Stunden
|
||||||
|
|
||||||
|
**Meine Empfehlung:** **Option A + C hybrid**. Kinder malen die Helden-Figuren (ihre Lieblinge), Freelancer macht die Hintergründe und generische Objekte. Das wird emotional *und* professionell.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. Sprint-Plan (16 Wochen, ca. 8h/Woche)
|
||||||
|
|
||||||
|
Realistisch für einen Vollzeit-Entwickler mit Familie und Side-Projekten. Kürzer geht, wenn du die Abende länger nutzt.
|
||||||
|
|
||||||
|
### Sprint 0: Setup (Woche 1)
|
||||||
|
- [ ] Godot 4 installieren, Android-Export einrichten
|
||||||
|
- [ ] Git-Repo anlegen
|
||||||
|
- [ ] GDScript-Grundlagen durchgehen (Godot-Docs, 3-5h)
|
||||||
|
- [ ] Apple Developer Account falls iOS geplant
|
||||||
|
- [ ] Projektname + Logo-Idee
|
||||||
|
|
||||||
|
### Sprint 1-2: Proof of Concept (Woche 2-3)
|
||||||
|
- [ ] Ein Raum (z.B. Empfang) mit Hintergrund
|
||||||
|
- [ ] Eine Figur (Platzhalter-Häschen) per Drag bewegen
|
||||||
|
- [ ] Ein interaktives Objekt (z.B. Blume pflücken)
|
||||||
|
- [ ] Auf echtem Tablet testen
|
||||||
|
- **Gate:** Funktioniert der Kern-Loop? Finden die Kinder es gut?
|
||||||
|
|
||||||
|
### Sprint 3-4: Core Systems (Woche 4-5)
|
||||||
|
- [ ] Raum-Navigationssystem (Etagen-Wechsel per Aufzug)
|
||||||
|
- [ ] Save/Load-System
|
||||||
|
- [ ] Settings-Menü (Lautstärke, Reset)
|
||||||
|
- [ ] Character-State-System (gesund, krank, schläft)
|
||||||
|
|
||||||
|
### Sprint 5-7: Erdgeschoss (Woche 6-8)
|
||||||
|
- [ ] Empfang komplett
|
||||||
|
- [ ] Geschenke-Shop
|
||||||
|
- [ ] Restaurant
|
||||||
|
- [ ] Notaufnahme mit Krankenwagen-Animation
|
||||||
|
|
||||||
|
### Sprint 8-10: 1. Obergeschoss (Woche 9-11)
|
||||||
|
- [ ] Röntgen mit Slide-Animation
|
||||||
|
- [ ] Apotheke (alle Medikamente positiv!)
|
||||||
|
- [ ] Labor
|
||||||
|
- [ ] Patientenzimmer
|
||||||
|
|
||||||
|
### Sprint 11-13: 2. Obergeschoss (Woche 12-14)
|
||||||
|
- [ ] Ultraschall (sanfte Herzschlag-Animation)
|
||||||
|
- [ ] Kreißsaal (kindgerecht: Mama kommt rein, Baby ist da)
|
||||||
|
- [ ] Säuglingsstation mit Wiegen
|
||||||
|
|
||||||
|
### Sprint 14: Zuhause & Garten (Woche 15)
|
||||||
|
- [ ] Garten-Szene
|
||||||
|
- [ ] Party-Mechanik (Geschenke auspacken, Tee)
|
||||||
|
|
||||||
|
### Sprint 15: Polish & Sound (Woche 16)
|
||||||
|
- [ ] Alle Sounds einbauen
|
||||||
|
- [ ] Hintergrundmusik mit Cross-Fade
|
||||||
|
- [ ] Animations-Feinschliff
|
||||||
|
- [ ] Tutorial / erster Start
|
||||||
|
|
||||||
|
### Sprint 16: Release-Vorbereitung (Woche 17+)
|
||||||
|
- [ ] Icon, Splash Screen
|
||||||
|
- [ ] Play Console Setup, Screenshots, Beschreibung
|
||||||
|
- [ ] Internal Testing mit Kindern
|
||||||
|
- [ ] Release auf Play Store (Android zuerst)
|
||||||
|
- [ ] iOS-Port falls gewünscht
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. Release & Distribution
|
||||||
|
|
||||||
|
### Android (einfacher Start)
|
||||||
|
1. Google Play Developer Account (€25 einmalig)
|
||||||
|
2. Release als **Privat**/Closed Testing zuerst — nur Familie
|
||||||
|
3. Oder: Direkte APK-Distribution in der Familie (kein Store nötig)
|
||||||
|
4. Ggf. später: Öffentlicher Release
|
||||||
|
|
||||||
|
### iOS (später)
|
||||||
|
- Apple Developer Account (€99/Jahr)
|
||||||
|
- TestFlight für Familie
|
||||||
|
- App Store Review deutlich strenger als Google
|
||||||
|
|
||||||
|
### **WICHTIG — COPPA/Kids-Compliance**
|
||||||
|
Da Zielgruppe 3+ Jahre:
|
||||||
|
- Keine Analytics (Google Analytics, Firebase, etc.)
|
||||||
|
- Keine externen Links ohne Parental Gate
|
||||||
|
- Keine personenbezogenen Daten
|
||||||
|
- In der Play Store Data Safety: **"Keine Daten erhoben"** angeben — und das auch umsetzen
|
||||||
|
|
||||||
|
### Monetarisierung
|
||||||
|
**Empfehlung: Keine.** Das ist ein Projekt für deine Kinder. Wenn du später öffentlich willst:
|
||||||
|
- **Einmalkauf €2,99** (fair, keine Werbung)
|
||||||
|
- Keine In-App-Käufe, keine Werbung
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. Risiken & Tipps
|
||||||
|
|
||||||
|
### Größte Fallstricke
|
||||||
|
|
||||||
|
| Risiko | Mitigation |
|
||||||
|
|---|---|
|
||||||
|
| **Asset-Produktion zieht sich** | Mit Platzhaltern entwickeln, Assets parallelisieren |
|
||||||
|
| **iOS-Deployment kompliziert** | Erst Android, iOS später |
|
||||||
|
| **Feature-Creep** | Strikt am MVP-Plan halten, später iterieren |
|
||||||
|
| **Motivation ebbt nach 2 Monaten ab** | Kinder regelmäßig Build zeigen → Feedback = Motor |
|
||||||
|
| **Komplexe Animationen** | Mit einfachen 2-Frame-Animationen starten |
|
||||||
|
|
||||||
|
### Pro-Tipps aus der Praxis
|
||||||
|
|
||||||
|
1. **Kinder sind deine Beta-Tester.** Zeig ihnen jeden Build. Was sie nicht finden, ist zu versteckt. Was sie zum Lachen bringt, behältst du.
|
||||||
|
2. **Finger statt Maus.** Entwickle am Rechner, teste aber wöchentlich auf dem echten Tablet. UI-Elemente brauchen **mindestens 48dp** / besser 64dp Größe.
|
||||||
|
3. **Persistierende Chaos-Toleranz.** Wenn das Kind alle Objekte in eine Ecke stapelt — perfekt. Ladet es genau so wieder. Kein "Ordnen" beim Reset.
|
||||||
|
4. **Bewusste Musik-Lautstärke.** Default auf 60%, nicht 100%. Kinder-Tablets stehen oft auf Max.
|
||||||
|
5. **Großer Zurück-Button immer sichtbar.** Kein Verirren in Untermenüs.
|
||||||
|
6. **Keine Text-UI für Kinder unter 6.** Icons, Symbole, Farben. Text nur für dich als Dev.
|
||||||
|
7. **Idle-Animationen.** Jede Figur blinzelt / atmet auch im Stand. Das macht die Welt lebendig.
|
||||||
|
8. **Sound ist 50% der Magie.** Ein gutes "Ploppen" beim Aufnehmen eines Objekts ist mehr wert als jede Animation.
|
||||||
|
|
||||||
|
### Was ich NICHT machen würde
|
||||||
|
|
||||||
|
- ❌ Multiplayer / Online-Features
|
||||||
|
- ❌ Prozedurale Generierung
|
||||||
|
- ❌ Physik-Engine (nicht nötig für ein Puppenhaus)
|
||||||
|
- ❌ Eigene Character-Editor (Kinder wollen spielen, nicht konfigurieren)
|
||||||
|
- ❌ Level-System / Achievements (widerspricht dem Sandbox-Charakter)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 9. Nächste Schritte (diese Woche)
|
||||||
|
|
||||||
|
1. **Godot 4 installieren** und das offizielle "Your First 2D Game"-Tutorial durchspielen (ca. 2h) — danach verstehst du die Engine
|
||||||
|
2. **Git-Repo anlegen** (lokal oder auf GitHub privat)
|
||||||
|
3. **Ein leeres Projekt** mit `Main.tscn` und einem leeren Raum erstellen
|
||||||
|
4. **Projektnamen** mit den Kindern festlegen — das macht es offiziell
|
||||||
|
5. **Mit den Kindern** 2–3 Figuren-Skizzen auf Papier machen (zum Einscannen später)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 10. Nützliche Ressourcen
|
||||||
|
|
||||||
|
**Godot lernen:**
|
||||||
|
- [Godot Docs — Your first 2D game](https://docs.godotengine.org/en/stable/getting_started/first_2d_game/)
|
||||||
|
- [GDQuest YouTube](https://www.youtube.com/@Gdquest)
|
||||||
|
- [Godot Tours (interaktiv)](https://school.gdquest.com/products/godot-tours-101-the-godot-editor)
|
||||||
|
|
||||||
|
**Assets:**
|
||||||
|
- [Kenney Assets](https://kenney.nl)
|
||||||
|
- [itch.io Game Assets](https://itch.io/game-assets)
|
||||||
|
- [OpenGameArt](https://opengameart.org)
|
||||||
|
|
||||||
|
**Sounds:**
|
||||||
|
- [Freesound](https://freesound.org)
|
||||||
|
- [Zapsplat](https://www.zapsplat.com)
|
||||||
|
|
||||||
|
**Inspiration / Benchmarks:**
|
||||||
|
- Yasa Pets World, Farm, Town (gleiches Studio, anderer Kontext)
|
||||||
|
- Pepi Hospital 2 (4,1 Sterne, sauberer umgesetzt)
|
||||||
|
- Toca Boca Serie (Goldstandard in diesem Genre)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
*Dieser Plan ist ein lebendes Dokument. Anpassen nach jedem Sprint.*
|
||||||
0
localization/.gitkeep
Normal file
0
localization/.gitkeep
Normal file
0
scenes/characters/.gitkeep
Normal file
0
scenes/characters/.gitkeep
Normal file
0
scenes/main/.gitkeep
Normal file
0
scenes/main/.gitkeep
Normal file
0
scenes/objects/.gitkeep
Normal file
0
scenes/objects/.gitkeep
Normal file
0
scenes/rooms/floor0/.gitkeep
Normal file
0
scenes/rooms/floor0/.gitkeep
Normal file
0
scenes/rooms/floor1/.gitkeep
Normal file
0
scenes/rooms/floor1/.gitkeep
Normal file
0
scenes/rooms/floor2/.gitkeep
Normal file
0
scenes/rooms/floor2/.gitkeep
Normal file
0
scenes/rooms/home/.gitkeep
Normal file
0
scenes/rooms/home/.gitkeep
Normal file
0
scenes/ui/.gitkeep
Normal file
0
scenes/ui/.gitkeep
Normal file
0
scripts/autoload/.gitkeep
Normal file
0
scripts/autoload/.gitkeep
Normal file
0
scripts/characters/.gitkeep
Normal file
0
scripts/characters/.gitkeep
Normal file
0
scripts/objects/.gitkeep
Normal file
0
scripts/objects/.gitkeep
Normal file
0
scripts/systems/.gitkeep
Normal file
0
scripts/systems/.gitkeep
Normal file
Reference in New Issue
Block a user