Sections Demo 2#

Screen shot of using sections
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"""
 21from __future__ import annotations
 22
 23import random
 24
 25from arcade import Window, Section, View, SpriteList, SpriteSolidColor, \
 26    SpriteCircle, draw_text, draw_line
 27from arcade.color import BLACK, BLUE, RED, BEAU_BLUE, GRAY
 28from arcade.key import W, S, UP, DOWN
 29
 30PLAYER_SECTION_WIDTH = 100
 31PLAYER_PADDLE_SPEED = 10
 32
 33
 34class Player(Section):
 35    """
 36    A Section representing the space in the screen where the player
 37    paddle can move
 38    """
 39
 40    def __init__(self, left: int, bottom: int, width: int, height: int,
 41                 key_up: int, key_down: int, **kwargs):
 42        super().__init__(left, bottom, width, height, accept_keyboard_keys={key_up, key_down}, **kwargs)
 43
 44        # keys assigned to move the paddle
 45        self.key_up: int = key_up
 46        self.key_down: int = key_down
 47
 48        # the player paddle
 49        self.paddle: SpriteSolidColor = SpriteSolidColor(30, 100, color=BLACK)
 50
 51        # player score
 52        self.score: int = 0
 53
 54    def setup(self):
 55        # reset the player paddle position to the middle of the screen
 56        self.paddle.position = self.left + 50, self.height / 2
 57
 58    def on_update(self, delta_time: float):
 59        # update the paddle position
 60        self.paddle.update()
 61
 62    def on_draw(self):
 63        # draw sections info and score
 64        if self.name == 'Left':
 65            keys = 'W and S'
 66            start_x = self.left + 5
 67        else:
 68            keys = 'UP and DOWN'
 69            start_x = self.left - 290
 70        draw_text(f'Player {self.name} (move paddle with: {keys})',
 71                  start_x, self.top - 20, BLUE, 9)
 72        draw_text(f'Score: {self.score}', self.left + 20,
 73                  self.bottom + 20, BLUE)
 74
 75        # draw the paddle
 76        self.paddle.draw()
 77
 78    def on_key_press(self, symbol: int, modifiers: int):
 79        # set the paddle direction and movement speed
 80        if symbol == self.key_up:
 81            self.paddle.change_y = PLAYER_PADDLE_SPEED
 82        else:
 83            self.paddle.change_y = -PLAYER_PADDLE_SPEED
 84
 85    def on_key_release(self, _symbol: int, _modifiers: int):
 86        # stop moving the paddle
 87        self.paddle.stop()
 88
 89
 90class Pong(View):
 91
 92    def __init__(self):
 93        super().__init__()
 94
 95        # a sprite list that will hold each player paddle to
 96        # check for collisions
 97        self.paddles: SpriteList = SpriteList()
 98
 99        # we store each Section
100        self.left_player: Player = Player(
101            0, 0, PLAYER_SECTION_WIDTH, self.window.height, key_up=W,
102            key_down=S, name='Left')
103        self.right_player: Player = Player(
104            self.window.width - PLAYER_SECTION_WIDTH, 0, PLAYER_SECTION_WIDTH,
105            self.window.height, key_up=UP, key_down=DOWN, name='Right')
106
107        # add the sections to the SectionManager so Sections start to work
108        self.add_section(self.left_player)
109        self.add_section(self.right_player)
110
111        # add each paddle to the sprite list
112        self.paddles.append(self.left_player.paddle)
113        self.paddles.append(self.right_player.paddle)
114
115        # create the ball
116        self.ball: SpriteCircle = SpriteCircle(20, RED)
117
118    def setup(self):
119        # set up a new game
120
121        # set ball position in the middle
122        self.ball.position = self.window.width / 2, self.window.height / 2
123
124        # randomize ball direction and speed
125        self.ball.change_x = random.choice([-3, -2, 3, 2])
126        self.ball.change_y = random.choice([-3, -2, 3, 2])
127
128        # setup player paddles
129        self.left_player.setup()
130        self.right_player.setup()
131
132    def on_update(self, delta_time: float):
133        self.ball.update()  # update the ball
134
135        # bounce the ball either at the top or at the bottom
136        if self.ball.bottom <= 0:
137            self.ball.change_y *= -1
138        elif self.ball.top >= self.window.height:
139            self.ball.change_y *= -1
140
141        # check if the ball has collided with a paddle
142        collided_paddle = self.ball.collides_with_list(self.paddles)
143        if collided_paddle:
144            # adjust ball coordinates to simplify the game
145            if collided_paddle[0] is self.left_player.paddle:
146                self.ball.left = self.left_player.paddle.right
147            else:
148                self.ball.right = self.right_player.paddle.left
149
150            # bounce the ball from the paddle
151            self.ball.change_x *= -1
152
153        # check if the ball has exited the screen in either side and
154        # end the game
155        if self.ball.right <= 0:
156            self.end_game(self.right_player)
157        elif self.ball.left >= self.window.width:
158            self.end_game(self.left_player)
159
160    def end_game(self, winner: Player):
161        """ Called when one player wins """
162        winner.score += 1  # increment the winner score
163        self.setup()  # prepare a new game
164
165    def on_draw(self):
166        self.clear(BEAU_BLUE)  # clear the screen
167
168        self.ball.draw()  # draw the ball
169
170        half_window_x = self.window.width / 2  # middle x
171
172        # draw a line diving the screen in half
173        draw_line(half_window_x, 0, half_window_x, self.window.height, GRAY, 2)
174
175
176def main():
177    # create the window
178    window = Window(title='Two player simple Pong with Sections!')
179
180    # create the custom View
181    game = Pong()
182
183    # set up the game (start a game)
184    game.setup()
185
186    # show the view
187    window.show_view(game)
188
189    # run arcade loop
190    window.run()
191
192
193if __name__ == '__main__':
194    main()