Platformer Template#
Quickly get started creating your own platformer!
About This Template#
This is a template to get you started coding a side-scrolling platformer as quickly as possible. I recommend the following steps:
Create a folder to hold the code. Copy this example to that folder, and call it
main.py
.Make sure the example code runs fine.
Copy the tile images you want to use to a subdirectory of the folder that holds your code.
Create a very simple Tiled Map using the Tiled Map Editor. I suggest just creating a floor and nothing else. For more detail on how to create a tiled map, see Step 9 - Adding Sound.
Save the file to the same directory as your source code. If you create a separate tileset, also save it to the same directory as your code.
Update the code to load your file instead of the map.
Test and make sure it works.
Now that you are sure things work, make your own platformer!
Warning
Watch the directories!
One of the most frequent mistakes is to save maps and tile sets to a directory that isn’t the same directory as your code. Or to not have the tile images in that folder. If everything isn’t in the same folder (or a subfolder of that) it is hard to package it up later.
For more detailed instructions, see the tutorial Simple Platformer.
Source Code#
1"""
2Platformer Template
3
4If Python and Arcade are installed, this example can be run from the command line with:
5python -m arcade.examples.template_platformer
6"""
7import arcade
8
9# --- Constants
10SCREEN_TITLE = "Platformer"
11
12SCREEN_WIDTH = 1000
13SCREEN_HEIGHT = 650
14
15# Constants used to scale our sprites from their original size
16CHARACTER_SCALING = 1
17TILE_SCALING = 0.5
18COIN_SCALING = 0.5
19SPRITE_PIXEL_SIZE = 128
20GRID_PIXEL_SIZE = SPRITE_PIXEL_SIZE * TILE_SCALING
21
22# Movement speed of player, in pixels per frame
23PLAYER_MOVEMENT_SPEED = 10
24GRAVITY = 1
25PLAYER_JUMP_SPEED = 20
26
27
28class MyGame(arcade.Window):
29 """
30 Main application class.
31 """
32
33 def __init__(self):
34
35 # Call the parent class and set up the window
36 super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT,
37 SCREEN_TITLE, resizable=True)
38
39 # Our TileMap Object
40 self.tile_map = None
41
42 # Our Scene Object
43 self.scene = None
44
45 # Separate variable that holds the player sprite
46 self.player_sprite = None
47
48 # Our physics engine
49 self.physics_engine = None
50
51 # A Camera that can be used for scrolling the screen
52 self.camera_sprites = None
53
54 # A non-scrolling camera that can be used to draw GUI elements
55 self.camera_gui = None
56
57 # Keep track of the score
58 self.score = 0
59
60 # What key is pressed down?
61 self.left_key_down = False
62 self.right_key_down = False
63
64 def setup(self):
65 """Set up the game here. Call this function to restart the game."""
66
67 # Setup the Cameras
68 self.camera_sprites = arcade.SimpleCamera()
69 self.camera_gui = arcade.SimpleCamera()
70
71 # Name of map file to load
72 map_name = ":resources:tiled_maps/map.json"
73
74 # Layer specific options are defined based on Layer names in a dictionary
75 # Doing this will make the SpriteList for the platforms layer
76 # use spatial hashing for detection.
77 layer_options = {
78 "Platforms": {
79 "use_spatial_hash": True,
80 },
81 }
82
83 # Read in the tiled map
84 self.tile_map = arcade.load_tilemap(map_name, TILE_SCALING, layer_options)
85
86 # Initialize Scene with our TileMap, this will automatically add all layers
87 # from the map as SpriteLists in the scene in the proper order.
88 self.scene = arcade.Scene.from_tilemap(self.tile_map)
89
90 # Set the background color
91 if self.tile_map.background_color:
92 self.background_color = self.tile_map.background_color
93
94 # Keep track of the score
95 self.score = 0
96
97 # Set up the player, specifically placing it at these coordinates.
98 src = ":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png"
99 self.player_sprite = arcade.Sprite(src, scale=CHARACTER_SCALING)
100 self.player_sprite.center_x = 128
101 self.player_sprite.center_y = 128
102 self.scene.add_sprite("Player", self.player_sprite)
103
104 # --- Other stuff
105 # Create the 'physics engine'
106 self.physics_engine = arcade.PhysicsEnginePlatformer(
107 self.player_sprite, gravity_constant=GRAVITY, walls=self.scene["Platforms"]
108 )
109
110 def on_draw(self):
111 """Render the screen."""
112
113 # Clear the screen to the background color
114 self.clear()
115
116 # Activate the game camera
117 self.camera_sprites.use()
118
119 # Draw our Scene
120 # Note, if you a want pixelated look, add pixelated=True to the parameters
121 self.scene.draw()
122
123 # Activate the GUI camera before drawing GUI elements
124 self.camera_gui.use()
125
126 # Draw our score on the screen, scrolling it with the viewport
127 score_text = f"Score: {self.score}"
128 arcade.draw_text(score_text,
129 start_x=10,
130 start_y=10,
131 color=arcade.csscolor.WHITE,
132 font_size=18)
133
134 def update_player_speed(self):
135
136 # Calculate speed based on the keys pressed
137 self.player_sprite.change_x = 0
138
139 if self.left_key_down and not self.right_key_down:
140 self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
141 elif self.right_key_down and not self.left_key_down:
142 self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
143
144 def on_key_press(self, key, modifiers):
145 """Called whenever a key is pressed."""
146
147 # Jump
148 if key == arcade.key.UP or key == arcade.key.W:
149 if self.physics_engine.can_jump():
150 self.player_sprite.change_y = PLAYER_JUMP_SPEED
151
152 # Left
153 elif key == arcade.key.LEFT or key == arcade.key.A:
154 self.left_key_down = True
155 self.update_player_speed()
156
157 # Right
158 elif key == arcade.key.RIGHT or key == arcade.key.D:
159 self.right_key_down = True
160 self.update_player_speed()
161
162 def on_key_release(self, key, modifiers):
163 """Called when the user releases a key."""
164 if key == arcade.key.LEFT or key == arcade.key.A:
165 self.left_key_down = False
166 self.update_player_speed()
167 elif key == arcade.key.RIGHT or key == arcade.key.D:
168 self.right_key_down = False
169 self.update_player_speed()
170
171 def center_camera_to_player(self):
172 # Find where player is, then calculate lower left corner from that
173 screen_center_x = self.player_sprite.center_x - (self.camera_sprites.viewport_width / 2)
174 screen_center_y = self.player_sprite.center_y - (self.camera_sprites.viewport_height / 2)
175
176 # Set some limits on how far we scroll
177 if screen_center_x < 0:
178 screen_center_x = 0
179 if screen_center_y < 0:
180 screen_center_y = 0
181
182 # Here's our center, move to it
183 player_centered = screen_center_x, screen_center_y
184 self.camera_sprites.move_to(player_centered)
185
186 def on_update(self, delta_time):
187 """Movement and game logic"""
188
189 # Move the player with the physics engine
190 self.physics_engine.update()
191
192 # See if we hit any coins
193 coin_hit_list = arcade.check_for_collision_with_list(
194 self.player_sprite, self.scene["Coins"]
195 )
196
197 # Loop through each coin we hit (if any) and remove it
198 for coin in coin_hit_list:
199 # Remove the coin
200 coin.remove_from_sprite_lists()
201 # Add one to the score
202 self.score += 1
203
204 # Position the camera
205 self.center_camera_to_player()
206
207 def on_resize(self, width: int, height: int):
208 """ Resize window """
209 self.camera_sprites.resize(width, height)
210 self.camera_gui.resize(width, height)
211
212
213def main():
214 """Main function"""
215 window = MyGame()
216 window.setup()
217 arcade.run()
218
219
220if __name__ == "__main__":
221 main()