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 | """
Section Example 2:
In this Section example we develop a very basic Pong game playable by two
persons in the same computer (hot seat!).
Each Player is abstracted as a Section that consists of a space in the screen
where the player paddle can move.
Note:
- Sections can live along with Views. Sections do not need to occupy 100%
of the screen.
- View methods can interact with Sections by storing a reference to each
one.
- How keyboard events can be redirected to each section depending on the
pressed key automatically.
"""
import random
from arcade import Window, Section, View, SpriteList, SpriteSolidColor, \
SpriteCircle, draw_text, draw_line
from arcade.color import BLACK, BLUE, RED, BEAU_BLUE, GRAY
from arcade.key import W, S, UP, DOWN
PLAYER_SECTION_WIDTH = 100
PLAYER_PADDLE_SPEED = 10
class Player(Section):
"""
A Section representing the space in the screen where the player
paddle can move
"""
def __init__(self, left: float, bottom: float, width: float, height: float,
key_up: int, key_down: int, **kwargs):
super().__init__(left, bottom, width, height,
accept_keyboard_events={key_up, key_down}, **kwargs)
# keys assigned to move the paddle
self.key_up: int = key_up
self.key_down: int = key_down
# the player paddle
self.paddle: SpriteSolidColor = SpriteSolidColor(30, 100, BLACK)
# player score
self.score: int = 0
def setup(self):
# reset the player paddle position to the middle of the screen
self.paddle.position = self.left + 50, self.height / 2
def on_update(self, delta_time: float):
# update the paddle position
self.paddle.update()
def on_draw(self):
# draw sections info and score
if self.name == 'Left':
keys = 'W and S'
start_x = self.left + 5
else:
keys = 'UP and DOWN'
start_x = self.left - 290
draw_text(f'Player {self.name} (move paddle with: {keys})',
start_x, self.top - 20, BLUE, 9)
draw_text(f'Score: {self.score}', self.left + 20,
self.bottom + 20, BLUE)
# draw the paddle
self.paddle.draw()
def on_key_press(self, symbol: int, modifiers: int):
# set the paddle direction and movement speed
if symbol == self.key_up:
self.paddle.change_y = PLAYER_PADDLE_SPEED
else:
self.paddle.change_y = -PLAYER_PADDLE_SPEED
def on_key_release(self, _symbol: int, _modifiers: int):
# stop moving the paddle
self.paddle.stop()
class Pong(View):
def __init__(self):
super().__init__()
# a sprite list that will hold each player paddle to
# check for collisions
self.paddles: SpriteList = SpriteList()
# we store each Section
self.left_player: Player = Player(
0, 0, PLAYER_SECTION_WIDTH, self.window.height, key_up=W,
key_down=S, name='Left')
self.right_player: Player = Player(
self.window.width - PLAYER_SECTION_WIDTH, 0, PLAYER_SECTION_WIDTH,
self.window.height, key_up=UP, key_down=DOWN, name='Right')
# add the sections to the SectionManager so Sections start to work
self.add_section(self.left_player)
self.add_section(self.right_player)
# add each paddle to the sprite list
self.paddles.append(self.left_player.paddle)
self.paddles.append(self.right_player.paddle)
# create the ball
self.ball: SpriteCircle = SpriteCircle(20, RED)
def setup(self):
# set up a new game
# set ball position in the middle
self.ball.position = self.window.width / 2, self.window.height / 2
# randomize ball direction and speed
self.ball.change_x = random.choice([-3, -2, 3, 2])
self.ball.change_y = random.choice([-3, -2, 3, 2])
# setup player paddles
self.left_player.setup()
self.right_player.setup()
def on_update(self, delta_time: float):
self.ball.update() # update the ball
# bounce the ball either at the top or at the bottom
if self.ball.bottom <= 0:
self.ball.change_y *= -1
elif self.ball.top >= self.window.height:
self.ball.change_y *= -1
# check if the ball has collided with a paddle
collided_paddle = self.ball.collides_with_list(self.paddles)
if collided_paddle:
# adjust ball coordinates to simplify the game
if collided_paddle[0] is self.left_player.paddle:
self.ball.left = self.left_player.paddle.right
else:
self.ball.right = self.right_player.paddle.left
# bounce the ball from the paddle
self.ball.change_x *= -1
# check if the ball has exited the screen in either side and
# end the game
if self.ball.right <= 0:
self.end_game(self.right_player)
elif self.ball.left >= self.window.width:
self.end_game(self.left_player)
def end_game(self, winner: Player):
""" Called when one player wins """
winner.score += 1 # increment the winner score
self.setup() # prepare a new game
def on_draw(self):
self.clear(BEAU_BLUE) # clear the screen
self.ball.draw() # draw the ball
half_window_x = self.window.width / 2 # middle x
# draw a line diving the screen in half
draw_line(half_window_x, 0, half_window_x, self.window.height, GRAY, 2)
def main():
# create the window
window = Window(title='Two player simple Pong with Sections!')
# create the custom View
game = Pong()
# set up the game (start a game)
game.setup()
# show the view
window.show_view(game)
# run arcade loop
window.run()
if __name__ == '__main__':
main()
|