Merge branch 'master' of ctpug.org.za:koperkapel
[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 & scene management.
17         """
18
19     def __init__(self, app, scene, world):
20         self._app = app
21         self._scene = scene
22         self._world = world
23         self._viewport = (0, 0)
24
25     def _apply_events(self, events):
26         if not events:
27             return
28         for ev in events:
29             ev.apply(self)
30
31     def change_scene(self, scene):
32         self._apply_events(self._scene.exit(self._world.proxy()))
33         self._scene = scene
34         self._apply_events(self._scene.enter(self._world.proxy()))
35
36     def change_world(self, *args, **kw):
37         self._world.apply_event(*args, **kw)
38
39     def quit_game(self):
40         from pgzero.game import exit
41         exit()
42
43     def move_screen(self, offset):
44         self._viewport = (self._viewport[0] + offset[0],
45                           self._viewport[1] + offset[1])
46
47     @apply_events
48     def update(self, dt):
49         return self._scene.update(self._world.proxy(), dt)
50
51     def draw(self):
52         self._scene.draw(self._app.screen, self._viewport)
53
54     @apply_events
55     def on_mouse_down(self, pos, button):
56         return self._scene.on_mouse_down(pos, button)
57
58     @apply_events
59     def on_mouse_up(self, pos, button):
60         return self._scene.on_mouse_up(pos, button)
61
62     @apply_events
63     def on_key_down(self, key, mod, unicode):
64         return self._scene.on_key_down(key, mod, unicode)
65
66     @apply_events
67     def on_key_up(self, key, mod):
68         return self._scene.on_key_up(key, mod)
69
70     @apply_events
71     def on_music_end(self):
72         return self._scene.on_music_end()
73
74
75 class Event:
76     """ Base class for events. """
77
78     ENGINE_METHOD = "unknown_event"
79
80     def __init__(self, *args, **kw):
81         self._args = args
82         self._kw = kw
83
84     def apply(self, engine):
85         getattr(engine, self.ENGINE_METHOD)(*self._args, **self._kw)
86
87
88 class ChangeSceneEvent(Event):
89     """ Change to a new scene. """
90
91     ENGINE_METHOD = "change_scene"
92
93
94 class WorldEvent(Event):
95     """ Be a hero. Change the world. """
96
97     ENGINE_METHOD = "change_world"
98
99
100 class QuitEvent(Event):
101     """ Quit the game. """
102
103     ENGINE_METHOD = "quit_game"
104
105
106 class MoveViewportEvent(Event):
107     """ Change to a new scene. """
108
109     ENGINE_METHOD = "move_screen"
110
111
112 class Actors:
113     """ A list of actors. """
114
115     def __init__(self):
116         self._actors = []
117
118     def add(self, actor):
119         self._actors.append(actor)
120         return actor
121
122     def remove(self, actor):
123         self._actors.remove(actor)
124         return actor
125
126     def draw(self, screen):
127         for actor in self._actors:
128             actor.draw()  # TODO: allow an option screen to be passed in
129
130
131 class Scene:
132     """ Base class for scenes. """
133
134     def __init__(self):
135         self.actors = Actors()
136
137     def enter(self, world):
138         pass
139
140     def exit(self, world):
141         pass
142
143     def update(self, world, dt):
144         pass
145
146     def draw(self, screen, viewport):
147         screen.clear()
148         self.actors.draw(screen)
149
150     def on_mouse_down(self, pos, button):
151         pass
152
153     def on_mouse_up(self, pos, button):
154         pass
155
156     def on_key_down(self, key, mod, unicode):
157         pass
158
159     def on_key_up(self, key, mod):
160         pass
161
162     def on_music_end(self):
163         pass