cdec/water-game.py
2025-10-12 14:09:27 +02:00

276 lines
9.3 KiB
Python

import sys
import random
import pygame
import numpy as np
import rasterio
from player import Player
from enemy import Enemy
from tapwater import TapWater
from settings import PLAYER_SIZE, MAP_PATH, WIDTH, HEIGHT, MINIMAP_MARGIN
DEBUG = False
MAX_AMMO = 5
def play_video(win, video_path):
"""Play video with audio - extracts audio and plays with pygame mixer"""
import cv2
import os
import tempfile
try:
# Extract audio from video to temporary file
audio_path = None
try:
from moviepy import VideoFileClip
print("Extracting audio from video...")
video = VideoFileClip(video_path)
if video.audio:
temp_audio = tempfile.NamedTemporaryFile(delete=False, suffix='.mp3')
audio_path = temp_audio.name
temp_audio.close()
video.audio.write_audiofile(audio_path, logger=None)
print(f"Audio extracted to: {audio_path}")
# Play audio
pygame.mixer.init()
pygame.mixer.music.load(audio_path)
pygame.mixer.music.play()
print("Audio playback started")
else:
print("No audio track found in video")
video.close()
except Exception as e:
print(f"Audio extraction warning: {e}") # Play video
cap = cv2.VideoCapture(video_path)
if not cap.isOpened():
print(f"Error: Could not open video file: {video_path}")
return
clock = pygame.time.Clock()
running = True
win_size = win.get_size()
frame_count = 0
while running and cap.isOpened():
ret, frame = cap.read()
if not ret:
break
frame_count += 1
frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
# Transpose for pygame (width, height) format
frame = frame.swapaxes(0, 1)
frame_surface = pygame.surfarray.make_surface(frame)
frame_surface = pygame.transform.smoothscale(frame_surface, win_size)
win.blit(frame_surface, (0, 0))
pygame.display.update()
for event in pygame.event.get():
if event.type == pygame.KEYDOWN or event.type == pygame.QUIT:
running = False
if audio_path:
pygame.mixer.music.stop()
clock.tick(30)
cap.release()
if audio_path:
pygame.mixer.music.stop()
print(f"Played {frame_count} video frames")
# Clean up temp audio file
if audio_path and os.path.exists(audio_path):
try:
os.unlink(audio_path)
except:
pass
except Exception as e:
print(f"Video playback error: {e}")
print("Skipping video...")
trinkbrunnen_positions = np.load('trinkbrunnen_pixel_positions.npy')
# Nach dem Laden der Positionen:
used_brunnen = [False] * len(trinkbrunnen_positions)
pygame.init()
# logo_img = pygame.image.load("images/logo.png")
# pygame.display.set_icon(logo_img)
WIN = pygame.display.set_mode((WIDTH, HEIGHT))
pygame.display.set_caption("Wasser der Regierung")
logo_img = pygame.image.load("images/Wasser_der_Regierung.PNG")
pygame.display.set_icon(logo_img)
def load_map(path):
try:
arr = rasterio.open(path).read(1)
arr = np.nan_to_num(arr - 272.15, nan=0)
arr = np.clip(arr, np.percentile(arr, 5), np.percentile(arr, 95))
arr = ((arr - arr.min()) / (arr.max() - arr.min()) * 255).astype(np.uint8)
arr = np.stack([arr, arr, arr], -1)
surf = pygame.surfarray.make_surface(arr)
return surf, arr.shape[1], arr.shape[0]
except Exception as e:
print(f"Map load error: {e}")
return None, WIDTH, HEIGHT
map_surface, MAP_W, MAP_H = load_map(MAP_PATH)
DIST_FACTOR = 2.0 # 2.0 = doppelte Entfernung, 1.0 = Standard
# Karte vergrößern
scaled_map = pygame.transform.smoothscale(map_surface, (int(MAP_W * DIST_FACTOR), int(MAP_H * DIST_FACTOR)))
WIN.blit(scaled_map, (0, 0))
MINIMAP_WIDTH = 200
MINIMAP_HEIGHT = int(MAP_H / MAP_W * MINIMAP_WIDTH)
def draw_minimap(win, map_surface, player, enemies, kranwasser):
mini = pygame.transform.smoothscale(map_surface, (MINIMAP_WIDTH, MINIMAP_HEIGHT))
win.blit(mini, (WIDTH - MINIMAP_WIDTH - MINIMAP_MARGIN, MINIMAP_MARGIN))
def map2mini(x, y):
mx = int(x / MAP_W * MINIMAP_WIDTH)
my = int(y / MAP_H * MINIMAP_HEIGHT)
return WIDTH - MINIMAP_WIDTH - MINIMAP_MARGIN + mx, MINIMAP_MARGIN + my
pygame.draw.circle(win, (0, 255, 0), map2mini(player.x + PLAYER_SIZE // 2, player.y + PLAYER_SIZE // 2), 5)
for enemy in enemies:
color = (0, 128, 255) if enemy.is_human else (255, 0, 0) if enemy.controlled else (200, 200, 0)
ex, ey = map2mini(enemy.x + PLAYER_SIZE // 4, enemy.y + PLAYER_SIZE // 4)
pygame.draw.circle(win, color, (ex, ey), 5)
for wasser in kranwasser:
pygame.draw.circle(win, (0, 180, 255), map2mini(wasser.x, wasser.y), 3)
def show_title_screen(win):
title = pygame.image.load("images/Wasser_der_Regierung.PNG")
title = pygame.transform.smoothscale(title, (WIDTH, HEIGHT))
win.blit(title,(0,0))
pygame.display.update()
pygame.time.wait(3000)
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(5000)
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(5000)
def main():
from settings import PLAYER_IMG_PATH, ENEMY_IMG_PATH, HUMAN_IMG_PATH, PLAYER_SIZE, load_img
player_img = load_img(PLAYER_IMG_PATH, (PLAYER_SIZE, PLAYER_SIZE))
enemy_img = load_img(ENEMY_IMG_PATH, (PLAYER_SIZE, PLAYER_SIZE))
human_img = load_img(HUMAN_IMG_PATH, (PLAYER_SIZE, PLAYER_SIZE))
player = Player(MAP_W // 2, MAP_H // 2, player_img)
enemies = [
Enemy(random.randint(0, MAP_W - PLAYER_SIZE), random.randint(0, MAP_H - PLAYER_SIZE), enemy_img, human_img,
i == 0) for i in range(20)]
kranwasser = []
minimap_visible = True
clock = pygame.time.Clock()
play_video(WIN, "videos/test.mov")
show_title_screen(WIN)
running = True
while running:
clock.tick(60)
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_SPACE:
if player.ammo > 0:
kranwasser.append(TapWater(player.x, player.y, player.dir))
player.ammo -= 1
else:
print("Keine Munition!")
if event.key == pygame.K_m:
minimap_visible = not minimap_visible
keys = pygame.key.get_pressed()
player.move(keys, MAP_W, MAP_H)
for enemy in enemies:
enemy.move(keys, player, MAP_W, MAP_H)
enemy.check_kill_player(player)
for wasser in kranwasser[:]:
for enemy in enemies:
if enemy.rect.colliderect(wasser.rect):
enemy.take_damage(20)
kranwasser.remove(wasser)
break
kranwasser = [w for w in kranwasser if 0 <= w.x <= MAP_W and 0 <= w.y <= MAP_H]
ox = max(0, min(player.x + PLAYER_SIZE // 2 - WIDTH // 2, MAP_W - WIDTH))
oy = max(0, min(player.y + PLAYER_SIZE // 2 - HEIGHT // 2, MAP_H - HEIGHT))
if scaled_map:
WIN.blit(scaled_map, (0, 0), area=pygame.Rect(ox, oy, WIDTH, HEIGHT))
else:
WIN.fill((255, 255, 255))
for px, py in trinkbrunnen_positions:
pygame.draw.circle(WIN, (0, 0, 0), (px - ox, py - oy), 4)
player.draw(WIN, ox, oy)
for wasser in kranwasser:
wasser.draw(WIN, ox, oy)
for enemy in enemies:
enemy.draw(WIN, ox, oy)
if minimap_visible:
draw_minimap(WIN, map_surface, player, enemies, kranwasser)
player_rect = pygame.Rect(player.x, player.y, PLAYER_SIZE, PLAYER_SIZE)
# Beim Auffüllen:
for i, (px, py) in enumerate(trinkbrunnen_positions):
brunnen_rect = pygame.Rect(px, py, 20, 20)
if player_rect.colliderect(brunnen_rect) and not used_brunnen[i] and player.ammo < MAX_AMMO:
player.ammo += 3
used_brunnen[i] = True # Brunnen blockieren
font = pygame.font.SysFont(None, 32)
ammo_text = font.render(f"Wasser: {player.ammo}", True, (0, 0, 255))
WIN.blit(ammo_text, (20, 20))
pygame.display.update()
if not player.alive:
show_lose_screen(WIN)
running = False
elif all(not e.alive or e.health <= 0 for e in enemies):
show_win_screen(WIN)
running = False
pygame.quit()
sys.exit()
if __name__ == "__main__":
main()