Move viewport management down into the engine and add suitable events. Cache initial...
[koperkapel.git] / koperkapel / scenes / base.py
1 """ Scene utilities. """
2
3 import functools
4
5
6 def apply_events(f):
7     """ Decorator that applies events to an engine. """
8     @functools.wraps(f)
9     def wrap(self, *args, **kw):
10         events = f(self, *args, **kw)
11         self._apply_events(events)
12     return wrap
13
14
15 class Engine:
16     """ A holder for game state. """
17
18     def __init__(self, app, scene):
19         self._app = app
20         self._scene = scene
21         self._viewport = (0, 0)
22
23     def _apply_events(self, events):
24         if not events:
25             return
26         for ev in events:
27             ev.apply(self)
28
29     def change_scene(self, scene):
30         self._scene.exit()
31         self._scene = scene
32         self._scene.enter()
33
34     def quit_game(self):
35         from pgzero.game import exit
36         exit()
37
38     def move_screen(self, offset):
39         self._viewport = (self._viewport[0] + offset[0],
40                             self._viewport[1] + offset[1])
41
42     @apply_events
43     def update(self, dt):
44         return self._scene.update(dt)
45
46     def draw(self):
47         self._scene.draw(self._app.screen, self._viewport)
48
49     @apply_events
50     def on_mouse_down(self, pos, button):
51         return self._scene.on_mouse_down(pos, button)
52
53     @apply_events
54     def on_mouse_up(self, pos, button):
55         return self._scene.on_mouse_up(pos, button)
56
57     @apply_events
58     def on_key_down(self, key, mod, unicode):
59         return self._scene.on_key_down(key, mod, unicode)
60
61     @apply_events
62     def on_key_up(self, key, mod):
63         return self._scene.on_key_up(key, mod)
64
65     @apply_events
66     def on_music_end(self):
67         return self._scene.on_music_end()
68
69
70 class Event:
71     """ Base class for events. """
72
73     ENGINE_METHOD = "unknown_event"
74
75     def __init__(self, *args, **kw):
76         self._args = args
77         self._kw = kw
78
79     def apply(self, engine):
80         getattr(engine, self.ENGINE_METHOD)(*self._args, **self._kw)
81
82
83 class ChangeSceneEvent(Event):
84     """ Change to a new scene. """
85
86     ENGINE_METHOD = "change_scene"
87
88
89 class QuitEvent(Event):
90     """ Quit the game. """
91
92     ENGINE_METHOD = "quit_game"
93
94
95 class MoveViewportEvent(Event):
96     """ Change to a new scene. """
97
98     ENGINE_METHOD = "move_screen"
99
100
101 class Actors:
102     """ A list of actors. """
103
104     def __init__(self):
105         self._actors = []
106
107     def add(self, actor):
108         self._actors.append(actor)
109         return actor
110
111     def remove(self, actor):
112         self._actors.remove(actor)
113         return actor
114
115     def draw(self, screen):
116         for actor in self._actors:
117             actor.draw()  # TODO: allow an option screen to be passed in
118
119
120 class Scene:
121     """ Base class for scenes. """
122
123     def __init__(self):
124         self.actors = Actors()
125
126     def enter(self):
127         pass
128
129     def exit(self):
130         pass
131
132     def update(self, dt):
133         pass
134
135     def draw(self, screen, viewport):
136         screen.clear()
137         self.actors.draw(screen)
138
139     def on_mouse_down(self, pos, button):
140         pass
141
142     def on_mouse_up(self, pos, button):
143         pass
144
145     def on_key_down(self, key, mod, unicode):
146         pass
147
148     def on_key_up(self, key, mod):
149         pass
150
151     def on_music_end(self):
152         pass