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