Mercurial > skaapsteker
view skaapsteker/engine.py @ 632:0675f390653c
Initial port to Python 3 and Pygame 2.
author | Simon Cross <hodgestar@gmail.com> |
---|---|
date | Fri, 20 Jan 2023 20:01:06 +0100 |
parents | fb9258d66137 |
children |
line wrap: on
line source
"""Top-level engine for switching scenes.""" import os import pygame.display import pygame.time import pygame.event from pygame.locals import QUIT, USEREVENT from . import options class Engine(object): def __init__(self, soundsystem): # avoid circular imports from .gamestate import GameState self._framerate = 60 self._current_scene = None self._fpss = [self._framerate] * 100 self._cur_frame = 0 self.game_state = GameState(os.path.join(options['save_location'], 'savegame.json')) if self.game_state.can_resume(): self.game_state.load_game() self.soundsystem = soundsystem def change_scene(self, next_scene): self.game_state.save_game() self.soundsystem.stop_music() if self._current_scene is not None: self._current_scene.leave() self._current_scene = next_scene self._current_scene.enter() def run(self): """Run the game loop dispatching events as necessary.""" assert self._current_scene is not None clock = pygame.time.Clock() surface = pygame.display.get_surface() while True: events = pygame.event.get() for ev in events: if ev.type == QUIT: return if ChangeScene.matches(ev): next_scene = ev.next_scene if not isinstance(next_scene, Scene): next_scene = next_scene[0](self.game_state, self.soundsystem, *(next_scene[1:])) self.change_scene(next_scene) break self._current_scene.dispatch(ev) self._current_scene.draw(surface, self) pygame.display.flip() self._fpss[self._cur_frame] = 1000.0 / clock.tick(self._framerate) self._cur_frame = self._cur_frame + 1 if self._cur_frame < 99 else 0 def get_fps(self): return sum(self._fpss) / 100 class Scene(object): def __init__(self, game_state, soundsystem): self.widgets = [] self.game_state = game_state self._soundsystem = soundsystem def post(self, ev): """Post an event to pygame's event loop.""" pygame.event.post(ev) def enter(self): """Enter the scene.""" pass def leave(self): """Exit the scene.""" pass def dispatch(self, ev): """Dispatch an event.""" for widget in self.widgets: widget.dispatch(ev) def draw(self, surface, engine): """Update the scene surface.""" for widget in self.widgets: widget.draw(surface) class UserEvent(object): utype = "UNKNOWN" @classmethod def post(cls, **kws): ev = pygame.event.Event(USEREVENT, utype=cls.utype, **kws) pygame.event.post(ev) @classmethod def matches(cls, ev): return ev.type == USEREVENT and ev.utype == cls.utype class ChangeScene(UserEvent): utype = "CHANGE_SCENE" @classmethod def post(cls, next_scene): super(ChangeScene, cls).post(next_scene=next_scene) class PlayerDied(UserEvent): utype = "PLAYER_DIED" @classmethod def post(cls): super(PlayerDied, cls).post() class OpenDialog(UserEvent): utype = "OPEN_DIALOG" @classmethod def post(cls, npc): # request to open dialog box for given NPC sprite # will do nothing if the NPC's current state has # no text super(OpenDialog, cls).post(npc=npc) class OpenNotification(UserEvent): utype = "OPEN_NOTIFICATION" @classmethod def post(cls, text): # request to open dialog box for given NPC sprite # will do nothing if the NPC's current state has # no text super(OpenNotification, cls).post(text=text) class CloseDialog(UserEvent): utype = "CLOSE_DIALOG" @classmethod def post(cls, npc): # close dialog box for given NPC sprite # will do nothing if the sprite has no dialog open super(CloseDialog, cls).post(npc=npc) class NpcEvent(UserEvent): # TODO: Needed? utype = "NPC_EVENT" @classmethod def post(cls, npc, ev): """npc is an NPC sprite. ev is a DsmEvent for that sprite. """ super(NpcEvent, cls).post(npc=npc, ev=ev) class GlobalNpcEvent(UserEvent): # TODO: Needed? utype = "GLOBAL_NPC_EVENT" @classmethod def post(cls, ev): """Send a DsmEvent event to all NPCs. """ super(GlobalNpcEvent, cls).post(ev=ev) class AddSpriteEvent(UserEvent): utype = "ADD_SPRITE_EVENT" @classmethod def post(cls, item): """Put a Sprite into the world. """ super(AddSpriteEvent, cls).post(item=item)