Sections Demo 2

sections_demo_2.py
1"""
2Section Example 2:
3
4In this Section example we develop a very basic Pong game playable by two
5persons in the same computer (hot seat!).
6
7Each Player is abstracted as a Section that consists of a space in the screen
8where the player paddle can move.
9
10Note:
11 - Sections can live along with Views. Sections do not need to occupy 100%
12 of the screen.
13 - View methods can interact with Sections by storing a reference to each
14 one.
15 - How keyboard events can be redirected to each section depending on the
16 pressed key automatically.
17
18If Python and Arcade are installed, this example can be run from the command line with:
19python -m arcade.examples.sections_demo_2
20"""
21
22import random
23
24import arcade
25from arcade.color import BLACK, BLUE, RED, BEAU_BLUE, GRAY
26from arcade.key import W, S, UP, DOWN
27
28PLAYER_SECTION_WIDTH = 100
29PLAYER_PADDLE_SPEED = 10
30
31
32class Player(arcade.Section):
33 """
34 A Section representing the space in the screen where the player
35 paddle can move
36 """
37
38 def __init__(
39 self, left: int, bottom: int, width: int, height: int, key_up: int, key_down: int, **kwargs
40 ):
41 super().__init__(
42 left,
43 bottom,
44 width,
45 height,
46 accept_keyboard_keys={key_up, key_down},
47 **kwargs,
48 )
49
50 # keys assigned to move the paddle
51 self.key_up: int = key_up
52 self.key_down: int = key_down
53
54 # the player paddle
55 self.paddle: arcade.SpriteSolidColor = arcade.SpriteSolidColor(30, 100, color=BLACK)
56
57 # player score
58 self.score: int = 0
59
60 def setup(self):
61 # reset the player paddle position to the middle of the screen
62 self.paddle.position = self.left + 50, self.height / 2
63
64 def on_update(self, delta_time: float):
65 # update the paddle position
66 self.paddle.update()
67
68 def on_draw(self):
69 # draw sections info and score
70 if self.name == "Left":
71 keys = "W and S"
72 start_x = self.left + 5
73 else:
74 keys = "UP and DOWN"
75 start_x = self.left - 290
76 arcade.draw_text(
77 f"Player {self.name} (move paddle with: {keys})",
78 start_x,
79 self.top - 20,
80 BLUE,
81 9,
82 )
83 arcade.draw_text(
84 f"Score: {self.score}",
85 self.left + 20,
86 self.bottom + 20,
87 BLUE,
88 )
89
90 # draw the paddle
91 arcade.draw_sprite(self.paddle)
92
93 def on_key_press(self, symbol: int, modifiers: int):
94 # set the paddle direction and movement speed
95 if symbol == self.key_up:
96 self.paddle.change_y = PLAYER_PADDLE_SPEED
97 else:
98 self.paddle.change_y = -PLAYER_PADDLE_SPEED
99
100 def on_key_release(self, _symbol: int, _modifiers: int):
101 # stop moving the paddle
102 self.paddle.stop()
103
104
105class GameView(arcade.View):
106 def __init__(self):
107 super().__init__()
108
109 # a sprite list that will hold each player paddle to
110 # check for collisions
111 self.paddles: arcade.SpriteList = arcade.SpriteList()
112
113 # we store each Section
114 self.left_player: Player = Player(
115 0, 0, PLAYER_SECTION_WIDTH, self.window.height, key_up=W, key_down=S, name="Left"
116 )
117 self.right_player: Player = Player(
118 self.window.width - PLAYER_SECTION_WIDTH,
119 0,
120 PLAYER_SECTION_WIDTH,
121 self.window.height,
122 key_up=UP,
123 key_down=DOWN,
124 name="Right",
125 )
126
127 # add the sections to the SectionManager so Sections start to work
128 self.section_manager = arcade.SectionManager(self)
129 self.section_manager.add_section(self.left_player)
130 self.section_manager.add_section(self.right_player)
131
132 # add each paddle to the sprite list
133 self.paddles.append(self.left_player.paddle)
134 self.paddles.append(self.right_player.paddle)
135
136 # create the ball
137 self.ball: arcade.SpriteCircle = arcade.SpriteCircle(20, RED)
138
139 def setup(self):
140 # set up a new game
141
142 # set ball position in the middle
143 self.ball.position = self.window.width / 2, self.window.height / 2
144
145 # randomize ball direction and speed
146 self.ball.change_x = random.choice([-3, -2, 3, 2])
147 self.ball.change_y = random.choice([-3, -2, 3, 2])
148
149 # setup player paddles
150 self.left_player.setup()
151 self.right_player.setup()
152
153 def on_show_view(self) -> None:
154 self.section_manager.enable()
155
156 def on_hide_view(self) -> None:
157 self.section_manager.disable()
158
159 def on_update(self, delta_time: float):
160 self.ball.update() # update the ball
161
162 # bounce the ball either at the top or at the bottom
163 if self.ball.bottom <= 0:
164 self.ball.change_y *= -1
165 elif self.ball.top >= self.window.height:
166 self.ball.change_y *= -1
167
168 # check if the ball has collided with a paddle
169 collided_paddle = self.ball.collides_with_list(self.paddles)
170 if collided_paddle:
171 # adjust ball coordinates to simplify the game
172 if collided_paddle[0] is self.left_player.paddle:
173 self.ball.left = self.left_player.paddle.right
174 else:
175 self.ball.right = self.right_player.paddle.left
176
177 # bounce the ball from the paddle
178 self.ball.change_x *= -1
179
180 # check if the ball has exited the screen in either side and
181 # end the game
182 if self.ball.right <= 0:
183 self.end_game(self.right_player)
184 elif self.ball.left >= self.window.width:
185 self.end_game(self.left_player)
186
187 def end_game(self, winner: Player):
188 """Called when one player wins"""
189 winner.score += 1 # increment the winner score
190 self.setup() # prepare a new game
191
192 def on_draw(self):
193 self.clear(color=BEAU_BLUE) # clear the screen
194
195 arcade.draw_sprite(self.ball) # draw the ball
196
197 half_window_x = self.window.width / 2 # middle x
198
199 # draw a line diving the screen in half
200 arcade.draw_line(half_window_x, 0, half_window_x, self.window.height, GRAY, 2)
201
202
203def main():
204 # create the window
205 window = arcade.Window(title="Two player simple Pong with Sections!")
206
207 # create the custom View
208 game = GameView()
209 game.setup()
210
211 # show the view
212 window.show_view(game)
213
214 # run arcade loop
215 window.run()
216
217
218if __name__ == "__main__":
219 main()