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.
# A Camera that can be used for scrolling the screen
self.camera = None
# A Camera that can be used to draw GUI elements
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.
# Set up the Game Camera
self.camera = arcade.SimpleCamera(viewport=(0, 0, self.width, self.height))
# Set up the GUI Camera
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.
self.physics_engine = arcade.PhysicsEnginePlatformer(
self.player_sprite, gravity_constant=GRAVITY, walls=self.scene["Walls"]
)
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,
Lastly in the on_update
function we just need to update the score when a player collects a coin:
coin_hit_list = arcade.check_for_collision_with_list(
self.player_sprite, self.scene["Coins"]
)
# 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()
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"""
6from __future__ import annotations
7
8import arcade
9
10# Constants
11SCREEN_WIDTH = 1000
12SCREEN_HEIGHT = 650
13SCREEN_TITLE = "Platformer"
14
15# Constants used to scale our sprites from their original size
16CHARACTER_SCALING = 1
17TILE_SCALING = 0.5
18COIN_SCALING = 0.5
19
20# Movement speed of player, in pixels per frame
21PLAYER_MOVEMENT_SPEED = 5
22GRAVITY = 1
23PLAYER_JUMP_SPEED = 20
24
25
26class MyGame(arcade.Window):
27 """
28 Main application class.
29 """
30
31 def __init__(self):
32
33 # Call the parent class and set up the window
34 super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT, SCREEN_TITLE)
35
36 # Our Scene Object
37 self.scene = None
38
39 # Separate variable that holds the player sprite
40 self.player_sprite = None
41
42 # Our physics engine
43 self.physics_engine = None
44
45 # A Camera that can be used for scrolling the screen
46 self.camera = None
47
48 # A Camera that can be used to draw GUI elements
49 self.gui_camera = None
50
51 # Keep track of the score
52 self.score = 0
53
54 # Load sounds
55 self.collect_coin_sound = arcade.load_sound(":resources:sounds/coin1.wav")
56 self.jump_sound = arcade.load_sound(":resources:sounds/jump1.wav")
57
58 self.background_color = arcade.csscolor.CORNFLOWER_BLUE
59
60 def setup(self):
61 """Set up the game here. Call this function to restart the game."""
62
63 # Set up the Game Camera
64 self.camera = arcade.SimpleCamera(viewport=(0, 0, self.width, self.height))
65
66 # Set up the GUI Camera
67 self.gui_camera = arcade.SimpleCamera(viewport=(0, 0, self.width, self.height))
68
69 # Keep track of the score
70 self.score = 0
71
72 # Initialize Scene
73 self.scene = arcade.Scene()
74
75 # Set up the player, specifically placing it at these coordinates.
76 image_source = ":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png"
77 self.player_sprite = arcade.Sprite(image_source, CHARACTER_SCALING)
78 self.player_sprite.center_x = 64
79 self.player_sprite.center_y = 96
80 self.scene.add_sprite("Player", self.player_sprite)
81
82 # Create the ground
83 # This shows using a loop to place multiple sprites horizontally
84 for x in range(0, 1250, 64):
85 wall = arcade.Sprite(":resources:images/tiles/grassMid.png", TILE_SCALING)
86 wall.center_x = x
87 wall.center_y = 32
88 self.scene.add_sprite("Walls", wall)
89
90 # Put some crates on the ground
91 # This shows using a coordinate list to place sprites
92 coordinate_list = [[512, 96], [256, 96], [768, 96]]
93
94 for coordinate in coordinate_list:
95 # Add a crate on the ground
96 wall = arcade.Sprite(
97 ":resources:images/tiles/boxCrate_double.png", TILE_SCALING
98 )
99 wall.position = coordinate
100 self.scene.add_sprite("Walls", wall)
101
102 # Use a loop to place some coins for our character to pick up
103 for x in range(128, 1250, 256):
104 coin = arcade.Sprite(":resources:images/items/coinGold.png", COIN_SCALING)
105 coin.center_x = x
106 coin.center_y = 96
107 self.scene.add_sprite("Coins", coin)
108
109 # Create the 'physics engine'
110 self.physics_engine = arcade.PhysicsEnginePlatformer(
111 self.player_sprite, gravity_constant=GRAVITY, walls=self.scene["Walls"]
112 )
113
114 def on_draw(self):
115 """Render the screen."""
116
117 # Clear the screen to the background color
118 self.clear()
119
120 # Activate the game camera
121 self.camera.use()
122
123 # Draw our Scene
124 self.scene.draw()
125
126 # Activate the GUI camera before drawing GUI elements
127 self.gui_camera.use()
128
129 # Draw our score on the screen, scrolling it with the viewport
130 score_text = f"Score: {self.score}"
131 arcade.draw_text(
132 score_text,
133 10,
134 10,
135 arcade.csscolor.WHITE,
136 18,
137 )
138
139 def on_key_press(self, key, modifiers):
140 """Called whenever a key is pressed."""
141
142 if key == arcade.key.UP or key == arcade.key.W:
143 if self.physics_engine.can_jump():
144 self.player_sprite.change_y = PLAYER_JUMP_SPEED
145 arcade.play_sound(self.jump_sound)
146 elif key == arcade.key.LEFT or key == arcade.key.A:
147 self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
148 elif key == arcade.key.RIGHT or key == arcade.key.D:
149 self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
150
151 def on_key_release(self, key, modifiers):
152 """Called when the user releases a key."""
153
154 if key == arcade.key.LEFT or key == arcade.key.A:
155 self.player_sprite.change_x = 0
156 elif key == arcade.key.RIGHT or key == arcade.key.D:
157 self.player_sprite.change_x = 0
158
159 def center_camera_to_player(self):
160 screen_center_x = self.player_sprite.center_x - (self.camera.viewport_width / 2)
161 screen_center_y = self.player_sprite.center_y - (
162 self.camera.viewport_height / 2
163 )
164 if screen_center_x < 0:
165 screen_center_x = 0
166 if screen_center_y < 0:
167 screen_center_y = 0
168 player_centered = screen_center_x, screen_center_y
169
170 self.camera.move_to(player_centered)
171
172 def on_update(self, delta_time):
173 """Movement and game logic"""
174
175 # Move the player with the physics engine
176 self.physics_engine.update()
177
178 # See if we hit any coins
179 coin_hit_list = arcade.check_for_collision_with_list(
180 self.player_sprite, self.scene["Coins"]
181 )
182
183 # Loop through each coin we hit (if any) and remove it
184 for coin in coin_hit_list:
185 # Remove the coin
186 coin.remove_from_sprite_lists()
187 # Play a sound
188 arcade.play_sound(self.collect_coin_sound)
189 # Add one to the score
190 self.score += 1
191
192 # Position the camera
193 self.center_camera_to_player()
194
195
196def main():
197 """Main function"""
198 window = MyGame()
199 window.setup()
200 arcade.run()
201
202
203if __name__ == "__main__":
204 main()