diff --git a/images/Wasser_der_Regierung.PNG b/images/Wasser_der_Regierung.PNG new file mode 100644 index 0000000..91629d3 Binary files /dev/null and b/images/Wasser_der_Regierung.PNG differ diff --git a/images/enemy.png b/images/enemy.png index 065cb41..16e7a45 100644 Binary files a/images/enemy.png and b/images/enemy.png differ diff --git a/images/human.png b/images/human.png new file mode 100644 index 0000000..eee2be6 Binary files /dev/null and b/images/human.png differ diff --git a/images/player.png b/images/player.png index 9f09f2e..7f68258 100644 Binary files a/images/player.png and b/images/player.png differ diff --git a/water-game.py b/water-game.py index 7b1958f..5b592d4 100644 --- a/water-game.py +++ b/water-game.py @@ -1,5 +1,5 @@ # Simple top-down shooter with WASD player, arrow-key enemy, health bar, minimap, and raster background -import pygame, sys, numpy as np, rasterio +import pygame, sys, numpy as np, rasterio, random pygame.init() WIDTH, HEIGHT = 800, 600 @@ -12,6 +12,7 @@ KILL_RADIUS = 30 MINIMAP_SIZE, MINIMAP_MARGIN = 200, 20 PLAYER_IMG_PATH = "images/player.png" ENEMY_IMG_PATH = "images/enemy.png" +HUMAN_IMG_PATH = "images/human.png" MAP_PATH = "results/s2_2025.tif" # Load images @@ -24,6 +25,7 @@ def load_img(path, size): PLAYER_IMAGE = load_img(PLAYER_IMG_PATH, (PLAYER_SIZE, PLAYER_SIZE)) ENEMY_IMAGE = load_img(ENEMY_IMG_PATH, (PLAYER_SIZE, PLAYER_SIZE)) +HUMAN_IMAGE = load_img(HUMAN_IMG_PATH, (PLAYER_SIZE, PLAYER_SIZE)) # Load raster map def load_map(path): try: @@ -55,45 +57,95 @@ class Player: self.x = max(0, min(MAP_W-PLAYER_SIZE, self.x+dx)) self.y = max(0, min(MAP_H-PLAYER_SIZE, self.y+dy)) self.rect.topleft = (self.x, self.y) + def draw(self, win, ox, oy): if not self.alive: return img = PLAYER_IMAGE or None - if img: win.blit(img, (self.x-ox, self.y-oy)) + angle = {"up": 90, "right": 0, "down": -90, "left": 180}[self.dir] + + if img: + rotated_img = pygame.transform.rotate(img, angle) + win.blit(rotated_img, (self.x-ox, self.y-oy)) else: pygame.draw.rect(win, (200,200,0), (self.x-ox, self.y-oy, PLAYER_SIZE, PLAYER_SIZE)) class Enemy: - def __init__(self, x, y): + def __init__(self, x, y,controlled=False): self.x, self.y = x, y - self.rect = pygame.Rect(x, y, PLAYER_SIZE//2, PLAYER_SIZE//2) + self.rect = pygame.Rect(x, y, PLAYER_SIZE, PLAYER_SIZE) self.dir = "up" self.max_health, self.health = 100, 100 - def move(self, keys): - dx = dy = 0 - if keys[pygame.K_UP]: dy -= PLAYER_SPEED; self.dir = "up" - if keys[pygame.K_DOWN]: dy += PLAYER_SPEED; self.dir = "down" - if keys[pygame.K_LEFT]: dx -= PLAYER_SPEED; self.dir = "left" - if keys[pygame.K_RIGHT]: dx += PLAYER_SPEED; self.dir = "right" - self.x = max(0, min(MAP_W-PLAYER_SIZE//2, self.x+dx)) - self.y = max(0, min(MAP_H-PLAYER_SIZE//2, self.y+dy)) - self.rect.topleft = (self.x, self.y) - def draw(self, win, ox, oy): - img = ENEMY_IMAGE or None - if img: win.blit(img, (self.x-ox, self.y-oy)) - else: pygame.draw.rect(win, (200,200,0), (self.x-ox, self.y-oy, PLAYER_SIZE//2, PLAYER_SIZE//2)) - # Health bar - bw, bh = PLAYER_SIZE//2, 6 - ratio = self.health/self.max_health - bx, by = self.x-ox, self.y-oy-bh-2 - pygame.draw.rect(win, (255,0,0), (bx,by,bw,bh)) - pygame.draw.rect(win, (0,255,0), (bx,by,int(bw*ratio),bh)) - def take_damage(self, amt): - self.health = max(0, self.health-amt) - def check_kill_player(self, player): - dx = (self.x+PLAYER_SIZE//4)-(player.x+PLAYER_SIZE//2) - dy = (self.y+PLAYER_SIZE//4)-(player.y+PLAYER_SIZE//2) - if (dx**2+dy**2)**0.5 < KILL_RADIUS: player.alive = False + self.is_human = False + self.controlled = controlled -class WaterBottle: + + + def move(self, keys, player=None): + if self.is_human: + # Move randomly + if random.random() < 0.02: + self.dir = random.choice(["up", "down", "left", "right"]) + dx = dy = 0 + if self.dir == "up": dy -= PLAYER_SPEED//1.5 + if self.dir == "down": dy += PLAYER_SPEED//2 + if self.dir == "left": dx -= PLAYER_SPEED//2 + if self.dir == "right": dx += PLAYER_SPEED//2 + self.x = max(0, min(MAP_W-PLAYER_SIZE//2, self.x+dx)) + self.y = max(0, min(MAP_H-PLAYER_SIZE//2, self.y+dy)) + self.rect.topleft = (self.x, self.y) + elif self.controlled: + dx = dy = 0 + if keys[pygame.K_UP]: dy -= PLAYER_SPEED//1.5; self.dir = "up" + if keys[pygame.K_DOWN]: dy += PLAYER_SPEED//1.5; self.dir = "down" + if keys[pygame.K_LEFT]: dx -= PLAYER_SPEED//1.5; self.dir = "left" + if keys[pygame.K_RIGHT]: dx += PLAYER_SPEED//1.5; self.dir = "right" + self.x = max(0, min(MAP_W-PLAYER_SIZE//2, self.x+dx)) + self.y = max(0, min(MAP_H-PLAYER_SIZE//2, self.y+dy)) + self.rect.topleft = (self.x, self.y) + else: + # Chase the player + if player and player.alive: + dx = player.x - self.x + dy = player.y - self.y + dist = max(1, (dx**2 + dy**2)**0.5) + speed = PLAYER_SPEED//2 + self.x += int(speed * dx / dist) + self.y += int(speed * dy / dist) + self.x = max(0, min(MAP_W-PLAYER_SIZE//2, self.x)) + self.y = max(0, min(MAP_H-PLAYER_SIZE//2, self.y)) + self.rect.topleft = (self.x, self.y) + + + def draw(self, win, ox, oy): + enemy_img = ENEMY_IMAGE or None + human_img = HUMAN_IMAGE or None + color = (0, 128, 255) if self.is_human else (200, 200, 0) + if enemy_img and not self.is_human: + win.blit(enemy_img, (self.x-ox, self.y-oy)) + elif human_img and self.is_human: + win.blit(human_img, (self.x-ox, self.y-oy)) + else: + pygame.draw.rect(win, color, (self.x-ox, self.y-oy, PLAYER_SIZE//2, PLAYER_SIZE//2)) + # Health bar (only for zombie) + if not self.is_human: + bw, bh = PLAYER_SIZE//2, 6 + ratio = self.health/self.max_health + bx, by = self.x-ox, self.y-oy-bh-2 + pygame.draw.rect(win, (255,0,0), (bx,by,bw,bh)) + pygame.draw.rect(win, (0,255,0), (bx,by,int(bw*ratio),bh)) + + def take_damage(self, amt): + if not self.is_human: + self.health = max(0, self.health-amt) + if self.health == 0: + self.is_human = True + + def check_kill_player(self, player): + if not self.is_human: + dx = (self.x+PLAYER_SIZE//4)-(player.x+PLAYER_SIZE//2) + dy = (self.y+PLAYER_SIZE//4)-(player.y+PLAYER_SIZE//2) + if (dx**2+dy**2)**0.5 < KILL_RADIUS: player.alive = False + +class TapWater: def __init__(self, x, y, dir): self.x = x+PLAYER_SIZE//2-WATER_SIZE//2 self.y = y+PLAYER_SIZE//2-WATER_SIZE//2 @@ -108,7 +160,7 @@ class WaterBottle: def draw(self, win, ox, oy): pygame.draw.rect(win, (0,180,255), (self.x-ox, self.y-oy, WATER_SIZE, WATER_SIZE)) -def draw_minimap(win, map_surface, player, enemy, bottles): +def draw_minimap(win, map_surface, player, enemies, bottles): mini = pygame.transform.smoothscale(map_surface, (MINIMAP_SIZE, MINIMAP_SIZE)) win.blit(mini, (WIDTH-MINIMAP_SIZE-MINIMAP_MARGIN, MINIMAP_MARGIN)) def map2mini(x,y): @@ -116,13 +168,22 @@ def draw_minimap(win, map_surface, player, enemy, bottles): my = int(y/MAP_H*MINIMAP_SIZE) return WIDTH-MINIMAP_SIZE-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) - pygame.draw.circle(win, (255,0,0), map2mini(enemy.x+PLAYER_SIZE//4, enemy.y+PLAYER_SIZE//4), 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 b in bottles: pygame.draw.circle(win, (0,180,255), map2mini(b.x, b.y), 3) def main(): player = Player(MAP_W//2, MAP_H//2) - enemy = Enemy(MAP_W//3, MAP_H//3) + # Spawn 20 zombies, only the first is controlled + enemies = [] + for i in range(20): + x = random.randint(0, MAP_W-PLAYER_SIZE) + y = random.randint(0, MAP_H-PLAYER_SIZE) + controlled = (i == 0) + enemies.append(Enemy(x, y, controlled=controlled)) bottles = [] minimap_visible = True clock = pygame.time.Clock() @@ -132,15 +193,16 @@ def main(): for event in pygame.event.get(): if event.type==pygame.QUIT: running=False if event.type==pygame.KEYDOWN: - if event.key==pygame.K_SPACE: bottles.append(WaterBottle(player.x, player.y, player.dir)) + if event.key==pygame.K_SPACE: bottles.append(TapWater(player.x, player.y, player.dir)) if event.key==pygame.K_m: minimap_visible = not minimap_visible keys = pygame.key.get_pressed() player.move(keys) - enemy.move(keys) - enemy.check_kill_player(player) + for enemy in enemies: + enemy.move(keys, player) + enemy.check_kill_player(player) for b in bottles[:]: - b.move() - if enemy.rect.colliderect(b.rect): enemy.take_damage(20); bottles.remove(b) + for enemy in enemies: + if enemy.rect.colliderect(b.rect): enemy.take_damage(20); bottles.remove(b); break bottles = [b for b in bottles if 0<=b.x<=MAP_W and 0<=b.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)) @@ -148,8 +210,10 @@ def main(): else: WIN.fill((255,255,255)) player.draw(WIN, ox, oy) for b in bottles: b.draw(WIN, ox, oy) - enemy.draw(WIN, ox, oy) - if minimap_visible: draw_minimap(WIN, map_surface, player, enemy, bottles) + for enemy in enemies: enemy.draw(WIN, ox, oy) + if minimap_visible: + # Draw all enemies on minimap + draw_minimap(WIN, map_surface, player, enemies, bottles) pygame.display.update() if not player.alive: font = pygame.font.SysFont(None, 48)