Step 8 - Collecting Coins

Now that we can fully move around our game, we need to give the player an objective. A classic goal in video games is collecting coins, so let’s go ahead and add that.

In this chapter you will learn how to check for collisions with our player, and find out exactly what they collided with and do something with it. For now we will just remove the coin from the screen when they collect it, but in later chapters we will give the character a score, and add to it when they collect a coin. We will also start playing sounds later.

First off we will create a new SpriteList to hold our coins. Exactly like our other spritelist for walls, go ahead and add a variable to the __init__ function to store it, and then initialize it inside the setup function. We will want to turn on spatial hashing for this list for now. If you decided to have moving coins, you would want to turn that off.

# Inside __init__
self.coin_list = None

# Inside setup
self.coin_list = arcade.SpriteList(use_spatial_hash=True)

See if you can experiment with a way to add the coins to the SpriteList using what we’ve already learned. The built-in resource for them is :resources:images/items/coinGold.png. HINT: You’ll want to scale these just like we did with our boxes and ground. If you get stuck, you can check the full source code below to see how we’ve placed them following the same pattern we used for the ground.

Once you have placed the coins and added them to the coin_list, don’t forget to add them to on_draw.

self.coin_list.draw()

Now that we’re drawing our coins to the screen, how do we make them interact with the player? When the player hits one, we want to remove it from the screen. To do this we will use arcade.check_for_collision_with_list() function. This function takes a single Sprite, in this instance our player, and a SpriteList, for us, the coins. It will return a list containing all of the Sprites from the given SpriteList that the Sprite collided with.

We can iterate over that list with a for loop to do something with each sprite that had a collision. This means we can detect the user hitting multiple coins at once if we had them placed close together.

In order to do this, and remove the coin sprites when the player hits them, we will add this to the on_update function.

coin_hit_list = arcade.check_for_collision_with_list(
    self.player_sprite, self.coin_list
)

for coin in coin_hit_list:
    coin.remove_from_sprite_lists()

We use this arcade.BasicSprite.remove_from_sprite_lists() function in order to ensure our Sprite is completely removed from all SpriteLists it was a part of.

Source Code

Collecting Coins
  1"""
  2Platformer Game
  3
  4python -m arcade.examples.platform_tutorial.08_coins
  5"""
  6import arcade
  7
  8# Constants
  9SCREEN_WIDTH = 800
 10SCREEN_HEIGHT = 600
 11SCREEN_TITLE = "Platformer"
 12
 13# Constants used to scale our sprites from their original size
 14TILE_SCALING = 0.5
 15COIN_SCALING = 0.5
 16
 17# Movement speed of player, in pixels per frame
 18PLAYER_MOVEMENT_SPEED = 5
 19GRAVITY = 1
 20PLAYER_JUMP_SPEED = 20
 21
 22
 23class MyGame(arcade.Window):
 24    """
 25    Main application class.
 26    """
 27
 28    def __init__(self):
 29
 30        # Call the parent class and set up the window
 31        super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
 32
 33        # Variable to hold our texture for our player
 34        self.player_texture = None
 35
 36        # Separate variable that holds the player sprite
 37        self.player_sprite = None
 38
 39        # SpriteList for our player
 40        self.player_list = None
 41
 42        # SpriteList for our boxes and ground
 43        # Putting our ground and box Sprites in the same SpriteList
 44        # will make it easier to perform collision detection against
 45        # them later on. Setting the spatial hash to True will make
 46        # collision detection much faster if the objects in this
 47        # SpriteList do not move.
 48        self.wall_list = None
 49
 50        # SpriteList for coins the player can collect
 51        self.coin_list = None
 52
 53        # A variable to store our camera object
 54        self.camera = None
 55
 56    def setup(self):
 57        """Set up the game here. Call this function to restart the game."""
 58        self.player_texture = arcade.load_texture(":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png")
 59
 60        self.player_sprite = arcade.Sprite(self.player_texture)
 61        self.player_sprite.center_x = 64
 62        self.player_sprite.center_y = 128
 63
 64        self.player_list = arcade.SpriteList()
 65        self.player_list.append(self.player_sprite)
 66
 67        self.wall_list = arcade.SpriteList(use_spatial_hash=True)
 68        self.coin_list = arcade.SpriteList(use_spatial_hash=True)
 69
 70        # Create the ground
 71        # This shows using a loop to place multiple sprites horizontally
 72        for x in range(0, 1250, 64):
 73            wall = arcade.Sprite(":resources:images/tiles/grassMid.png", scale=TILE_SCALING)
 74            wall.center_x = x
 75            wall.center_y = 32
 76            self.wall_list.append(wall)
 77
 78        # Put some crates on the ground
 79        # This shows using a coordinate list to place sprites
 80        coordinate_list = [[512, 96], [256, 96], [768, 96]]
 81
 82        for coordinate in coordinate_list:
 83            # Add a crate on the ground
 84            wall = arcade.Sprite(
 85                ":resources:images/tiles/boxCrate_double.png", scale=TILE_SCALING
 86            )
 87            wall.position = coordinate
 88            self.wall_list.append(wall)
 89
 90        # Add coins to the world
 91        for x in range(128, 1250, 256):
 92            coin = arcade.Sprite(":resources:images/items/coinGold.png", scale=COIN_SCALING)
 93            coin.center_x = x
 94            coin.center_y = 96
 95            self.coin_list.append(coin)
 96
 97        # Create a Platformer Physics Engine, this will handle moving our
 98        # player as well as collisions between the player sprite and
 99        # whatever SpriteList we specify for the walls.
100        # It is important to supply static to the walls parameter. There is a
101        # platforms parameter that is intended for moving platforms.
102        # If a platform is supposed to move, and is added to the walls list,
103        # it will not be moved.
104        self.physics_engine = arcade.PhysicsEnginePlatformer(
105            self.player_sprite, walls=self.wall_list, gravity_constant=GRAVITY
106        )
107
108        # Initialize our camera, setting a viewport the size of our window.
109        self.camera = arcade.camera.Camera2D()
110
111        self.background_color = arcade.csscolor.CORNFLOWER_BLUE
112
113    def on_draw(self):
114        """Render the screen."""
115
116        # Clear the screen to the background color
117        self.clear()
118
119        # Activate our camera before drawing
120        self.camera.use()
121
122        # Draw our sprites
123        self.player_list.draw()
124        self.wall_list.draw()
125        self.coin_list.draw()
126
127    def on_update(self, delta_time):
128        """Movement and Game Logic"""
129
130        # Move the player using our physics engine
131        self.physics_engine.update()
132
133        # See if we hit any coins
134        coin_hit_list = arcade.check_for_collision_with_list(
135            self.player_sprite, self.coin_list
136        )
137
138        # Loop through each coin we hit (if any) and remove it
139        for coin in coin_hit_list:
140            # Remove the coin
141            coin.remove_from_sprite_lists()
142
143        # Center our camera on the player
144        self.camera.position = self.player_sprite.position
145
146    def on_key_press(self, key, modifiers):
147        """Called whenever a key is pressed."""
148
149        if key == arcade.key.ESCAPE:
150            self.setup()
151
152        if key == arcade.key.UP or key == arcade.key.W:
153            if self.physics_engine.can_jump():
154                self.player_sprite.change_y = PLAYER_JUMP_SPEED
155
156        if key == arcade.key.LEFT or key == arcade.key.A:
157            self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
158        elif key == arcade.key.RIGHT or key == arcade.key.D:
159            self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
160
161    def on_key_release(self, key, modifiers):
162        """Called whenever a key is released."""
163
164        if key == arcade.key.LEFT or key == arcade.key.A:
165            self.player_sprite.change_x = 0
166        elif key == arcade.key.RIGHT or key == arcade.key.D:
167            self.player_sprite.change_x = 0
168
169
170def main():
171    """Main function"""
172    window = MyGame()
173    window.setup()
174    arcade.run()
175
176
177if __name__ == "__main__":
178    main()

Run This Chapter

python -m arcade.examples.platform_tutorial.08_coins