/
kiraru
/
DeadBlocks
Обзор
Документация
Войти
/
kiraru
/
DeadBlocks
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
controllers/game_controller.py
237 строк
7 KB
kiraru
маленький фикс + коментарии
23 июн 2026, 09:51
23 июн 2026, 09:51
516b2d4
Код
Авторство
О чём код?
# game_controller.py связывает модель, ввод и системы import pygame from constants import Screen, ENEMY_BUFF_INTERVAL from models.game_state import GameState from systems.collision import CollisionSystem from systems.save_system import SaveSystem from controllers.input_handler import InputState class GameController: """ обновляет GameState на основе InputState. вся игровая логика одного кадра. """ def __init__(self, game_state: GameState, save_system: SaveSystem): self._gs = game_state self._save = save_system self._collision = CollisionSystem() # главный метод обновления def update(self, input_state: InputState, dt: float) -> None: gs = self._gs # глобальные команды if input_state.quit: pygame.quit() raise SystemExit if gs.current_screen == Screen.GAMEPLAY: if input_state.pause: gs.current_screen = Screen.PAUSE gs.is_paused = True return if not gs.is_paused: self._update_gameplay(input_state, dt) elif gs.current_screen == Screen.PAUSE: self._update_pause(input_state) # геймплей def _update_gameplay(self, inp: InputState, dt: float) -> None: gs = self._gs player = gs.player if player is None or not player.is_alive: gs.set_game_over() self._save.delete() return # обновляем таймер игры (для глобальных баффов врагов и чумы) gs.elapsed_time += dt # глобальный уровень баффа вычисляется из общего времени игры — global_buff_count = int(gs.elapsed_time / ENEMY_BUFF_INTERVAL) for room in gs.rooms: for enemy in room.enemies: if enemy.is_alive: enemy.apply_global_buff(global_buff_count) # ввод игрока self._apply_player_input(inp, player) # физика и коллизии игрока room = self._current_room() if room is None: return player.update(dt) CollisionSystem.resolve(player, room, dt) CollisionSystem.keep_in_bounds(player, room) # атака игрока if player.is_attacking and not player.has_dealt_damage_this_attack: attack_rect = player.get_attack_rect() hits = CollisionSystem.check_attack_hits(attack_rect, room.enemies) for enemy in hits: enemy.take_damage(player.damage, player.damage_type) player.has_dealt_damage_this_attack = True # враги self._update_enemies(room, player, dt) touching = CollisionSystem.check_player_enemy_overlap(player.rect, room.enemies) for enemy in touching: if enemy.try_attack(player.rect): player.take_damage(enemy.damage) # переход в следующую комнату if CollisionSystem.is_on_exit(player.rect, room): self._try_advance_room() # сундуки on_chest, chest_pos = CollisionSystem.is_on_chest(player.rect, room) if on_chest and inp.interact and chest_pos in room.chest_positions: from systems.level_generator import Tile room.chest_positions.remove(chest_pos) room.set_tile(chest_pos[0], chest_pos[1], Tile.FLOOR) # убираем сундук gs.prepare_artifact_choice() gs.current_screen = Screen.ARTIFACT # cмерть игрока if not player.is_alive: gs.set_game_over() self._save.delete() def _apply_player_input(self, inp: InputState, player) -> None: if not player.is_alive: return # движение if inp.move_left and not inp.move_right: direction = -1 elif inp.move_right and not inp.move_left: direction = 1 else: direction = 0 if inp.run: player.start_run() else: player.stop_run() player.move(direction) if inp.jump: player.jump() if inp.attack: player.attack() def _update_enemies(self, room, player, dt: float) -> None: for enemy in room.enemies: if not enemy.is_alive: continue enemy.update(dt, player.rect) CollisionSystem.resolve(enemy, room, dt) CollisionSystem.keep_in_bounds(enemy, room) def _try_advance_room(self) -> None: """дверь просто переводит в следующую комнату, если все враги убиты""" gs = self._gs room = self._current_room() if room is None: return # все враги убиты? alive = [e for e in room.enemies if e.is_alive] if alive: return # дверь заблокирована # босс убит — победа if room.is_boss_room: gs.set_victory() return self._enter_next_room() def _enter_next_room(self) -> None: gs = self._gs gs.advance_to_next_room() room = self._current_room() if room is None: return # переместить игрока на точку спавна новой комнаты wx, wy = room.player_spawn_world() player = gs.player player.rect.x = wx player.rect.y = wy player.velocity_x = 0.0 player.velocity_y = 0.0 def apply_chosen_artifact(self, artifact_index: int) -> None: """применить артефакт, выбранный в сундуке, и вернуться в геймплей""" self._gs.apply_chosen_artifact(artifact_index) self._gs.current_screen = Screen.GAMEPLAY def _update_pause(self, inp: InputState) -> None: gs = self._gs if inp.pause or inp.cancel: gs.current_screen = Screen.GAMEPLAY gs.is_paused = False # публичные экраны def cmd_start_new_game(self, difficulty: str) -> None: from systems.level_generator import LevelGenerator import random gs = self._gs gs.start_new_game(difficulty) seed = random.randint(0, 999999) gen = LevelGenerator(difficulty, gs.boss_weak_type, seed=seed) gs.rooms = gen.generate_all_rooms() # поставить игрока на спавн первой комнаты room = gs.rooms[0] wx, wy = room.player_spawn_world() gs.player.rect.x = wx gs.player.rect.y = wy def cmd_load_game(self) -> bool: return self._save.load(self._gs) def cmd_save_game(self) -> bool: return self._save.save(self._gs) def cmd_resume(self) -> None: gs = self._gs gs.is_paused = False gs.current_screen = Screen.GAMEPLAY def cmd_go_to_main_menu(self) -> None: self._gs.current_screen = Screen.MAIN_MENU def cmd_quit(self) -> None: pygame.quit() raise SystemExit # утилита def _current_room(self): gs = self._gs if not gs.rooms: return None idx = gs.current_room_index return gs.rooms[idx] if 0 <= idx < len(gs.rooms) else None