305 lines
9.6 KiB
Markdown
305 lines
9.6 KiB
Markdown
# Tipps & Hinweise
|
|
|
|
## Titelbild und Logo einfügen
|
|
|
|
- Ein Logo macht das Spiel persönlicher! Die Funktion zum Laden eines Logos ist im Code vorbereitet, aber aktuell deaktiviert.
|
|
- Die Kids können später ein eigenes Logo als `images/logo.png` erstellen und die folgende Zeile in `water-game.py` aktivieren:
|
|
|
|
```python
|
|
# logo_img = pygame.image.load("images/logo.png")
|
|
# pygame.display.set_icon(logo_img)
|
|
```
|
|
|
|
- Tipp: Das Logo sollte quadratisch und als PNG gespeichert sein.
|
|
- So kann jeder sein eigenes Spiel-Icon gestalten!
|
|
|
|
## Titelbildschirm, Gewinn- und Verlustbildschirm
|
|
|
|
- Implementiere einen Titelbildschirm und zeige bei Spielende einen Gewinn- oder Verlustbildschirm (siehe Codebeispiel unten).
|
|
|
|
**Beispiel für Titelbildschirm und Gewinn/Verlust:**
|
|
|
|
```python
|
|
# Titelbildschirm anzeigen
|
|
show_title_screen(WIN)
|
|
# ...
|
|
if win_condition:
|
|
show_win_screen(WIN)
|
|
elif lose_condition:
|
|
show_lose_screen(WIN)
|
|
```
|
|
|
|
**So kannst du Gewinn- und Verlustbildschirme umsetzen:**
|
|
|
|
1. Schreibe eine Funktion, die den Bildschirm einfärbt und einen Text anzeigt:
|
|
|
|
```python
|
|
def show_win_screen(win):
|
|
win.fill((40, 180, 80))
|
|
font = pygame.font.SysFont(None, 72)
|
|
text = font.render("Gewonnen!", True, (255, 255, 255))
|
|
win.blit(text, (win.get_width() // 2 - text.get_width() // 2, win.get_height() // 2 - text.get_height() // 2))
|
|
pygame.display.update()
|
|
pygame.time.wait(2500)
|
|
|
|
def show_lose_screen(win):
|
|
win.fill((180, 40, 40))
|
|
font = pygame.font.SysFont(None, 72)
|
|
text = font.render("Verloren!", True, (255, 255, 255))
|
|
win.blit(text, (win.get_width() // 2 - text.get_width() // 2, win.get_height() // 2 - text.get_height() // 2))
|
|
pygame.display.update()
|
|
pygame.time.wait(2500)
|
|
```
|
|
|
|
2. Rufe die jeweilige Funktion auf, wenn die Gewinn- oder Verlustbedingung erfüllt ist:
|
|
|
|
```python
|
|
if win_condition:
|
|
show_win_screen(WIN)
|
|
elif lose_condition:
|
|
show_lose_screen(WIN)
|
|
```
|
|
|
|
- Die Bedingungen kannst du selbst festlegen, z.B. alle Gegner besiegt = Gewinn, Spieler tot = Verlust.
|
|
- Nach dem Bildschirm kannst du das Spiel beenden oder neu starten.
|
|
|
|
## Trinkbrunnen-Pixelpositionen ins Spiel laden und anzeigen
|
|
|
|
- Die Datei `trinkbrunnen_pixel_positions.npy` enthält alle Trinkbrunnen-Positionen als Pixelkoordinaten.
|
|
- So lädst du die Positionen und zeichnest die Trinkbrunnen im Spiel:
|
|
|
|
**Schritt 1: Importiere numpy und lade die Datei**
|
|
|
|
```python
|
|
import numpy as np
|
|
trinkbrunnen_positions = np.load('trinkbrunnen_pixel_positions.npy')
|
|
```
|
|
|
|
**Schritt 2: Zeichne die Trinkbrunnen in der Spielschleife**
|
|
|
|
```python
|
|
for px, py in trinkbrunnen_positions:
|
|
pygame.draw.circle(WIN, (0, 180, 255), (px - ox, py - oy), 10)
|
|
```
|
|
|
|
- `ox` und `oy` sind die Offsets für das Kamerascrolling (falls verwendet).
|
|
- Die Farbe `(0, 180, 255)` ist ein helles Blau, der Radius `10` kann angepasst werden.
|
|
|
|
**Schritt 3: Interaktion mit Trinkbrunnen**
|
|
|
|
- Um z.B. Munition aufzufüllen, prüfe ob der Spieler einen Trinkbrunnen berührt:
|
|
|
|
```python
|
|
player_rect = pygame.Rect(player.x, player.y, PLAYER_SIZE, PLAYER_SIZE)
|
|
for px, py in trinkbrunnen_positions:
|
|
brunnen_rect = pygame.Rect(px, py, 20, 20) # Größe anpassen
|
|
if player_rect.colliderect(brunnen_rect):
|
|
player.ammo = MAX_AMMO
|
|
```
|
|
|
|
- So werden die Trinkbrunnen sichtbar und interaktiv im Spiel!
|
|
|
|
## Die Karte größer machen (Abstandsfaktor)
|
|
|
|
- Wenn du möchtest, dass die Karte größer wirkt und die Abstände zwischen den Trinkbrunnen (und anderen Objekten) wachsen, kannst du einen "Abstandsfaktor" einführen.
|
|
- Damit werden alle Positionen und die Kartengröße mit einem Faktor multipliziert, sodass die Karte gestreckt wird und die Wege länger werden.
|
|
|
|
**So geht's:**
|
|
|
|
**Wo und wie den Abstandsfaktor einbauen?**
|
|
|
|
1. **Definiere den Abstandsfaktor ganz oben in deiner Hauptdatei (z.B. `water-game.py`):**
|
|
|
|
```python
|
|
DIST_FACTOR = 2.0 # Beispielwert, kann angepasst werden
|
|
```
|
|
|
|
2. **Wende den Faktor direkt nach dem Laden der Daten an:**
|
|
|
|
- Nachdem du die Trinkbrunnen-Positionen und ggf. die Spieler-/Gegner-Positionen geladen hast, multipliziere sie mit dem Abstandsfaktor:
|
|
|
|
```python
|
|
# Nach dem Laden der Trinkbrunnen-Positionen
|
|
trinkbrunnen_positions = np.load('trinkbrunnen_pixel_positions.npy')
|
|
trinkbrunnen_positions = [(int(px * DIST_FACTOR), int(py * DIST_FACTOR)) for px, py in trinkbrunnen_positions]
|
|
|
|
# Spieler und Gegner ebenfalls anpassen (direkt nach deren Initialisierung):
|
|
player.x *= DIST_FACTOR
|
|
player.y *= DIST_FACTOR
|
|
for enemy in enemies:
|
|
enemy.x *= DIST_FACTOR
|
|
enemy.y *= DIST_FACTOR
|
|
```
|
|
|
|
3. **Beim Rendern der Karte:**
|
|
|
|
- Skaliere die Karte beim Anzeigen:
|
|
|
|
```python
|
|
scaled_map = pygame.transform.smoothscale(map_surface, (int(MAP_W * DIST_FACTOR), int(MAP_H * DIST_FACTOR)))
|
|
WIN.blit(scaled_map, (0, 0))
|
|
```
|
|
|
|
**Tipp:**
|
|
|
|
- Der Abstandsfaktor sollte immer am Anfang und nur einmal auf die Positionen angewendet werden, damit alle Objekte synchron gestreckt werden.
|
|
- Passe ggf. auch die Spielfeldgröße (`WIDTH`, `HEIGHT`) an, wenn die Karte sehr groß wird.
|
|
|
|
## Schnelles Skalieren der Karte nach dem Laden
|
|
|
|
- Statt alle Positionen und Objekte zu multiplizieren, kannst du die Karte direkt nach dem Laden einmalig skalieren und die Originalkoordinaten beibehalten.
|
|
- Das ist viel schneller und spart Rechenzeit!
|
|
|
|
**So geht's:**
|
|
|
|
1. **Karte nach dem Laden skalieren:**
|
|
|
|
```python
|
|
DIST_FACTOR = 2.0 # Beispielwert
|
|
|
|
# Nach dem Laden der Karte (z.B. map_surface):
|
|
scaled_map = pygame.transform.smoothscale(map_surface, (int(MAP_W * DIST_FACTOR), int(MAP_H * DIST_FACTOR)))
|
|
```
|
|
|
|
2. **Beim Rendern die Karte und alle Objekte mit dem Faktor verschieben:**
|
|
|
|
```python
|
|
WIN.blit(scaled_map, (0, 0))
|
|
for px, py in trinkbrunnen_positions:
|
|
pygame.draw.circle(WIN, (0, 180, 255), (int(px * DIST_FACTOR), int(py * DIST_FACTOR)), 10)
|
|
# Spieler, Gegner usw. ebenfalls mit DIST_FACTOR multiplizieren, aber nur beim Zeichnen!
|
|
```
|
|
|
|
- Die Positionsdaten bleiben im Speicher unverändert, nur die Darstellung wird gestreckt.
|
|
- Das ist besonders bei großen Karten und vielen Objekten viel performanter.
|
|
- Du kannst den Abstandsfaktor jederzeit ändern, ohne die Originaldaten zu verlieren.
|
|
|
|
## .exe erstellen (Windows)
|
|
|
|
**Kurzanleitung auf Deutsch:**
|
|
|
|
1. Installiere PyInstaller:
|
|
|
|
```sh
|
|
pip install pyinstaller
|
|
```
|
|
|
|
2. Konvertiere dein Logo zu einer `.ico`-Datei (z.B. mit [favicon.io](https://favicon.io/)).
|
|
3. Erstelle die .exe:
|
|
|
|
```sh
|
|
pyinstaller --onefile --windowed --icon=images/logo.ico water-game.py
|
|
```
|
|
|
|
4. Die ausführbare Datei findest du im `dist`-Ordner.
|
|
|
|
## Mac: App als ausführbare Datei erstellen
|
|
|
|
**Kurzanleitung auf Deutsch:**
|
|
|
|
1. Installiere PyInstaller:
|
|
|
|
```sh
|
|
pip install pyinstaller
|
|
```
|
|
|
|
2. Erstelle die Mac-App:
|
|
|
|
```sh
|
|
pyinstaller --onefile --windowed --icon=images/logo.png water-game.py
|
|
```
|
|
|
|
- Das Icon kann als PNG verwendet werden.
|
|
- Die App wird im `dist`-Ordner als ausführbare Datei erscheinen.
|
|
|
|
3. (Optional) Um eine echte Mac-App zu erzeugen, nutze das Flag `--name` und `--osx-bundle-identifier`:
|
|
|
|
```sh
|
|
pyinstaller --onefile --windowed --icon=images/logo.png --name=WasserGame --osx-bundle-identifier=com.deinname.wassergame water-game.py
|
|
```
|
|
|
|
**Hinweis:**
|
|
|
|
- Die App kann per Doppelklick gestartet werden.
|
|
- Für die Verteilung an andere Macs kann eine Code-Signierung und Notarisierung nötig sein (siehe [Apple Doku](https://developer.apple.com/documentation/xcode/notarizing_macos_software_before_distribution)).
|
|
|
|
## Tipp: Intro-Video vor Spielstart abspielen
|
|
|
|
- Du kannst ein Video (z.B. MP4) als Intro vor dem eigentlichen Spiel abspielen.
|
|
- Nutze dazu z.B. die Bibliothek [`pygame-vlc`](https://github.com/pygame/pygame-vlc) oder [`opencv-python`](https://pypi.org/project/opencv-python/) zum Abspielen von Videos im Pygame-Fenster.
|
|
|
|
**Beispiel mit pygame-vlc:**
|
|
|
|
```python
|
|
import vlc
|
|
import pygame
|
|
|
|
def play_intro_video(win, video_path):
|
|
instance = vlc.Instance()
|
|
player = instance.media_player_new()
|
|
media = instance.media_new(video_path)
|
|
player.set_media(media)
|
|
player.set_xwindow(win.get_window_id()) # Für Linux, für Windows/Mac ggf. anpassen
|
|
player.play()
|
|
# Warte bis das Video fertig ist oder eine Taste gedrückt wird
|
|
playing = True
|
|
while playing:
|
|
for event in pygame.event.get():
|
|
if event.type == pygame.KEYDOWN or event.type == pygame.QUIT:
|
|
player.stop()
|
|
playing = False
|
|
pygame.time.wait(100)
|
|
```
|
|
|
|
- Das Video kann z.B. als `intro.mp4` im Projektordner liegen.
|
|
- Nach dem Intro kannst du wie gewohnt den Titelbildschirm anzeigen.
|
|
- Für Windows/Mac kann die Fenster-ID Methode abweichen, siehe Doku von pygame-vlc.
|
|
|
|
## Munition für den Spieler und Anzeige als Counter
|
|
|
|
- So fügst du dem Spieler eine Munition-Variable hinzu und zeigst sie als Counter im Spiel an:
|
|
|
|
**1. Munition im Player anlegen:**
|
|
|
|
- Ergänze die Player-Klasse um ein Attribut, z.B.:
|
|
|
|
```python
|
|
class Player:
|
|
def __init__(self, x, y, image):
|
|
self.x = x
|
|
self.y = y
|
|
self.image = image
|
|
self.ammo = 10 # Startwert für Munition
|
|
# ...
|
|
```
|
|
|
|
**2. Munition beim Schießen verringern:**
|
|
|
|
```python
|
|
if player.ammo > 0:
|
|
bottles.append(TapWater(player.x, player.y, player.dir))
|
|
player.ammo -= 1
|
|
else:
|
|
print("Keine Munition!")
|
|
```
|
|
|
|
**3. Munition beim Berühren eines Trinkbrunnens auffüllen:**
|
|
|
|
```python
|
|
MAX_AMMO = 10
|
|
# ...
|
|
if player_rect.colliderect(brunnen_rect):
|
|
player.ammo = MAX_AMMO
|
|
```
|
|
|
|
**4. Munition als Counter im HUD anzeigen:**
|
|
|
|
- Im Haupt-Draw-Loop nach dem Zeichnen der Spielfläche:
|
|
|
|
```python
|
|
font = pygame.font.SysFont(None, 32)
|
|
ammo_text = font.render(f"Wasser: {player.ammo}", True, (0, 0, 255))
|
|
WIN.blit(ammo_text, (20, 20))
|
|
```
|
|
|
|
- So sieht der Spieler immer, wie viel Munition noch übrig ist!
|