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"""
 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()