Step 8 - Display The Score#
Now that we can collect coins and get points, we need a way to display the score on the screen.
This process is a little bit more complex than just drawing some text at an X and Y location. For properly drawing text, or any GUI elements, we need to use a separate camera than the one we use to draw the rest of our scene.
This is because we are scrolling around the main game camera, but we want our GUI elements to stay still. Using a second camera lets us do this.
As an example, if we were not to use a second camera, and instead draw on the same camera as our scene. We would need to offset the position that we draw our text at by position of the camera. This might be easier if you’re only displaying one thing, but if you have a lot of GUI elements this could get out of hand.
First start by creating the new GUI camera and the score variables in the __init__
function.
self.camera = None
# A Camera that can be used to draw GUI elements
self.gui_camera = None
Then we can initialize them in the setup
function. We reset the score to 0 here because this
function is intended to fully reset the game back to it’s starting state.
self.camera = arcade.SimpleCamera(viewport=(0, 0, self.width, self.height))
# Set up the GUI Camera
self.gui_camera = arcade.SimpleCamera(viewport=(0, 0, self.width, self.height))
Then in our on_draw
function we can first draw our scene like normal, and then switch to the
GUI camera, and then finally draw our text.
)
def on_draw(self):
"""Render the screen."""
# Clear the screen to the background color
self.clear()
# Activate the game camera
self.camera.use()
# Draw our Scene
self.scene.draw()
# Activate the GUI camera before drawing GUI elements
self.gui_camera.use()
# Draw our score on the screen, scrolling it with the viewport
score_text = f"Score: {self.score}"
arcade.draw_text(
score_text,
10,
10,
arcade.csscolor.WHITE,
Lastly in the on_update
function we just need to update the score when a player collects a coin:
)
# Loop through each coin we hit (if any) and remove it
for coin in coin_hit_list:
# Remove the coin
coin.remove_from_sprite_lists()
# Play a sound
arcade.play_sound(self.collect_coin_sound)
Note
You might also want to add:
A count of how many coins are left to be collected.
Number of lives left.
A timer: On-Screen Timer
This example shows how to add an FPS timer: Draw Moving Sprites Stress Test
Source Code#
1"""
2Platformer Game
3
4python -m arcade.examples.platform_tutorial.08_score
5"""
6import arcade
7
8# Constants
9SCREEN_WIDTH = 1000
10SCREEN_HEIGHT = 650
11SCREEN_TITLE = "Platformer"
12
13# Constants used to scale our sprites from their original size
14CHARACTER_SCALING = 1
15TILE_SCALING = 0.5
16COIN_SCALING = 0.5
17
18# Movement speed of player, in pixels per frame
19PLAYER_MOVEMENT_SPEED = 5
20GRAVITY = 1
21PLAYER_JUMP_SPEED = 20
22
23
24class MyGame(arcade.Window):
25 """
26 Main application class.
27 """
28
29 def __init__(self):
30
31 # Call the parent class and set up the window
32 super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
33
34 # Our Scene Object
35 self.scene = None
36
37 # Separate variable that holds the player sprite
38 self.player_sprite = None
39
40 # Our physics engine
41 self.physics_engine = None
42
43 # A Camera that can be used for scrolling the screen
44 self.camera = None
45
46 # A Camera that can be used to draw GUI elements
47 self.gui_camera = None
48
49 # Keep track of the score
50 self.score = 0
51
52 # Load sounds
53 self.collect_coin_sound = arcade.load_sound(":resources:sounds/coin1.wav")
54 self.jump_sound = arcade.load_sound(":resources:sounds/jump1.wav")
55
56 self.background_color = arcade.csscolor.CORNFLOWER_BLUE
57
58 def setup(self):
59 """Set up the game here. Call this function to restart the game."""
60
61 # Set up the Game Camera
62 self.camera = arcade.SimpleCamera(viewport=(0, 0, self.width, self.height))
63
64 # Set up the GUI Camera
65 self.gui_camera = arcade.SimpleCamera(viewport=(0, 0, self.width, self.height))
66
67 # Keep track of the score
68 self.score = 0
69
70 # Initialize Scene
71 self.scene = arcade.Scene()
72
73 # Set up the player, specifically placing it at these coordinates.
74 image_source = ":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png"
75 self.player_sprite = arcade.Sprite(image_source, CHARACTER_SCALING)
76 self.player_sprite.center_x = 64
77 self.player_sprite.center_y = 96
78 self.scene.add_sprite("Player", self.player_sprite)
79
80 # Create the ground
81 # This shows using a loop to place multiple sprites horizontally
82 for x in range(0, 1250, 64):
83 wall = arcade.Sprite(":resources:images/tiles/grassMid.png", TILE_SCALING)
84 wall.center_x = x
85 wall.center_y = 32
86 self.scene.add_sprite("Walls", wall)
87
88 # Put some crates on the ground
89 # This shows using a coordinate list to place sprites
90 coordinate_list = [[512, 96], [256, 96], [768, 96]]
91
92 for coordinate in coordinate_list:
93 # Add a crate on the ground
94 wall = arcade.Sprite(
95 ":resources:images/tiles/boxCrate_double.png", TILE_SCALING
96 )
97 wall.position = coordinate
98 self.scene.add_sprite("Walls", wall)
99
100 # Use a loop to place some coins for our character to pick up
101 for x in range(128, 1250, 256):
102 coin = arcade.Sprite(":resources:images/items/coinGold.png", COIN_SCALING)
103 coin.center_x = x
104 coin.center_y = 96
105 self.scene.add_sprite("Coins", coin)
106
107 # Create the 'physics engine'
108 self.physics_engine = arcade.PhysicsEnginePlatformer(
109 self.player_sprite, gravity_constant=GRAVITY, walls=self.scene["Walls"]
110 )
111
112 def on_draw(self):
113 """Render the screen."""
114
115 # Clear the screen to the background color
116 self.clear()
117
118 # Activate the game camera
119 self.camera.use()
120
121 # Draw our Scene
122 self.scene.draw()
123
124 # Activate the GUI camera before drawing GUI elements
125 self.gui_camera.use()
126
127 # Draw our score on the screen, scrolling it with the viewport
128 score_text = f"Score: {self.score}"
129 arcade.draw_text(
130 score_text,
131 10,
132 10,
133 arcade.csscolor.WHITE,
134 18,
135 )
136
137 def on_key_press(self, key, modifiers):
138 """Called whenever a key is pressed."""
139
140 if key == arcade.key.UP or key == arcade.key.W:
141 if self.physics_engine.can_jump():
142 self.player_sprite.change_y = PLAYER_JUMP_SPEED
143 arcade.play_sound(self.jump_sound)
144 elif key == arcade.key.LEFT or key == arcade.key.A:
145 self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
146 elif key == arcade.key.RIGHT or key == arcade.key.D:
147 self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
148
149 def on_key_release(self, key, modifiers):
150 """Called when the user releases a key."""
151
152 if key == arcade.key.LEFT or key == arcade.key.A:
153 self.player_sprite.change_x = 0
154 elif key == arcade.key.RIGHT or key == arcade.key.D:
155 self.player_sprite.change_x = 0
156
157 def center_camera_to_player(self):
158 screen_center_x = self.player_sprite.center_x - (self.camera.viewport_width / 2)
159 screen_center_y = self.player_sprite.center_y - (
160 self.camera.viewport_height / 2
161 )
162 if screen_center_x < 0:
163 screen_center_x = 0
164 if screen_center_y < 0:
165 screen_center_y = 0
166 player_centered = screen_center_x, screen_center_y
167
168 self.camera.move_to(player_centered)
169
170 def on_update(self, delta_time):
171 """Movement and game logic"""
172
173 # Move the player with the physics engine
174 self.physics_engine.update()
175
176 # See if we hit any coins
177 coin_hit_list = arcade.check_for_collision_with_list(
178 self.player_sprite, self.scene["Coins"]
179 )
180
181 # Loop through each coin we hit (if any) and remove it
182 for coin in coin_hit_list:
183 # Remove the coin
184 coin.remove_from_sprite_lists()
185 # Play a sound
186 arcade.play_sound(self.collect_coin_sound)
187 # Add one to the score
188 self.score += 1
189
190 # Position the camera
191 self.center_camera_to_player()
192
193
194def main():
195 """Main function"""
196 window = MyGame()
197 window.setup()
198 arcade.run()
199
200
201if __name__ == "__main__":
202 main()