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
  9WINDOW_WIDTH = 1280
 10WINDOW_HEIGHT = 720
 11WINDOW_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 GameView(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__(WINDOW_WIDTH, WINDOW_HEIGHT, WINDOW_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(
 59            ":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png"
 60        )
 61
 62        self.player_sprite = arcade.Sprite(self.player_texture)
 63        self.player_sprite.center_x = 64
 64        self.player_sprite.center_y = 128
 65
 66        self.player_list = arcade.SpriteList()
 67        self.player_list.append(self.player_sprite)
 68
 69        self.wall_list = arcade.SpriteList(use_spatial_hash=True)
 70        self.coin_list = arcade.SpriteList(use_spatial_hash=True)
 71
 72        # Create the ground
 73        # This shows using a loop to place multiple sprites horizontally
 74        for x in range(0, 1250, 64):
 75            wall = arcade.Sprite(":resources:images/tiles/grassMid.png", scale=TILE_SCALING)
 76            wall.center_x = x
 77            wall.center_y = 32
 78            self.wall_list.append(wall)
 79
 80        # Put some crates on the ground
 81        # This shows using a coordinate list to place sprites
 82        coordinate_list = [[512, 96], [256, 96], [768, 96]]
 83
 84        for coordinate in coordinate_list:
 85            # Add a crate on the ground
 86            wall = arcade.Sprite(
 87                ":resources:images/tiles/boxCrate_double.png", scale=TILE_SCALING
 88            )
 89            wall.position = coordinate
 90            self.wall_list.append(wall)
 91
 92        # Add coins to the world
 93        for x in range(128, 1250, 256):
 94            coin = arcade.Sprite(":resources:images/items/coinGold.png", scale=COIN_SCALING)
 95            coin.center_x = x
 96            coin.center_y = 96
 97            self.coin_list.append(coin)
 98
 99        # Create a Platformer Physics Engine, this will handle moving our
100        # player as well as collisions between the player sprite and
101        # whatever SpriteList we specify for the walls.
102        # It is important to supply static to the walls parameter. There is a
103        # platforms parameter that is intended for moving platforms.
104        # If a platform is supposed to move, and is added to the walls list,
105        # it will not be moved.
106        self.physics_engine = arcade.PhysicsEnginePlatformer(
107            self.player_sprite, walls=self.wall_list, gravity_constant=GRAVITY
108        )
109
110        # Initialize our camera, setting a viewport the size of our window.
111        self.camera = arcade.camera.Camera2D()
112
113        self.background_color = arcade.csscolor.CORNFLOWER_BLUE
114
115    def on_draw(self):
116        """Render the screen."""
117
118        # Clear the screen to the background color
119        self.clear()
120
121        # Activate our camera before drawing
122        self.camera.use()
123
124        # Draw our sprites
125        self.player_list.draw()
126        self.wall_list.draw()
127        self.coin_list.draw()
128
129    def on_update(self, delta_time):
130        """Movement and Game Logic"""
131
132        # Move the player using our physics engine
133        self.physics_engine.update()
134
135        # See if we hit any coins
136        coin_hit_list = arcade.check_for_collision_with_list(
137            self.player_sprite, self.coin_list
138        )
139
140        # Loop through each coin we hit (if any) and remove it
141        for coin in coin_hit_list:
142            # Remove the coin
143            coin.remove_from_sprite_lists()
144
145        # Center our camera on the player
146        self.camera.position = self.player_sprite.position
147
148    def on_key_press(self, key, modifiers):
149        """Called whenever a key is pressed."""
150
151        if key == arcade.key.ESCAPE:
152            self.setup()
153
154        if key == arcade.key.UP or key == arcade.key.W:
155            if self.physics_engine.can_jump():
156                self.player_sprite.change_y = PLAYER_JUMP_SPEED
157
158        if key == arcade.key.LEFT or key == arcade.key.A:
159            self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
160        elif key == arcade.key.RIGHT or key == arcade.key.D:
161            self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
162
163    def on_key_release(self, key, modifiers):
164        """Called whenever a key is released."""
165
166        if key == arcade.key.LEFT or key == arcade.key.A:
167            self.player_sprite.change_x = 0
168        elif key == arcade.key.RIGHT or key == arcade.key.D:
169            self.player_sprite.change_x = 0
170
171
172def main():
173    """Main function"""
174    window = GameView()
175    window.setup()
176    arcade.run()
177
178
179if __name__ == "__main__":
180    main()

Run This Chapter

python -m arcade.examples.platform_tutorial.08_coins