-
Notifications
You must be signed in to change notification settings - Fork 0
/
pong_v3.py
306 lines (245 loc) Β· 10.8 KB
/
pong_v3.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
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
# Pong by Zeyu Li
# This is a program that is a recreation of pong
# imports the pygame module
import pygame
# User-defined functions
def main():
# initialize all pygame modules (some need initialization)
pygame.init()
# create a pygame display window 500 px by 400 px
pygame.display.set_mode((500, 400))
# set the title of the display window
pygame.display.set_caption('Pong - Python Application')
# get the display surface
w_surface = pygame.display.get_surface()
# create a game object
game = Game(w_surface)
# start the main game loop by calling the play method on the game object
game.play()
# quit pygame and clean up the pygame window
pygame.quit()
# User-defined classes
class Game:
# An object in this class represents a complete game.
def __init__(self, surface):
# Initialize a Game.
# - self is the Game to initialize
# - surface is the display window surface object
# sets surface and the color black
self.surface = surface
self.bg_color = pygame.Color('black')
self.fg_color = pygame.Color('white')
# sets fps to 60
self.FPS = 60
self.game_Clock = pygame.time.Clock()
self.close_clicked = False
self.continue_game = True
# sets scores
self.left_score = 0
self.right_score = 0
# defines middle of window
y_middle = int(self.surface.get_height()/2)
# set the paddles y coords
self.l_paddle = y_middle - 20
self.r_paddle = y_middle - 20
# sets the paddles velocity
self.l_paddle_v = 0
self.r_paddle_v = 0
# game objects: ball, left paddle and right paddle
self.left_paddle = Paddle(
'white', pygame.Rect(100, self.l_paddle, 10, 40), 5, self.surface
)
self.right_paddle = Paddle(
'white', pygame.Rect(self.surface.get_width() - 100, self.r_paddle, 10, 40), 5, self.surface
)
self.ball = Ball(
'white', 5, [int(self.surface.get_width()/2) - 3,
y_middle - 3], [6, 2], self.surface
)
# max frames not needed
# self.max_frames = 150
self.frame_counter = 0
def play(self):
# Play the game until the player presses the close box.
# - self is the Game that should be continued or not.
while not self.close_clicked: # until player clicks close box
# play frame
self.handle_events()
self.draw()
if self.continue_game:
self.update()
self.decide_continue()
self.game_Clock.tick(self.FPS) # run at most with FPS Frames Per Second
def handle_events(self):
# Handle each user event by changing the game state appropriately.
# - self is the Game whose events will be handled
events = pygame.event.get()
for event in events:
if event.type == pygame.QUIT:
self.close_clicked = True
elif event.type == pygame.KEYDOWN:
# modifies left paddle velocity when key pressed
if event.key == pygame.K_q:
self.l_paddle_v = 5
elif event.key == pygame.K_a:
self.l_paddle_v = -5
# modifies right paddle velocity when key pressed
if event.key == pygame.K_p:
self.r_paddle_v = 5
elif event.key == pygame.K_l:
self.r_paddle_v = -5
elif event.type == pygame.KEYUP:
# modifies paddle velocity when key released
if event.key == pygame.K_q or event.key == pygame.K_a:
self.l_paddle_v = 0
if event.key == pygame.K_p or event.key == pygame.K_l:
self.r_paddle_v = 0
def draw(self):
# Draw all game objects.
# - self is the Game to draw
# draws ball, right and left paddle and the scores
self.surface.fill(self.bg_color) # clear the display surface first
self.ball.draw()
self.left_paddle.draw()
self.right_paddle.draw()
self.score('right')
self.score('left')
pygame.display.update() # make the updated surface appear on the display
def update(self):
# Update the game objects.
# - self is the Game to update
# modifies paddle position given velocity of paddles
if self.l_paddle - self.l_paddle_v < 0:
self.l_paddle = 0
elif self.l_paddle + 40 - self.l_paddle_v > self.surface.get_height():
self.l_paddle = self.surface.get_height() - 40
else:
self.l_paddle -= self.l_paddle_v
if self.r_paddle - self.r_paddle_v < 0:
self.r_paddle = 0
elif self.r_paddle + 40 - self.r_paddle_v > self.surface.get_height():
self.r_paddle = self.surface.get_height() - 40
else:
self.r_paddle -= self.r_paddle_v
# updates paddles
self.left_paddle = Paddle(
'white', pygame.Rect(100, self.l_paddle, 10, 40), 5, self.surface
)
self.right_paddle = Paddle(
'white', pygame.Rect(self.surface.get_width() - 100, self.r_paddle, 10, 40), 5, self.surface
)
# scored is the var that is either left if it hits the right wall,
# right if it hits the left wall and pass if it hits the paddle
scored = self.ball.move(self.l_paddle, self.r_paddle)
if scored == 'right':
self.left_score += 1
elif scored == 'left':
self.right_score += 1
# advance frame counter
self.frame_counter = self.frame_counter + 1
def decide_continue(self):
# Check and remember if the game should continue
# - self is the Game to check
# check score to see if 11 on either side
if self.right_score == 11 or self.left_score == 11:
self.continue_game = False
def score(self, side):
# sets text score
# - self is Game
# - side is which side the text is displayed
# use default system font and at 75
font = pygame.font.SysFont('', 75)
if side == 'left':
# if left side, render text at (5,0)
coordinate = (5, 0)
text_box = font.render(str(self.left_score), True, self.fg_color, self.bg_color)
else:
# to align text right, I used:
# https://stackoverflow.com/questions/34013119/pygame-text-anchor-right (1st answer)
# if right side, render text on the right side
text_box = font.render(str(self.right_score), True, self.fg_color, self.bg_color)
text_rect = text_box.get_rect() # get rect from textbox
text_rect.right = self.surface.get_width()
coordinate = text_rect
# prints to surface
self.surface.blit(text_box, coordinate)
class Ball:
# An object in this class represents objects in the game
def __init__(self, ball_color, ball_radius, ball_center, ball_velocity, surface):
# Initialize a Ball.
# - self is the Ball to initialize
# - color is the pygame.Color of the ball
# - center is a list containing the x and y int
# coords of the center of the ball
# - radius is the int pixel radius of the ball
# - velocity is a list containing the x and y components
# - surface is the window's pygame. Surface object
self.color = pygame.Color(ball_color)
self.radius = ball_radius
self.center = ball_center
self.velocity = ball_velocity
self.surface = surface
def move(self, l_paddle, r_paddle):
# Change the location of the Ball by adding the corresponding
# speed values to the x and y coordinate of its center
# - self is the Ball
# - l_paddle is the top position of left paddle
# - r_paddle is the top position of right paddle
# default score is pass
scored = 'pass'
# for x then y
for i in range(0,2):
if i == 0:
# left and right paddle
if self.surface.get_width() < self.center[i] + 2 + self.velocity[i] or 0 > self.center[i] - 2 + self.velocity[i]:
self.velocity[i] = -self.velocity[i]
# if it hits wall say which side scored using the velocity
if self.velocity[i] > 0:
scored = 'left'
else:
scored = 'right'
# check to see if it hits the paddle and is heading the right way
# if it hits, bounce off
elif (105 <= self.center[i] - 2 + self.velocity[i] <= 111 and self.velocity[i] < 0 and
l_paddle - 3 <= self.center[i+1] + self.velocity[i+1] <= l_paddle + 43):
self.velocity[i] = -self.velocity[i]
elif (self.surface.get_width() - 101 <= self.center[i] - 2 + self.velocity[i] <= self.surface.get_width() - 95 and
self.velocity[i] > 0 and
r_paddle -3 <= self.center[i+1] + self.velocity[i+1] <= r_paddle + 43):
self.velocity[i] = -self.velocity[i]
else:
if self.surface.get_height() < self.center[i] + 2 + self.velocity[i] or 0 > self.center[i] - 2 + self.velocity[i]:
self.velocity[i] = -self.velocity[i]
self.center[i] = (self.center[i] + self.velocity[i])
# return which side scored
return scored
def draw(self):
# Draw the ball on the surface
# - self is the Ball
pygame.draw.circle(self.surface, self.color, self.center, self.radius)
class Paddle:
# An object in this class represents objects in the game
def __init__(self, paddle_color, paddle_object, paddle_velocity, surface):
# Initialize a paddle.
# - self is the paddle to initialize
# - color is the pygame.Color of the paddle
# - object of the paddle as a Rect
# - velocity is a list containing the x and y components
# - surface is the window's pygame. Surface object
self.color = pygame.Color(paddle_color)
self.center = paddle_object
self.velocity = paddle_velocity
self.surface = surface
def move(self):
# NOT in use at the moment
# Change the location of the paddle by adding the corresponding
# speed values to the x and y coordinate of its center
# - self is the paddle
for i in range(0,2):
self.center[i] = (self.center[i] + self.velocity[i])
def draw(self):
# Draw the paddle on the surface
# - self is the Paddle
pygame.draw.rect(self.surface, self.color, self.center)
# main function call
main()