added zombie list
This commit is contained in:
parent
44a42901c6
commit
7b9d7734ab
5 changed files with 104 additions and 40 deletions
BIN
images/Wasser_der_Regierung.PNG
Normal file
BIN
images/Wasser_der_Regierung.PNG
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.9 MiB |
BIN
images/enemy.png
BIN
images/enemy.png
Binary file not shown.
|
Before Width: | Height: | Size: 44 KiB After Width: | Height: | Size: 44 KiB |
BIN
images/human.png
Normal file
BIN
images/human.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 88 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 2.2 KiB After Width: | Height: | Size: 2.6 KiB |
144
water-game.py
144
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)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue