source: skaapsteker/engine.py

Last change on this file was 479:fb9258d66137, checked in by Stefano Rivera <stefano@…>, 12 years ago

New Main Menu

File size: 4.7 KB
Line 
1"""Top-level engine for switching scenes."""
2
3import os
4
5import pygame.display
6import pygame.time
7import pygame.event
8from pygame.locals import QUIT, USEREVENT
9
10from . import options
11
12
13class Engine(object):
14
15 def __init__(self, soundsystem):
16 # avoid circular imports
17 from .gamestate import GameState
18 self._framerate = 60
19 self._current_scene = None
20 self._fpss = [self._framerate] * 100
21 self._cur_frame = 0
22 self.game_state = GameState(os.path.join(options['save_location'], 'savegame.json'))
23 if self.game_state.can_resume():
24 self.game_state.load_game()
25 self.soundsystem = soundsystem
26
27 def change_scene(self, next_scene):
28 self.game_state.save_game()
29 self.soundsystem.stop_music()
30 if self._current_scene is not None:
31 self._current_scene.leave()
32 self._current_scene = next_scene
33 self._current_scene.enter()
34
35 def run(self):
36 """Run the game loop dispatching events as necessary."""
37 assert self._current_scene is not None
38 clock = pygame.time.Clock()
39 surface = pygame.display.get_surface()
40 while True:
41 events = pygame.event.get()
42 for ev in events:
43 if ev.type is QUIT:
44 return
45 if ChangeScene.matches(ev):
46 next_scene = ev.next_scene
47 if not isinstance(next_scene, Scene):
48 next_scene = next_scene[0](self.game_state, self.soundsystem, *(next_scene[1:]))
49 self.change_scene(next_scene)
50 break
51 self._current_scene.dispatch(ev)
52 self._current_scene.draw(surface, self)
53 pygame.display.flip()
54 self._fpss[self._cur_frame] = 1000.0 / clock.tick(self._framerate)
55 self._cur_frame = self._cur_frame + 1 if self._cur_frame < 99 else 0
56
57 def get_fps(self):
58 return sum(self._fpss) / 100
59
60
61class Scene(object):
62
63 def __init__(self, game_state, soundsystem):
64 self.widgets = []
65 self.game_state = game_state
66 self._soundsystem = soundsystem
67
68 def post(self, ev):
69 """Post an event to pygame's event loop."""
70 pygame.event.post(ev)
71
72 def enter(self):
73 """Enter the scene."""
74 pass
75
76 def leave(self):
77 """Exit the scene."""
78 pass
79
80 def dispatch(self, ev):
81 """Dispatch an event."""
82 for widget in self.widgets:
83 widget.dispatch(ev)
84
85 def draw(self, surface, engine):
86 """Update the scene surface."""
87 for widget in self.widgets:
88 widget.draw(surface)
89
90
91class UserEvent(object):
92
93 utype = "UNKNOWN"
94
95 @classmethod
96 def post(cls, **kws):
97 ev = pygame.event.Event(USEREVENT, utype=cls.utype, **kws)
98 pygame.event.post(ev)
99
100 @classmethod
101 def matches(cls, ev):
102 return ev.type is USEREVENT and ev.utype == cls.utype
103
104
105class ChangeScene(UserEvent):
106
107 utype = "CHANGE_SCENE"
108
109 @classmethod
110 def post(cls, next_scene):
111 super(ChangeScene, cls).post(next_scene=next_scene)
112
113class PlayerDied(UserEvent):
114
115 utype = "PLAYER_DIED"
116
117 @classmethod
118 def post(cls):
119 super(PlayerDied, cls).post()
120
121class OpenDialog(UserEvent):
122
123 utype = "OPEN_DIALOG"
124
125 @classmethod
126 def post(cls, npc):
127 # request to open dialog box for given NPC sprite
128 # will do nothing if the NPC's current state has
129 # no text
130 super(OpenDialog, cls).post(npc=npc)
131
132class OpenNotification(UserEvent):
133
134 utype = "OPEN_NOTIFICATION"
135
136 @classmethod
137 def post(cls, text):
138 # request to open dialog box for given NPC sprite
139 # will do nothing if the NPC's current state has
140 # no text
141 super(OpenNotification, cls).post(text=text)
142
143class CloseDialog(UserEvent):
144
145 utype = "CLOSE_DIALOG"
146
147 @classmethod
148 def post(cls, npc):
149 # close dialog box for given NPC sprite
150 # will do nothing if the sprite has no dialog open
151 super(CloseDialog, cls).post(npc=npc)
152
153class NpcEvent(UserEvent): # TODO: Needed?
154
155 utype = "NPC_EVENT"
156
157 @classmethod
158 def post(cls, npc, ev):
159 """npc is an NPC sprite.
160 ev is a DsmEvent for that sprite.
161 """
162 super(NpcEvent, cls).post(npc=npc, ev=ev)
163
164class GlobalNpcEvent(UserEvent): # TODO: Needed?
165
166 utype = "GLOBAL_NPC_EVENT"
167
168 @classmethod
169 def post(cls, ev):
170 """Send a DsmEvent event to all NPCs.
171 """
172 super(GlobalNpcEvent, cls).post(ev=ev)
173
174
175class AddSpriteEvent(UserEvent):
176
177 utype = "ADD_SPRITE_EVENT"
178
179 @classmethod
180 def post(cls, item):
181 """Put a Sprite into the world.
182 """
183 super(AddSpriteEvent, cls).post(item=item)
Note: See TracBrowser for help on using the repository browser.