X-Git-Url: https://git.ctpug.org.za/?a=blobdiff_plain;f=koperkapel%2Fscenes%2Fbase.py;h=d0b9a951ae16c57e20e279560f54fd9ab8a7b7a4;hb=1df183b924e272541198f34c1ebb3d33406192a6;hp=859f816e6359249e8dfbdc61e36f24b4699fcc44;hpb=8631d4fcb6dbc05c0f8f8283f1740ef6ca835ed1;p=koperkapel.git diff --git a/koperkapel/scenes/base.py b/koperkapel/scenes/base.py index 859f816..d0b9a95 100644 --- a/koperkapel/scenes/base.py +++ b/koperkapel/scenes/base.py @@ -1,44 +1,164 @@ """ Scene utilities. """ +import functools + + +def apply_events(f): + """ Decorator that applies events to an engine. """ + @functools.wraps(f) + def wrap(self, *args, **kw): + events = f(self, *args, **kw) + self._apply_events(events) + return wrap + class Engine: - """ A holder for game state. """ + """ A holder for game state & scene management. + """ - def __init__(self, app, scene): + def __init__(self, app, scene, world): self._app = app self._scene = scene + self._world = world + self._viewport = (0, 0) + + def _apply_events(self, events): + if not events: + return + for ev in events: + ev.apply(self) + + def change_scene(self, scene): + self._apply_events(self._scene.exit(self._world.proxy())) + self._scene = scene + self._apply_events(self._scene.enter(self._world.proxy())) + def change_world(self, *args, **kw): + self._world.apply_event(*args, **kw) + + def quit_game(self): + from pgzero.game import exit + exit() + + def move_screen(self, offset): + self._viewport = (self._viewport[0] + offset[0], + self._viewport[1] + offset[1]) + + @apply_events def update(self, dt): - self._scene.update(dt) + return self._scene.update(self._world.proxy(), dt) def draw(self): - self._scene.draw(self._app.screen) + self._scene.draw(self._app.screen, self._viewport) + @apply_events def on_mouse_down(self, pos, button): - self._scene.on_mouse_down(pos, button) + return self._scene.on_mouse_down(pos, button) + @apply_events def on_mouse_up(self, pos, button): - self._scene.on_mouse_up(pos, button) + return self._scene.on_mouse_up(pos, button) + @apply_events def on_key_down(self, key, mod, unicode): - self._scene.on_key_down(key, mod, unicode) + return self._scene.on_key_down(key, mod, unicode) + @apply_events def on_key_up(self, key, mod): - self._scene.on_key_up(key, mod) + return self._scene.on_key_up(key, mod) + @apply_events def on_music_end(self): - self._scene.on_music_end() + return self._scene.on_music_end() + + +class Event: + """ Base class for events. """ + + ENGINE_METHOD = "unknown_event" + + def __init__(self, *args, **kw): + self._args = args + self._kw = kw + + def apply(self, engine): + getattr(engine, self.ENGINE_METHOD)(*self._args, **self._kw) + + +class ChangeSceneEvent(Event): + """ Change to a new scene. """ + + ENGINE_METHOD = "change_scene" + + +class WorldEvent(Event): + """ Be a hero. Change the world. """ + + ENGINE_METHOD = "change_world" + + +class QuitEvent(Event): + """ Quit the game. """ + + ENGINE_METHOD = "quit_game" + + +class MoveViewportEvent(Event): + """ Change to a new scene. """ + + ENGINE_METHOD = "move_screen" + + +class Actors: + """ A list of actors. + + Actors may be rendered in different layers. Layers with lower levels + are rendered lower than layers with higher ones. + """ + + def __init__(self): + self._layer_order = [] + self._layers = {} + self.add_layer("default", 0) + + def add_layer(self, name, level): + self._layer_order.append((level, name)) + self._layer_order.sort() + self._layers[name] = [] + + def add(self, actor, layer="default"): + self._layers[layer].append(actor) + return actor + + def remove(self, actor, layer="default"): + self._layers[layer].remove(actor) + return actor + + def draw(self, screen): + for lvl, layer in self._layer_order: + for actor in self._layers[layer]: + actor.draw() # TODO: allow an option screen to be passed in class Scene: """ Base class for scenes. """ - def update(self, dt): + def __init__(self): + self.actors = Actors() + + def enter(self, world): pass - def draw(self, screen): + def exit(self, world): pass + def update(self, world, dt): + pass + + def draw(self, screen, viewport): + screen.clear() + self.actors.draw(screen) + def on_mouse_down(self, pos, button): pass