/
Vibek
/
First_Game
Обзор
Документация
Войти
/
Vibek
/
First_Game
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
CI/CD
Аналитика
Безопасность
master
core/game.py
191 строка
7 KB
Vibek
все перменные перенесены в конфиг, отрисовка динамическая
21 июн 2026, 20:32
21 июн 2026, 20:32
f32a834
Код
Авторство
О чём код?
""" Главный класс игры (Game Loop). Отвечает за инициализацию PyGame, управление состояниями (FSM) и цикл отрисовки. """ import sys import pygame from core.config import Config from core.display_manager import DisplayManager from core.events import EventBus from utils.fsm import StateMachine from resources.asset_manager import AssetManager from resources.sound_manager import SoundManager, NullSound class Game: """ Основной класс приложения. Управляет жизненным циклом игры. """ def __init__(self): """Инициализация подсистем.""" pygame.init() pygame.display.set_caption(Config.TITLE) self.fullscreen = Config.Display.FULLSCREEN self.screen = self._create_window() self.clock = pygame.time.Clock() self.running = True self.display = DisplayManager(Config.Design.WIDTH, Config.Design.HEIGHT) self.display.update_layout(self.screen.get_size()) self.game_surface = self.display.game_surface self.fsm = StateMachine() self.bus = EventBus() self.assets = AssetManager() self.assets.load_all() try: self.sound = SoundManager(self.bus) except Exception as exc: print(f"[Game] Sound init failed, continuing without audio: {exc}") self.sound = NullSound() self._setup_listeners() self._setup_states() print("Game initialized successfully.") def _window_flags(self) -> int: flags = 0 if Config.Display.RESIZABLE: flags |= pygame.RESIZABLE if self.fullscreen: flags |= pygame.FULLSCREEN return flags def _create_window(self) -> pygame.Surface: flags = self._window_flags() if self.fullscreen: return pygame.display.set_mode((0, 0), flags) return pygame.display.set_mode( (Config.Display.DEFAULT_WINDOW_WIDTH, Config.Display.DEFAULT_WINDOW_HEIGHT), flags, ) def _toggle_fullscreen(self) -> None: self.fullscreen = not self.fullscreen self.screen = self._create_window() self.display.update_layout(self.screen.get_size()) def _handle_display_events(self, events: list[pygame.event.Event]) -> None: for event in events: if event.type == pygame.VIDEORESIZE and not self.fullscreen: self.screen = pygame.display.set_mode(event.size, self._window_flags()) self.display.update_layout(self.screen.get_size()) elif event.type == pygame.KEYDOWN and event.key == pygame.K_F11: self._toggle_fullscreen() def _setup_listeners(self): """Настройка слушателей EventBus.""" self.bus.subscribe("app:quit", self._on_quit_request) def _setup_states(self): """Регистрация состояний с внедрением зависимостей (DI).""" from views.states.menu_state import MenuState from views.states.intro_ago_state import IntroAgoState from views.states.intro_crawl_state import IntroCrawlState from views.states.playing_state import PlayingState from views.states.upgrade_state import UpgradeState from views.states.victory_state import VictoryState self.fsm.add_state(MenuState(self.game_surface, self.bus, self.display)) self.bus.subscribe(Config.EVT_APP_GAME_START, self._on_start_game) self.bus.subscribe(Config.EVT_APP_GAME_OVER, self._on_game_over) self.bus.subscribe(Config.EVT_APP_VICTORY, self._on_victory) self.bus.subscribe(Config.EVT_APP_VICTORY_DISMISS, self._on_victory_dismiss) self.bus.subscribe(Config.EVT_APP_INTRO_CRAWL, self._on_intro_crawl) self.bus.subscribe(Config.EVT_APP_INTRO_FINISHED, self._on_intro_finished) self.bus.subscribe("app:resume_game", self._on_resume_game) self.fsm.add_state(IntroAgoState(self.game_surface, self.bus)) self.fsm.add_state(IntroCrawlState(self.game_surface, self.bus)) self.fsm.add_state(PlayingState(self.game_surface, self.bus, self.assets, self.display)) self.fsm.add_state(UpgradeState(self.game_surface, self.bus, self.display)) self.fsm.add_state(VictoryState(self.game_surface, self.bus)) self.bus.subscribe(Config.EVT_APP_SHOW_UPGRADES, self._on_show_upgrades) def _on_quit_request(self, _data=None): """Обработчик запроса выхода.""" self.running = False def run(self): """Главный игровой цикл.""" print("Game Loop started.") self.fsm.switch_state("MENU") self.sound.play_state_music("MENU") while self.running: dt = self.clock.tick(Config.FPS) / 1000.0 events = pygame.event.get() for event in events: if event.type == pygame.QUIT: self.running = False self._handle_display_events(events) self.game_surface.fill(Config.BLACK) self.fsm.update(dt, events) self.fsm.render(self.game_surface) self.display.present(self.screen) pygame.display.flip() self.quit() def _on_start_game(self, _data=None): """Запуск intro-цепочки перед первой волной.""" self.fsm.switch_state("INTRO_AGO") def _on_intro_crawl(self, _data=None) -> None: print("[Game] Switching to INTRO_CRAWL state.") self.fsm.switch_state("INTRO_CRAWL") def _on_intro_finished(self, _data=None) -> None: """Intro завершён — начинаем новую игровую сессию.""" print("[Game] Intro finished. Starting gameplay.") self.bus.emit(Config.EVT_APP_NEW_GAME_SESSION) self.fsm.switch_state("Playing") def _on_game_over(self, _data=None) -> None: """ Перехватывает сигнал конца игры от PlayingState. Безопасно переключает FSM в MENU. """ print("[Game] Received app:game_over. Switching to MENU.") try: self.fsm.switch_state("MENU") except ValueError as e: print(f"[Game] FSM Switch Error: {e}") def _on_victory(self, _data=None) -> None: print("[Game] Victory achieved. Showing ending.") self.fsm.switch_state("VICTORY") def _on_victory_dismiss(self, _data=None) -> None: print("[Game] Victory dismissed. Returning to MENU.") self.fsm.switch_state("MENU") self.sound.play_state_music("MENU") def _on_resume_game(self, _data=None) -> None: """Возврат в игру после экрана улучшений.""" print("[Game] Resuming game after upgrade.") self.fsm.switch_state("Playing") def quit(self): """Корректное завершение.""" print("Game shutting down...") if hasattr(self, "sound") and self.sound is not None: self.sound.dispose() pygame.quit() sys.exit() def _on_show_upgrades(self, _data=None) -> None: """Переход к экрану улучшений после волны.""" print("[Game] Switching to UPGRADE state.") self.fsm.switch_state("UPGRADE")