25. Sprites und Wände

25.1. Konfiguration

Viele Spiele mit Sprites haben oft „Wände“, durch die sich die Spielfigur nicht bewegen kann. Sie lassen sich eher unkompliziert erstellen.

Lass uns zunächst mit ein paar Bildern anfangen. Unsere Spielfigur und eine Kiste, die als Sperrmauer fungiert. Beide Bilder stammen von kenney.nl.

../../_images/character1.png

images/character.png

../../_images/boxCrate_double.png

images/boxCrate_double.png

Beginne mit einem Einstiegsprogramm:

sprite_move_walls.py - Anfang
 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
""" Sprite Sample Program """

import arcade

# --- Constants ---
SPRITE_SCALING_BOX = 0.5
SPRITE_SCALING_PLAYER = 0.5

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

MOVEMENT_SPEED = 5


class MyGame(arcade.Window):
    """ This class represents the main window of the game. """

    def __init__(self):
        """ Initializer """
        # Call the parent class initializer
        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, "Sprites With Walls Example")


    def setup(self):
        # Set the background color
        arcade.set_background_color(arcade.color.AMAZON)

    def on_draw(self):
        arcade.start_render()


def main():
    window = MyGame()
    window.setup()
    arcade.run()


if __name__ == "__main__":
    main()

Erstellen wir in der __init__-Methode einige Attribute für unsere Sprites:

# Sprite lists
self.player_list = None
self.wall_list = None

# Set up the player
self.player_sprite = None

# This variable holds our simple "physics engine"
self.physics_engine = None

In der setup Methode erstellen wir unsere Sprite-Listen:

# Sprite lists
self.player_list = arcade.SpriteList()
self.wall_list = arcade.SpriteList()

Setze danach die Punktzahl zurück und erstelle die Spielfigur:

# Reset the score
self.score = 0

# Create the player
self.player_sprite = arcade.Sprite("images/character.png", SPRITE_SCALING_PLAYER)
self.player_sprite.center_x = 50
self.player_sprite.center_y = 64
self.player_list.append(self.player_sprite)

Dann zeichne alles in unserer Methode on_draw:

def on_draw(self):
    arcade.start_render()
    self.wall_list.draw()
    self.player_list.draw()

Führe das Programm aus und stelle sicher, dass es funktioniert.

../../_images/just_player.png

25.2. Wände individuell platzieren

In unserer setup Methode können wir einzelne Boxen positionieren, die als „Wände“ verwendet werden:

# Manually create and position a box at 300, 200
wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
wall.center_x = 300
wall.center_y = 200
self.wall_list.append(wall)

# Manually create and position a box at 364, 200
wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
wall.center_x = 364
wall.center_y = 200
self.wall_list.append(wall)

Probiere es einfach aus. Es sollte so aussehen:

../../_images/with_two_boxes.png

Vollständiges Listing unten:

sprite_move_walls.py - Schritt 2
 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
""" Sprite Sample Program """

import arcade

# --- Constants ---
SPRITE_SCALING_BOX = 0.5
SPRITE_SCALING_PLAYER = 0.5

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

MOVEMENT_SPEED = 5


class MyGame(arcade.Window):
    """ This class represents the main window of the game. """

    def __init__(self):
        """ Initializer """
        # Call the parent class initializer
        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, "Sprite Example")

        # Sprite lists
        self.player_list = None
        self.wall_list = None

        # Set up the player
        self.player_sprite = None

    def setup(self):

        # Set the background color
        arcade.set_background_color(arcade.color.AMAZON)

        # Sprite lists
        self.player_list = arcade.SpriteList()
        self.wall_list = arcade.SpriteList()

        # Reset the score
        self.score = 0

        # Create the player
        self.player_sprite = arcade.Sprite("images/character.png", SPRITE_SCALING_PLAYER)
        self.player_sprite.center_x = 50
        self.player_sprite.center_y = 64
        self.player_list.append(self.player_sprite)

        # Manually create and position a box at 300, 200
        wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
        wall.center_x = 300
        wall.center_y = 200
        self.wall_list.append(wall)

        # Manually create and position a box at 364, 200
        wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
        wall.center_x = 364
        wall.center_y = 200
        self.wall_list.append(wall)

    def on_draw(self):
        arcade.start_render()
        self.wall_list.draw()
        self.player_list.draw()


def main():
    """ Main method """
    window = MyGame()
    window.setup()
    arcade.run()


if __name__ == "__main__":
    main()

25.3. Wände mit Hilfe einer Schleife platzieren

In unserer setup -Methode können wir eine Reihe von Box-Sprites mit einer for-Schleife erstellen. Im folgenden Code ist unser y-Wert immer 350, und wir ändern den x-Wert von 173 in 650. Wir setzen alle 64 Pixel ein Kästchen, da jedes Kästchen 64 Pixel breit ist.

# Place boxes inside a loop
for x in range(173, 650, 64):
    wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
    wall.center_x = x
    wall.center_y = 350
    self.wall_list.append(wall)
../../_images/boxes_loop.png

25.4. Wände mit einer Liste platzieren

Man kann sogar eine Liste mit Koordinaten erstellen und diese Liste dann einfach durchlaufen und Wände erstellen:

# --- Place walls with a list
coordinate_list = [[400, 500],
                   [470, 500],
                   [400, 570],
                   [470, 570]]

# Loop through coordinates
for coordinate in coordinate_list:
    wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
    wall.center_x = coordinate[0]
    wall.center_y = coordinate[1]
    self.wall_list.append(wall)
../../_images/list.png

Vollständiges Listing unten:

sprite_move_walls.py - Schritt 3
 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
""" Sprite Sample Program """

import arcade

# --- Constants ---
SPRITE_SCALING_BOX = 0.5
SPRITE_SCALING_PLAYER = 0.5

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

MOVEMENT_SPEED = 5

class MyGame(arcade.Window):
    """ This class represents the main window of the game. """

    def __init__(self):
        """ Initializer """
        # Call the parent class initializer
        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, "Sprite Example")

        # Sprite lists
        self.player_list = None
        self.wall_list = None

        # Set up the player
        self.player_sprite = None

    def setup(self):

        # Set the background color
        arcade.set_background_color(arcade.color.AMAZON)

        # Sprite lists
        self.player_list = arcade.SpriteList()
        self.wall_list = arcade.SpriteList()

        # Reset the score
        self.score = 0

        # Create the player
        self.player_sprite = arcade.Sprite("images/character.png", SPRITE_SCALING_PLAYER)
        self.player_sprite.center_x = 50
        self.player_sprite.center_y = 64
        self.player_list.append(self.player_sprite)

        # --- Manually place walls

        # Manually create and position a box at 300, 200
        wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
        wall.center_x = 300
        wall.center_y = 200
        self.wall_list.append(wall)

        # Manually create and position a box at 364, 200
        wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
        wall.center_x = 364
        wall.center_y = 200
        self.wall_list.append(wall)

        # --- Place boxes inside a loop
        for x in range(173, 650, 64):
            wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
            wall.center_x = x
            wall.center_y = 350
            self.wall_list.append(wall)

        # --- Place walls with a list
        coordinate_list = [[400, 500],
                           [470, 500],
                           [400, 570],
                           [470, 570]]

        # Loop through coordinates
        for coordinate in coordinate_list:
            wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
            wall.center_x = coordinate[0]
            wall.center_y = coordinate[1]
            self.wall_list.append(wall)


    def on_draw(self):
        arcade.start_render()
        self.player_list.draw()
        self.wall_list.draw()


def main():
    """ Main method """
    window = MyGame()
    window.setup()
    arcade.run()


if __name__ == "__main__":
    main()

25.5. Physik-Engine

Zuerst müssen wir die Tastatur mit der Spielfigur verknüpfen:

def on_key_press(self, key, modifiers):
    """Called whenever a key is pressed. """

    if key == arcade.key.UP:
        self.player_sprite.change_y = MOVEMENT_SPEED
    elif key == arcade.key.DOWN:
        self.player_sprite.change_y = -MOVEMENT_SPEED
    elif key == arcade.key.LEFT:
        self.player_sprite.change_x = -MOVEMENT_SPEED
    elif key == arcade.key.RIGHT:
        self.player_sprite.change_x = MOVEMENT_SPEED

def on_key_release(self, key, modifiers):
    """Called when the user releases a key. """

    if key == arcade.key.UP or key == arcade.key.DOWN:
        self.player_sprite.change_y = 0
    elif key == arcade.key.LEFT or key == arcade.key.RIGHT:
        self.player_sprite.change_x = 0

Jetzt müssen wir eine Möglichkeit hinzufügen, die Spielfigur daran zu hindern, in die Wände hinein zu rennen.

Die Arcade-Bibliothek verfügt über eine integrierte „Physik-Engine“. Eine Physik-Engine verwaltet die Interaktionen zwischen den virtuellen physischen Objekten im Spiel. Zum Beispiel kann eine Physik-Engine aus mehreren Bällen bestehen, die aufeinander treffen, eine Spielfigur, die einen Hügel hinunterrutscht, oder einem Auto, das auf der Straße eine Kurve fährt.

Physik-Engines haben beeindruckende Fortschritte erzielt, was sie simulieren können. Für unser Spiel werden wir die Dinge einfach halten und sicherstellen, dass unsere Spielfigur nicht durch Wände gehen kann.

Wir werden ein Attribut für unsere Physik-Engine in __init__ erstellen:

# This variable holds our simple "physics engine"
self.physics_engine = None

Wir können die eigentliche Physik-Engine in unserer setup-Methode mit folgendem Code erstellen:

self.physics_engine = arcade.PhysicsEngineSimple(self.player_sprite, self.wall_list)

Dies identifiziert die Spielfigur (player_sprite) und eine Liste von Sprites (wall_list), die die Spielfigur nicht passieren darf.

Vorher haben wir alle Sprites mit der Anweisung self.all_sprites_list.update() aktualisiert. Mit der Physik-Engine aktualisieren wir stattdessen die Sprites mithilfe des update der Physik-Engine:

def update(self, delta_time):
    self.physics_engine.update()

Die einfache Physik-Engine folgt dem folgenden Algorithmus:

  • Bewege die Spielfigur in x-Richtung entsprechend dem change_x-Wert der Spielfigur.

  • Überprüfe mit der Wandliste, ob Kollisionen mit der Spielfigur vorliegen.

  • Wenn die Spielfigur kollidiert:

    • Wenn sich die Spielfigur nach rechts bewegt, setze die rechte Kante der Spielfigur auf die linke Kante der Wand.

    • Wenn sich die Spielfigur nach links bewegt, setze die linke Kante der Spielfigur auf die rechte Kante der Wand.

    • Wenn sich die Spielfigur nicht nach links oder rechts bewegt, gebe die Nachricht aus, dass wir verwirrt sind, wie wir auf etwas treffen können, wenn wir uns nicht bewegen.

  • Dann machen wir dasselbe, nur mit den y-Koordinaten.

Du kannst dir den Physics Engine Source Code auf GitHub ansehen.

Hier ist das vollständige Beispiel:

sprite_move_walls.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
""" Sprite Sample Program """

import arcade

# --- Constants ---
SPRITE_SCALING_BOX = 0.5
SPRITE_SCALING_PLAYER = 0.5

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

MOVEMENT_SPEED = 5


class MyGame(arcade.Window):
    """ This class represents the main window of the game. """

    def __init__(self):
        """ Initializer """
        # Call the parent class initializer
        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, "Sprite Example")

        # Sprite lists
        self.player_list = None
        self.wall_list = None

        # Set up the player
        self.player_sprite = None

        # This variable holds our simple "physics engine"
        self.physics_engine = None

    def setup(self):

        # Set the background color
        arcade.set_background_color(arcade.color.AMAZON)

        # Sprite lists
        self.player_list = arcade.SpriteList()
        self.wall_list = arcade.SpriteList()

        # Reset the score
        self.score = 0

        # Create the player
        self.player_sprite = arcade.Sprite("images/character.png", SPRITE_SCALING_PLAYER)
        self.player_sprite.center_x = 50
        self.player_sprite.center_y = 64
        self.player_list.append(self.player_sprite)

        # --- Manually place walls

        # Manually create and position a box at 300, 200
        wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
        wall.center_x = 300
        wall.center_y = 200
        self.wall_list.append(wall)

        # Manually create and position a box at 364, 200
        wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
        wall.center_x = 364
        wall.center_y = 200
        self.wall_list.append(wall)

        # --- Place boxes inside a loop
        for x in range(173, 650, 64):
            wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
            wall.center_x = x
            wall.center_y = 350
            self.wall_list.append(wall)

        # --- Place walls with a list
        coordinate_list = [[400, 500],
                           [470, 500],
                           [400, 570],
                           [470, 570]]

        # Loop through coordinates
        for coordinate in coordinate_list:
            wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
            wall.center_x = coordinate[0]
            wall.center_y = coordinate[1]
            self.wall_list.append(wall)

        # Create the physics engine. Give it a reference to the player, and
        # the walls we can't run into.
        self.physics_engine = arcade.PhysicsEngineSimple(self.player_sprite, self.wall_list)

    def on_draw(self):
        arcade.start_render()
        self.wall_list.draw()
        self.player_list.draw()

    def update(self, delta_time):
        self.physics_engine.update()

    def on_key_press(self, key, modifiers):
        """Called whenever a key is pressed. """

        if key == arcade.key.UP:
            self.player_sprite.change_y = MOVEMENT_SPEED
        elif key == arcade.key.DOWN:
            self.player_sprite.change_y = -MOVEMENT_SPEED
        elif key == arcade.key.LEFT:
            self.player_sprite.change_x = -MOVEMENT_SPEED
        elif key == arcade.key.RIGHT:
            self.player_sprite.change_x = MOVEMENT_SPEED

    def on_key_release(self, key, modifiers):
        """Called when the user releases a key. """

        if key == arcade.key.UP or key == arcade.key.DOWN:
            self.player_sprite.change_y = 0
        elif key == arcade.key.LEFT or key == arcade.key.RIGHT:
            self.player_sprite.change_x = 0


def main():
    """ Main method """
    window = MyGame()
    window.setup()
    arcade.run()


if __name__ == "__main__":
    main()

25.6. Verwenden eines Bildausschnitts zum Scrollen

Was ist, wenn ein Bildschirm nicht ausreicht, um Ihr Wandlabyrinth zu enthalten? Wir können eine Welt erstellen, die größer ist als nur unser Fenster. Wir tun dies, indem wir den View Port (Bildausschnitt) anpassen. Normalerweise ist die Koordinate (0, 0) die untere linke Ecke unseres Bildschirms. Das können wir ändern! Wir könnten eine ganze Welt von (0, 0) bis (3000, 3000) haben und einen kleineren Ausschnitt von 800 x 640, in dem wir herum scrollen.

Der Befehl zur Verwendung des Bildausschnitts lautet set_viewport. Dieser Befehl benötigt vier Argumente. Die ersten beiden sind die linken und unteren Grenzen des Fensters. Standardmäßig sind diese Null. Aus diesem Grund befindet sich (0, 0) unten links auf dem Bildschirm. Die nächsten beiden Befehle sind die oberen und rechten Koordinaten des Bildschirms. Standardmäßig sind dies die Bildschirmbreite und -höhe minus eins. Ein 800 Pixel breites Fenster hätte also x-Koordinaten von 0 bis 799.

Eine Anweisung wie die folgende verschiebt die gesamte „Ansicht“ des Fensters um 200 Pixel nach rechts:

# Specify viewport size by (left, right, bottom, top)
arcade.set_viewport(200, 200 + SCREEN_WIDTH - 1, 0, SCREEN_HEIGHT - 1)

Bei einem 800 Pixel breiten Fenster würden wir also die x-Koordinaten 200 - 999 anstelle von 0 - 799 anzeigen.

Anstatt die Verschiebung um 200 Pixel fest zu codieren, müssen wir eine Variable verwenden und Regeln festlegen, wann die Ansicht verschoben werden soll. In unserem nächsten Beispiel erstellen wir zwei neue Objektvariablen in unserer Anwendungsklasse, die die linken und unteren Koordinaten für unseren Bildausschnitt enthalten. Wir werden sie standardmäßig auf Null setzen.

self.view_left = 0
self.view_bottom = 0

We are also going to create two new constants. We don’t want the player to reach the edge of the screen before we start scrolling. Because then the player would have no idea where she is going. In our example we will set a „margin“ of 150 pixels. When the player is 150 pixels from the edge of the screen, we’ll move the view port so she can see at least 150 pixels around her.

VIEWPORT_MARGIN = 150

Als nächstes müssen wir in unserer update-Methode sehen, ob der Benutzer zu nahe am Bildschirmrand ist, und wir müssen die Grenzen aktualisieren.

# Keep track of if we changed the boundary. We don't want to call the
# set_viewport command if we didn't change the view port.
changed = False

# Scroll left
left_boundary = self.view_left + VIEWPORT_MARGIN
if self.player_sprite.left < left_boundary:
    self.view_left -= left_boundary - self.player_sprite.left
    changed = True

# Scroll right
right_boundary = self.view_left + SCREEN_WIDTH - VIEWPORT_MARGIN
if self.player_sprite.right > right_boundary:
    self.view_left += self.player_sprite.right - right_boundary
    changed = True

# Scroll up
top_boundary = self.view_bottom + SCREEN_HEIGHT - VIEWPORT_MARGIN
if self.player_sprite.top > top_boundary:
    self.view_bottom += self.player_sprite.top - top_boundary
    changed = True

# Scroll down
bottom_boundary = self.view_bottom + VIEWPORT_MARGIN
if self.player_sprite.bottom < bottom_boundary:
    self.view_bottom -= bottom_boundary - self.player_sprite.bottom
    changed = True

# Make sure our boundaries are integer values. While the view port does
# support floating point numbers, for this application we want every pixel
# in the view port to map directly onto a pixel on the screen. We don't want
# any rounding errors.
self.view_left = int(self.view_left)
self.view_bottom = int(self.view_bottom)

# If we changed the boundary values, update the view port to match
if changed:
    arcade.set_viewport(self.view_left,
                        SCREEN_WIDTH + self.view_left - 1,
                        self.view_bottom,
                        SCREEN_HEIGHT + self.view_bottom - 1)

Das vollständige Beispiel findest du unten:

sprite_move_scrolling.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
""" Sprite Sample Program """

import arcade

# --- Constants ---
SPRITE_SCALING_BOX = 0.5
SPRITE_SCALING_PLAYER = 0.5

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

MOVEMENT_SPEED = 5

VIEWPORT_MARGIN = 150


class MyGame(arcade.Window):
    """ This class represents the main window of the game. """

    def __init__(self):
        """ Initializer """
        # Call the parent class initializer
        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, "Sprite Example")

        # Sprite lists
        self.player_list = None
        self.wall_list = None

        # Set up the player
        self.player_sprite = None

        # This variable holds our simple "physics engine"
        self.physics_engine = None

        # Manage the view port
        self.view_left = 0
        self.view_bottom = 0

    def setup(self):

        # Set the background color
        arcade.set_background_color(arcade.color.AMAZON)

        # Reset the view port
        self.view_left = 0
        self.view_bottom = 0

        # Sprite lists
        self.player_list = arcade.SpriteList()
        self.wall_list = arcade.SpriteList()

        # Reset the score
        self.score = 0

        # Create the player
        self.player_sprite = arcade.Sprite("images/character.png", SPRITE_SCALING_PLAYER)
        self.player_sprite.center_x = 50
        self.player_sprite.center_y = 64
        self.player_list.append(self.player_sprite)

        # --- Manually place walls

        # Manually create and position a box at 300, 200
        wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
        wall.center_x = 300
        wall.center_y = 200
        self.wall_list.append(wall)

        # Manually create and position a box at 364, 200
        wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
        wall.center_x = 364
        wall.center_y = 200
        self.wall_list.append(wall)

        # --- Place boxes inside a loop
        for x in range(173, 650, 64):
            wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
            wall.center_x = x
            wall.center_y = 350
            self.wall_list.append(wall)

        # --- Place walls with a list
        coordinate_list = [[400, 500],
                           [470, 500],
                           [400, 570],
                           [470, 570]]

        # Loop through coordinates
        for coordinate in coordinate_list:
            wall = arcade.Sprite("images/boxCrate_double.png", SPRITE_SCALING_BOX)
            wall.center_x = coordinate[0]
            wall.center_y = coordinate[1]
            self.wall_list.append(wall)

        # Create the physics engine. Give it a reference to the player, and
        # the walls we can't run into.
        self.physics_engine = arcade.PhysicsEngineSimple(self.player_sprite, self.wall_list)

    def on_draw(self):
        arcade.start_render()
        self.wall_list.draw()
        self.player_list.draw()

    def update(self, delta_time):
        self.physics_engine.update()

        # --- Manage Scrolling ---

        # Keep track of if we changed the boundary. We don't want to call the
        # set_viewport command if we didn't change the view port.
        changed = False

        # Scroll left
        left_boundary = self.view_left + VIEWPORT_MARGIN
        if self.player_sprite.left < left_boundary:
            self.view_left -= left_boundary - self.player_sprite.left
            changed = True

        # Scroll right
        right_boundary = self.view_left + SCREEN_WIDTH - VIEWPORT_MARGIN
        if self.player_sprite.right > right_boundary:
            self.view_left += self.player_sprite.right - right_boundary
            changed = True

        # Scroll up
        top_boundary = self.view_bottom + SCREEN_HEIGHT - VIEWPORT_MARGIN
        if self.player_sprite.top > top_boundary:
            self.view_bottom += self.player_sprite.top - top_boundary
            changed = True

        # Scroll down
        bottom_boundary = self.view_bottom + VIEWPORT_MARGIN
        if self.player_sprite.bottom < bottom_boundary:
            self.view_bottom -= bottom_boundary - self.player_sprite.bottom
            changed = True

        # Make sure our boundaries are integer values. While the view port does
        # support floating point numbers, for this application we want every pixel
        # in the view port to map directly onto a pixel on the screen. We don't want
        # any rounding errors.
        self.view_left = int(self.view_left)
        self.view_bottom = int(self.view_bottom)

        # If we changed the boundary values, update the view port to match
        if changed:
            arcade.set_viewport(self.view_left,
                                SCREEN_WIDTH + self.view_left - 1,
                                self.view_bottom,
                                SCREEN_HEIGHT + self.view_bottom - 1)

    def on_key_press(self, key, modifiers):
        """ Called whenever a key is pressed. """

        if key == arcade.key.UP:
            self.player_sprite.change_y = MOVEMENT_SPEED
        elif key == arcade.key.DOWN:
            self.player_sprite.change_y = -MOVEMENT_SPEED
        elif key == arcade.key.LEFT:
            self.player_sprite.change_x = -MOVEMENT_SPEED
        elif key == arcade.key.RIGHT:
            self.player_sprite.change_x = MOVEMENT_SPEED

    def on_key_release(self, key, modifiers):
        """Called when the user releases a key. """

        if key == arcade.key.UP or key == arcade.key.DOWN:
            self.player_sprite.change_y = 0
        elif key == arcade.key.LEFT or key == arcade.key.RIGHT:
            self.player_sprite.change_x = 0


def main():
    """ Main method """
    window = MyGame()
    window.setup()
    arcade.run()


if __name__ == "__main__":
    main()