From 86312b2106693426d2edf0eebf0ae4156f78a6a7 Mon Sep 17 00:00:00 2001 From: Benjamin Date: Fri, 12 Jun 2026 16:43:28 +0200 Subject: [PATCH] Gegner Bewegung ohne Runterfallen --- editor.py | 13 +++-- game.py | 34 ++++++------ scripts/entities.py | 33 +++++++++-- scripts/particle.py | 17 ++++-- scripts/tilemap.py | 130 +++++++++++++++++++++++++++++--------------- 5 files changed, 151 insertions(+), 76 deletions(-) diff --git a/editor.py b/editor.py index d60279a..f68b940 100644 --- a/editor.py +++ b/editor.py @@ -14,7 +14,9 @@ class Editor: pygame.display.set_caption("Editor") self.screen: pygame.Surface = pygame.display.set_mode((640, 480)) - self.display: pygame.Surface = pygame.Surface((self.screen.get_width()//2, self.screen.get_height()//2)) + self.display: pygame.Surface = pygame.Surface( + (self.screen.get_width() // 2, self.screen.get_height() // 2) + ) self.clock: pygame.time.Clock = pygame.time.Clock() @@ -58,13 +60,13 @@ class Editor: # Scroll-Offset fürs Rendern render_scroll: tuple[int, int] = (int(self.scroll[0]), int(self.scroll[1])) - + self.tilemap.render(surface=self.display, offset=render_scroll) # Aktuelle Kachel (Kopie) - current_tile_img: pygame.Surface = self.assets[self.tile_list[self.tile_group]][ - self.tile_variant - ].copy() + current_tile_img: pygame.Surface = self.assets[ + self.tile_list[self.tile_group] + ][self.tile_variant].copy() # Halbtransparent current_tile_img.set_alpha(100) @@ -243,4 +245,5 @@ class Editor: pygame.quit() sys.exit() + Editor().run() diff --git a/game.py b/game.py index 60aff50..57b8c86 100644 --- a/game.py +++ b/game.py @@ -1,4 +1,4 @@ -import pygame # ty: ignore[unresolved-import] +import pygame # ty: ignore[unresolved-import] import sys import random import math @@ -52,10 +52,12 @@ class Game: "player/wall_slide": Animation( load_images(path="entities/player/wall_slide") ), - - "enemy/idle": Animation(load_images(path="entities/enemy/idle"), image_duration=6), - "enemy/run": Animation(load_images(path="entities/enemy/run"), image_duration=4), - + "enemy/idle": Animation( + load_images(path="entities/enemy/idle"), image_duration=6 + ), + "enemy/run": Animation( + load_images(path="entities/enemy/run"), image_duration=4 + ), "particles/leaf": Animation( load_images(path="particles/leaf"), image_duration=20, loop=False ), @@ -64,7 +66,7 @@ class Game: ), "particles/particle": Animation( load_images(path="particles/particle"), image_duration=6, loop=False - ) + ), } self.player: Player = Player(game=self, pos=(50, 50), size=(8, 15)) @@ -114,7 +116,7 @@ class Game: for rect in self.leaf_spawners: if random.random() * 49999 < rect.width * rect.height: - pos = ( + pos = ( rect.x + random.random() * rect.width, rect.y + random.random() * rect.height, ) @@ -127,8 +129,6 @@ class Game: frame=random.randint(0, 20), ) ) - - self.clouds.update() self.clouds.render(surface=self.display, offset=render_scroll) @@ -147,13 +147,11 @@ class Game: for particle in self.particles.copy(): kill: bool = particle.update() particle.render(self.display, offset=render_scroll) - if particle.type == 'leaf': + if particle.type == "leaf": particle.pos[0] += math.sin(particle.animation.frame * 0.035) * 0.3 if kill: self.particles.remove(particle) - - for event in pygame.event.get(): if event.type == pygame.QUIT: self.running = False @@ -164,13 +162,15 @@ class Game: self.movement[0] = True if event.key == pygame.K_d: self.movement[1] = True - if event.key == pygame.K_SPACE or event.key == pygame.K_w: # and not self.isJumping + if ( + event.key == pygame.K_SPACE or event.key == pygame.K_w + ): # and not self.isJumping self.player.jump() - + if event.key == pygame.K_m: # self.boost = True self.player.boost() - + if event.key == pygame.K_x: self.player.dash() @@ -195,7 +195,5 @@ class Game: sys.exit() - - game = Game() -game.run() \ No newline at end of file +game.run() diff --git a/scripts/entities.py b/scripts/entities.py index 1821df5..4404fd4 100644 --- a/scripts/entities.py +++ b/scripts/entities.py @@ -105,6 +105,7 @@ class PhysicsEntity: image = self.e_type + "/" + self.action self.animation = self.game.assets[image].copy() + class Enemy(PhysicsEntity): def __init__(self, game, pos: tuple[float, float], size: tuple[int, int]): super().__init__(game, "enemy", pos, size) @@ -113,14 +114,27 @@ class Enemy(PhysicsEntity): def update(self, tilemap, movement: tuple[float, float] = (0, 0)): if self.walking: - movement = (movement[0] - 0.5 if self.flip else 0.5, movement[1]) + if tilemap.solid_check( + (self.rect().centerx + (-7 if self.flip else 7), self.pos[1] + 23) + ): + if self.collisions.right or self.collisions.left: + self.flip = not self.flip + else: + movement = (movement[0] - 0.5 if self.flip else 0.5, movement[1]) + else: + self.flip = not self.flip self.walking = max(0, self.walking - 1) elif random.random() < 0.01: self.walking = random.randint(30, 120) super().update(tilemap, movement) - + if movement[0] != 0: + self.set_action("run") + else: + self.set_action("idle") + + class Player(PhysicsEntity): def __init__(self, game, pos: tuple[float, float], size: tuple[int, int]): super().__init__(game, "player", pos, size) @@ -199,7 +213,15 @@ class Player(PhysicsEntity): 0, ] - self.game.particles.append(Particle(self.game, "particle", self.rect().center, particle_velocity, random.randint(0, 7))) + self.game.particles.append( + Particle( + self.game, + "particle", + self.rect().center, + particle_velocity, + random.randint(0, 7), + ) + ) if self.velocity[0] > 0: self.velocity[0] = max(self.velocity[0] - 0.1, 0) @@ -220,7 +242,7 @@ class Player(PhysicsEntity): self.air_time = 5 self.jumps = max(0, self.jumps - 1) - elif self.jumps > 0: + elif self.jumps > 0: # and not self.dashing self.velocity[1] = -3 self.jumps -= 1 self.air_time = 5 @@ -246,7 +268,6 @@ class Player(PhysicsEntity): else: self.dashing = 60 - def render(self, surface, offset=(0, 0)): if abs(self.dashing) <= 50: - super().render(surface, offset) \ No newline at end of file + super().render(surface, offset) diff --git a/scripts/particle.py b/scripts/particle.py index 6cb6f2d..5cd796a 100644 --- a/scripts/particle.py +++ b/scripts/particle.py @@ -4,12 +4,19 @@ from scripts.animation import Animation class Particle: - def __init__(self, game, p_type: str, pos: tuple[float, float], velocity: list[float] = [0, 0], frame: int = 0): + def __init__( + self, + game, + p_type: str, + pos: tuple[float, float], + velocity: list[float] = [0, 0], + frame: int = 0, + ): self.game = game self.type: str = p_type self.pos: list[float] = list(pos) self.velocity: list[float] = list(velocity) - self.animation: Animation = self.game.assets['particles/' + p_type].copy() + self.animation: Animation = self.game.assets["particles/" + p_type].copy() self.animation.frame = frame def update(self) -> bool: @@ -24,7 +31,9 @@ class Particle: return kill - def render(self, surface: pygame.Surface, offset: tuple[float, float] = (0, 0)) -> None: + def render( + self, surface: pygame.Surface, offset: tuple[float, float] = (0, 0) + ) -> None: img = self.animation.img() surface.blit( img, @@ -32,4 +41,4 @@ class Particle: self.pos[0] - offset[0] - img.get_width() // 2, self.pos[1] - offset[1] - img.get_height() // 2, ), - ) \ No newline at end of file + ) diff --git a/scripts/tilemap.py b/scripts/tilemap.py index 05fa01e..0edd105 100644 --- a/scripts/tilemap.py +++ b/scripts/tilemap.py @@ -14,9 +14,20 @@ AUTOTILE_MAP: dict[tuple[tuple[int, int], ...], int] = { tuple(sorted([(1, 0), (-1, 0), (0, 1), (0, -1)])): 8, } -NEIGHBOR_OFFSETS: list[tuple[int, int]] = [(-1, 0), (-1, -1), (0, -1), (1, -1), (1, 0), (0, 0), (-1, 1), (0, 1), (1, 1)] -PHYSICS_TILES: set[str] = {'grass', 'stone'} -AUTOTILE_TYPES: set[str] = {'grass', 'stone'} +NEIGHBOR_OFFSETS: list[tuple[int, int]] = [ + (-1, 0), + (-1, -1), + (0, -1), + (1, -1), + (1, 0), + (0, 0), + (-1, 1), + (0, 1), + (1, 1), +] +PHYSICS_TILES: set[str] = {"grass", "stone"} +AUTOTILE_TYPES: set[str] = {"grass", "stone"} + class Tilemap: def __init__(self, game, tile_size: int = 16) -> None: @@ -24,8 +35,10 @@ class Tilemap: self.tile_size: int = tile_size self.tilemap: dict[str, Tile] = {} self.offgrid_tiles: list[Tile] = [] - - def extract(self, id_pairs: list[tuple[str, int]], keep: bool = False) -> list[dict]: + + def extract( + self, id_pairs: list[tuple[str, int]], keep: bool = False + ) -> list[dict]: matches: list[dict] = [] for tile in self.offgrid_tiles.copy(): if (tile.type, tile.variant) in id_pairs: @@ -37,7 +50,10 @@ class Tilemap: tilemap_tile = self.tilemap[loc] if (tilemap_tile.type, tilemap_tile.variant) in id_pairs: end_match = tilemap_tile.to_dict() - end_match["pos"] = [end_match['pos'][0] * self.tile_size, end_match['pos'][1] * self.tile_size] + end_match["pos"] = [ + end_match["pos"][0] * self.tile_size, + end_match["pos"][1] * self.tile_size, + ] matches.append(end_match) @@ -47,80 +63,108 @@ class Tilemap: def tiles_around(self, pos: tuple[float, float]) -> list[Tile]: tiles: list[Tile] = [] - tile_location: tuple[int, int] = (int(pos[0] // self.tile_size), int(pos[1] // self.tile_size)) + tile_location: tuple[int, int] = ( + int(pos[0] // self.tile_size), + int(pos[1] // self.tile_size), + ) for offset in NEIGHBOR_OFFSETS: - check_location: str = str(tile_location[0] + offset[0]) + ';' + str(tile_location[1] + offset[1]) + check_location: str = ( + str(tile_location[0] + offset[0]) + + ";" + + str(tile_location[1] + offset[1]) + ) if check_location in self.tilemap: tiles.append(self.tilemap[check_location]) return tiles - + def save(self, path: str) -> None: data: dict = { - 'tilemap': { - k: tile.to_dict() for k, tile in self.tilemap.items() - }, - 'tile_size': self.tile_size, - 'offgrid': [ - tile.to_dict() for tile in self.offgrid_tiles - ], + "tilemap": {k: tile.to_dict() for k, tile in self.tilemap.items()}, + "tile_size": self.tile_size, + "offgrid": [tile.to_dict() for tile in self.offgrid_tiles], } - with open(path, 'w') as f: + with open(path, "w") as f: json.dump(data, f) - - + def load(self, path: str) -> None: - with open(path, 'r') as f: + with open(path, "r") as f: map_data = json.load(f) - - self.tile_size: int = map_data['tile_size'] + + self.tile_size: int = map_data["tile_size"] # Grid-Tiles: Dict -> Tile-Objekte self.tilemap: dict[str, Tile] = {} - for key, tile_data in map_data['tilemap'].items(): + for key, tile_data in map_data["tilemap"].items(): self.tilemap[key] = Tile.from_dict(tile_data) - + # Offgrid-Tiles: Dict -> Tile-Objekte self.offgrid_tiles: list[Tile] = [ - Tile.from_dict(t) for t in map_data['offgrid'] + Tile.from_dict(t) for t in map_data["offgrid"] ] + def solid_check(self, pos: tuple[float, float]): + tile_loc = ( + str(int(pos[0] // self.tile_size)) + + ";" + + str(int(pos[1] // self.tile_size)) + ) + if tile_loc in self.tilemap: + if self.tilemap[tile_loc].type in PHYSICS_TILES: + return self.tilemap[tile_loc] + def physics_rects_around(self, pos: tuple[float, float]) -> list[pygame.Rect]: rects: list[pygame.Rect] = [] for tile in self.tiles_around(pos): if tile.type in PHYSICS_TILES: - rects.append(pygame.Rect(tile.pos[0] * self.tile_size, tile.pos[1] * self.tile_size, self.tile_size, self.tile_size)) + rects.append( + pygame.Rect( + tile.pos[0] * self.tile_size, + tile.pos[1] * self.tile_size, + self.tile_size, + self.tile_size, + ) + ) return rects - + def autotile(self): for loc in self.tilemap: tile: Tile = self.tilemap[loc] neighbors: set[tuple[int, int]] = set() for shift in [(1, 0), (-1, 0), (0, -1), (0, 1)]: - check_loc: str = str(tile.pos[0] + shift[0]) + ';' + str(tile.pos[1] + shift[1]) + check_loc: str = ( + str(tile.pos[0] + shift[0]) + ";" + str(tile.pos[1] + shift[1]) + ) if check_loc in self.tilemap: if self.tilemap[check_loc].type == tile.type: neighbors.add(shift) neighbors: tuple[tuple[int, int], ...] = tuple(sorted(neighbors)) if (tile.type in AUTOTILE_TYPES) and (neighbors in AUTOTILE_MAP): tile.variant = AUTOTILE_MAP[neighbors] - - def render(self, surface: pygame.Surface, offset: tuple[float, float] = (0, 0)) -> None: + + def render( + self, surface: pygame.Surface, offset: tuple[float, float] = (0, 0) + ) -> None: for tile in self.offgrid_tiles: surface.blit( - self.game.assets[tile.type][tile.variant], - (tile.pos[0] - offset[0], tile.pos[1] - offset[1]) + self.game.assets[tile.type][tile.variant], + (tile.pos[0] - offset[0], tile.pos[1] - offset[1]), ) - - for x in range(offset[0] // self.tile_size, - (offset[0] + surface.get_width()) // self.tile_size + 1): - for y in range(offset[1] // self.tile_size, - (offset[1] + surface.get_height()) // self.tile_size + 1): - location_key: str = str(x) + ';' + str(y) + + for x in range( + offset[0] // self.tile_size, + (offset[0] + surface.get_width()) // self.tile_size + 1, + ): + for y in range( + offset[1] // self.tile_size, + (offset[1] + surface.get_height()) // self.tile_size + 1, + ): + location_key: str = str(x) + ";" + str(y) if location_key in self.tilemap: tile: Tile = self.tilemap[location_key] surface.blit( - self.game.assets[tile.type][tile.variant], - ( - tile.pos[0] * self.tile_size - offset[0], - tile.pos[1] * self.tile_size - offset[1]) - ) + self.game.assets[tile.type][tile.variant], + ( + tile.pos[0] * self.tile_size - offset[0], + tile.pos[1] * self.tile_size - offset[1], + ), + )