Sections Demo 2

Screen shot of using sections
sections_demo_2.py
  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: int, bottom: int, width: int, height: int,
                 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()