-
Notifications
You must be signed in to change notification settings - Fork 1
/
level.py
160 lines (131 loc) · 5.89 KB
/
level.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
from gamestrategy import Strategy
from enemy import Enemy
from gamemap import GameMap
from statusmodifiers import OneUp, Bomb, SpeedUp, MoreGuns
from utilfuncs import switch
from timer import Timer
from textelement import TextElement
from endgamesignal import EndLevel
from loadstaticres import oneupimg, moregunsimg, speedupimg, bombimg
from constants import NEW_SAUCER_IVAL, SAUCER_THRESHOLD, SCREENW, SCREENH, VAL_TEXT_SIZE, BOSSHEALTH, VAL_X_LOC, VAL_FONT, VAL_Y_LOC_START, TEXTCOLOR, INITIAL_SAUCERS, LVL_START_FONT, LVL_START_TIME
import random
class Level(Strategy):
"""
Strategy for managing progression of typical game level
"""
def __init__(self, scene, mixer, config, universal):
"""
Declare and assign variables
:param scene: Scene object to manipulate
:param mixer: pygame.mixer object
:param config: dictionary of level specific resources
:param universal: dictionary of objects that stay in use between levels
"""
super().__init__(scene)
self.mixer = mixer
self.config = config
# set up player
self.ship = universal["ship"]
# set up map
self.game_map = GameMap(self.config["background"].convert())
# add health and score labels
self.health_label = universal["health_label"]
self.score_label = universal["score_label"]
self.boss_health_label = TextElement(VAL_X_LOC, VAL_Y_LOC_START+VAL_TEXT_SIZE*2,
VAL_FONT, TEXTCOLOR, "Boss: {}", BOSSHEALTH)
self.level_start_label = TextElement(SCREENW/4, SCREENH/4, LVL_START_FONT, TEXTCOLOR, self.config["start_text"])
self.start_text_timer = Timer()
self.saucers = []
self.saucer_timer = Timer()
def setup(self):
"""
Attach objects to scene and set up subscriptions
"""
# clear relevant subscriptions on shared objects from previous levels
self.ship.remove_event("fire")
self.ship.remove_event("player_respawn")
# ensure ship is positioned correctly
self.ship.respawn()
# load up music
self.mixer.music.load(self.config["bg_music_fname"])
# enable firing of bullets
self.ship.subscribe("fire", lambda ev: self.scene.attach(ev.kwargs.get("bullet")))
# so that map speed up resets on player death
self.ship.subscribe("player_respawn", self.game_map.reset_speed)
self.saucer_timer.subscribe("timeout", self.add_saucer)
self.start_text_timer.subscribe("timeout", self.remove_start_text)
# create initial enemies
for x in range(0, INITIAL_SAUCERS):
newsaucer = Enemy(self.config["enemy_image"])
newsaucer.subscribe("score_up", self.score_label.update_value)
self.saucers.append(newsaucer)
self.scene.attach(newsaucer)
self.scene.attach(self.ship)
self.scene.attach(self.game_map)
self.scene.attach(self.health_label)
self.scene.attach(self.score_label)
self.scene.attach(self.level_start_label)
self.saucer_timer.startwatch(NEW_SAUCER_IVAL)
self.start_text_timer.startwatch(LVL_START_TIME)
def run_game(self):
try:
if not self.mixer.music.get_busy():
# start music on endless loop
self.mixer.music.play(-1)
if self.start_text_timer.is_timing():
self.start_text_timer.tick()
self.saucer_timer.tick()
# determine if we should have a status modifier
# so apparently there's no switch/case in python >_>
# choose a random number, determine which powerup based on number
for case in switch(random.randrange(0, 10000)):
statmod = None
if case(1):
statmod = OneUp(oneupimg)
elif case(90):
statmod = Bomb(bombimg)
elif case(1337):
statmod = SpeedUp(speedupimg)
statmod.subscribe("collision", self.game_map.increase_speed)
elif case(511):
statmod = MoreGuns(moregunsimg)
if statmod is not None:
self.scene.attach(statmod)
super().run_game()
# intercept the EndLevel signal, stop music, and attach score
except EndLevel as e:
self.mixer.music.stop()
self.ship.stop_motion()
info = e.args[0]
info['score'] = self.score_label.get_value()
raise EndLevel(info)
def remove_start_text(self, event):
self.scene.remove(self.level_start_label)
def add_saucer(self, event):
"""
Event handler for saucer add timeout
:param event:
:return:
"""
if len(self.saucers) < SAUCER_THRESHOLD:
newsaucer = Enemy(self.config["enemy_image"])
newsaucer.subscribe("score_up", self.score_label.update_value)
self.saucers.append(newsaucer)
self.scene.attach(newsaucer)
self.saucer_timer.startwatch(NEW_SAUCER_IVAL)
else:
# clear out the saucers and enter the boss
self.clear_saucers()
boss = self.config["boss_class"](SCREENW/2-self.config["boss_image"].get_width()/2,
-1200,
self.config["boss_image"],
self.ship)
boss.subscribe("health_down", self.boss_health_label.update_value)
boss.subscribe("fire", lambda ev: self.scene.attach(ev.kwargs.get("bullet")))
boss.subscribe("death", self.score_label.update_value)
self.scene.attach(boss)
self.scene.attach(self.boss_health_label)
def clear_saucers(self):
for s in self.saucers:
s.leave()
self.saucers.clear()