-
Notifications
You must be signed in to change notification settings - Fork 0
/
app.py
223 lines (178 loc) · 9.11 KB
/
app.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
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
"""
Primary module for Alien Invaders
This module contains the main controller class for the Alien Invaders app.
There is no need for any additional classes in this module. If you need
more classes, 99% of the time they belong in either the wave module or the
models module. If you are unsure about where a new class should go, post a
question on Piazza.
Ahmad Bhatti(mab558) and Anthony Ma(ajm439)
12/12/2019
"""
from consts import *
from game2d import *
from wave import *
import numpy
# PRIMARY RULE: Invaders can only access attributes in wave.py via getters/setters
# Invaders is NOT allowed to access anything in models.py
class Invaders(GameApp):
"""
The primary controller class for the Alien Invaders application
This class extends GameApp and implements the various methods necessary
for processing the player inputs and starting/running a game.
Method start begins the application.
Method update either changes the state or updates the Play object
Method draw displays the Play object and any other elements on screen
Because of some of the weird ways that Kivy works, you SHOULD NOT create
an initializer __init__ for this class. Any initialization should be done
in the start method instead. This is only for this class. All other
classes behave normally.
Most of the work handling the game is actually provided in the class Wave.
Wave should be modeled after subcontrollers.py from lecture, and will
have its own update and draw method.
The primary purpose of this class is to manage the game state: which is
when the game started, paused, completed, etc. It keeps track of that in
an internal (hidden) attribute.
For a complete description of how the states work, see the specification
for the method update.
Attribute view: the game view, used in drawing
Invariant: view is an instance of GView (inherited from GameApp)
Attribute input: user input, used to control the ship or resume the game
Invariant: input is an instance of GInput (inherited from GameApp)
"""
# HIDDEN ATTRIBUTES:
# Attribute _state: the current state of the game represented as an int
# Invariant: _state is one of STATE_INACTIVE, STATE_NEWWAVE, STATE_ACTIVE,
# STATE_PAUSED, STATE_CONTINUE, or STATE_COMPLETE
#
# Attribute _wave: the subcontroller for a single wave, managing aliens
# Invariant: _wave is a Wave object, or None if there is no wave currently
# active. It is only None if _state is STATE_INACTIVE.
#
# Attribute _text: the currently active message
# Invariant: _text is a GLabel object, or None if there is no message to
# display. It is onl None if _state is STATE_ACTIVE.
#
# You may have new attributes if you wish (you might want an attribute to
# store any score across multiple waves). But you must document them.
# LIST MORE ATTRIBUTES (AND THEIR INVARIANTS) HERE IF NECESSARY
#
# Attribute _last: the number of keys pressed last frame
# Invariant: _last is an int >= 0
# DO NOT MAKE A NEW INITIALIZER!
# THREE MAIN GAMEAPP METHODS
def start(self):
"""
Initializes the application.
This method is distinct from the built-in initializer __init__ (which
you should not override or change). This method is called once the
game is running. You should use it to initialize any game specific
attributes.
This method should make sure that all of the attributes satisfy the
given invariants. When done, it sets the _state to STATE_INACTIVE and
create a message (in attribute _text) saying that the user should press
to play a game.
"""
self._state = STATE_INACTIVE
if self._state == STATE_INACTIVE:
self._text = GLabel(text="Press 'S' to play", font_size=50,
x = GAME_WIDTH/2, y = GAME_HEIGHT/2, font_name="Arcade.ttf")
else:
self._text = None
self._wave = None
self._last=0
def update(self,dt):
"""
Animates a single frame in the game.
It is the method that does most of the work. It is NOT in charge of
playing the game. That is the purpose of the class Wave. The primary
purpose of this game is to determine the current state, and -- if the
game is active -- pass the input to the Wave object _wave to play the
game.
As part of the assignment, you are allowed to add your own states.
However, at a minimum you must support the following states:
STATE_INACTIVE, STATE_NEWWAVE, STATE_ACTIVE, STATE_PAUSED,
STATE_CONTINUE, and STATE_COMPLETE. Each one of these does its own
thing and might even needs its own helper. We describe these below.
STATE_INACTIVE: This is the state when the application first opens.
It is a paused state, waiting for the player to start the game. It
displays a simple message on the screen. The application remains in
this state so long as the player never presses a key. In addition,
this is the state the application returns to when the game is over
(all lives are lost or all aliens are dead).
STATE_NEWWAVE: This is the state creates a new wave and shows it on
the screen. The application switches to this state if the state was
STATE_INACTIVE in the previous frame, and the player pressed a key.
This state only lasts one animation frame before switching to
STATE_ACTIVE.
STATE_ACTIVE: This is a session of normal gameplay. The player can
move the ship and fire laser bolts. All of this should be handled
inside of class Wave (NOT in this class). Hence the Wave class
should have an update() method, just like the subcontroller example
in lecture.
STATE_PAUSED: Like STATE_INACTIVE, this is a paused state. However,
the game is still visible on the screen.
STATE_CONTINUE: This state restores the ship after it was destroyed.
The application switches to this state if the state was STATE_PAUSED
in the previous frame, and the player pressed a key. This state only
lasts one animation frame before switching to STATE_ACTIVE.
STATE_COMPLETE: The wave is over, and is either won or lost.
You are allowed to add more states if you wish. Should you do so, you should
describe them here.
Parameter dt: The time in seconds since last update
Precondition: dt is a number (int or float)
"""
if self._state == STATE_INACTIVE:
self._detState(STATE_NEWWAVE)
if self._state==STATE_NEWWAVE:
self._wave = Wave()
self._state= STATE_ACTIVE
if self._state == STATE_ACTIVE:
self._wave.update(self.input,dt)
if self._wave.getPause():
self._state = STATE_PAUSED
self._text = GLabel(text="Press 'S' to continue", font_size=50,
x = GAME_WIDTH/2, y = GAME_HEIGHT/2, font_name="Arcade.ttf")
elif self._wave.getEnd() > 0:
self._state = STATE_COMPLETE
if self._state == STATE_PAUSED:
self._detState(STATE_ACTIVE)
if self._state == STATE_COMPLETE:
if self._wave.getEnd() < 3:
self._text = GLabel(text="YOU LOSE!", font_size=50,
x = GAME_WIDTH/2, y = GAME_HEIGHT/2, font_name="Arcade.ttf")
elif self._wave.getEnd() == 3:
self._text = GLabel(text="YOU WIN!!!", font_size=50,
x = GAME_WIDTH/2, y = GAME_HEIGHT/2, font_name="Arcade.ttf")
def draw(self):
"""
Draws the game objects to the view.
Every single thing you want to draw in this game is a GObject. To
draw a GObject g, simply use the method g.draw(self.view). It is
that easy!
Many of the GObjects (such as the ships, aliens, and bolts) are
attributes in Wave. In order to draw them, you either need to add
getters for these attributes or you need to add a draw method to
class Wave. We suggest the latter. See the example subcontroller.py
from class.
"""
if self._state != STATE_ACTIVE:
self._text.draw(self.view)
else:
self._wave.draw(self.view)
# HELPER METHODS FOR THE STATES GO HERE
def _detState(self,state):
"""
Determines the current state and assigns it to self.state
This method checks for a key press, and if there is one, changes the state
to the next value. A key press is when a key is pressed for the FIRST TIME.
We do not want the state to continue to change as we hold down the key. The
user must release the key and press it again to change the state.
Parameter state: The state of the game to be changed into
Precondition: state is a valid state from constants
"""
assert STATE_INACTIVE <= state <= STATE_COMPLETE
current=self.input.key_count
if self.input.is_key_down('s') and self._last == 0:
self._state = state
self._text = None
self._last = current