Understanding the game engine
Whilst I work through the different game elements and features I want to implement, I though I’d revisit the game engine from LPTHW.
To be honest, I’ve struggled here a bit. The first time I implemented the game engine I didn’t really understand what was happening. But the code worked and I understood that I could create a scene (including some game text and actions) and provide the next scene in the enter function’s return statement. So for this implementation I wanted to be sure I actually understood the mechanics of the engine when it ran.
Zed has already explained that the engine class hierarchy is ‘Map’, ‘Engine’ and ‘Scene’, with a number of scenes listed based on the room type. Within these classes there will be a number of functions performing actions, such as opening_scene or next_scene, that navigated through the map.
Scenes #
So when I break it down, I start with a base class for scene that has a function; enter. As stated before, when the enter function is called on an instance of the scene class, it will be used to provide game content and the puzzles/challenges, before the next_scene information is provided by the return statement.
class Hibernation_Chamber(Scene):
def enter(self):
# do some stuff
return 'medilab'
Engine #
The Engine class, when instantiated, takes a scene_map as its argument. I’ll need to supply that. In order to ‘run’ the engine, a play function is defined. This initially sets the map’s opening scene as the current_scene and identifies the game’s end by setting the last_scene as a scene labelled ‘finished’. This label suggests a Dict is in use, which I’ll come to in a moment.
def play(self):
current_scene = self.scene_map.opening_scene()
last_scene = self.scene_map.next_scene('finished')
Then, there is a while loop to tee up the next scene of the game. It will only run if the current_scene is not the last_scene. It assigns whatever is returned by the enter function of the current scene to next_scene_name variable. I know this is going to be a Dict key, used as the argument to obtain the map’s next scene. This is then assigned to the current_scene variable.
while current_scene != last_scene:
next_scene_name = current_scene.enter()
current_scene = self.scene_map.next_scene(next_scene_name)
Finally, outside of the loop we take the current_scene we have just identified and call it’s enter function so the whole thing repeats.
So far so good. On to the game map…
Map #
The Map class takes the start_scene as its argument when instantiated. This will be the Dict key I mentioned earlier. The Dict contains details of all the rooms/scenes classes as it’s values, which I know are provided for the next_scene_name in the engine.
scenes = {
'hibernation_chamber': Hibernation_Chamber(),
'medilab': Medical_Lab()
}
Then, the next_scene function is defined, taking scene_name as it’s argument. The body of the function detailed below, is where I struggled:
val = Map.scenes.get(scene_name)
I understood that I was assigning the value obtained from ‘getting’ scene_name from the scene map to val, (this value would subsequently be returned by the function). But I was unfamiliar with how scene_name was working, even though I knew it was used in the Engine.play function described earlier.
After a brief review of dict.get() I understood that the argument provided to .get() is the Dict key, and this method returns the associated value, or in the case of the map, the scene’s class.
So the next_scene function just takes the key as it’s argument and returns the class, (which enables it’s enter function to be called in the while loop of Engine.play()). In retrospect, the clue was in the variable name and it was just the unfamiliar syntax that threw me.
Finally, an opening_scene function is defined, that simply returns the scenes key supplied during the class instantiation, as the argument to the ‘next_scene’ function described above. I recall that the opening_scene function is used in the Engine’s Play function as well, so this ties it all together to start the game in the right place.
def opening_scene(self):
return self.next_scene(self.start_scene)
Finally, a Map and Engine instance are created, and the play() function is call on the engine.
Job done!