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 - Use Tiled Map Editor.
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"""
7from __future__ import annotations
8
9import arcade
10
11# --- Constants
12SCREEN_TITLE = "Platformer"
13
14SCREEN_WIDTH = 1000
15SCREEN_HEIGHT = 650
16
17# Constants used to scale our sprites from their original size
18CHARACTER_SCALING = 1
19TILE_SCALING = 0.5
20COIN_SCALING = 0.5
21SPRITE_PIXEL_SIZE = 128
22GRID_PIXEL_SIZE = SPRITE_PIXEL_SIZE * TILE_SCALING
23
24# Movement speed of player, in pixels per frame
25PLAYER_MOVEMENT_SPEED = 10
26GRAVITY = 1
27PLAYER_JUMP_SPEED = 20
28
29
30class MyGame(arcade.Window):
31 """
32 Main application class.
33 """
34
35 def __init__(self):
36
37 # Call the parent class and set up the window
38 super().__init__(SCREEN_WIDTH, SCREEN_HEIGHT,
39 SCREEN_TITLE, resizable=True)
40
41 # Our TileMap Object
42 self.tile_map = None
43
44 # Our Scene Object
45 self.scene = None
46
47 # Separate variable that holds the player sprite
48 self.player_sprite = None
49
50 # Our physics engine
51 self.physics_engine = None
52
53 # A Camera that can be used for scrolling the screen
54 self.camera_sprites = None
55
56 # A non-scrolling camera that can be used to draw GUI elements
57 self.camera_gui = None
58
59 # Keep track of the score
60 self.score = 0
61
62 # What key is pressed down?
63 self.left_key_down = False
64 self.right_key_down = False
65
66 def setup(self):
67 """Set up the game here. Call this function to restart the game."""
68
69 # Setup the Cameras
70 self.camera_sprites = arcade.SimpleCamera()
71 self.camera_gui = arcade.SimpleCamera()
72
73 # Name of map file to load
74 map_name = ":resources:tiled_maps/map.json"
75
76 # Layer specific options are defined based on Layer names in a dictionary
77 # Doing this will make the SpriteList for the platforms layer
78 # use spatial hashing for detection.
79 layer_options = {
80 "Platforms": {
81 "use_spatial_hash": True,
82 },
83 }
84
85 # Read in the tiled map
86 self.tile_map = arcade.load_tilemap(map_name, TILE_SCALING, layer_options)
87
88 # Initialize Scene with our TileMap, this will automatically add all layers
89 # from the map as SpriteLists in the scene in the proper order.
90 self.scene = arcade.Scene.from_tilemap(self.tile_map)
91
92 # Set the background color
93 if self.tile_map.background_color:
94 self.background_color = self.tile_map.background_color
95
96 # Keep track of the score
97 self.score = 0
98
99 # Set up the player, specifically placing it at these coordinates.
100 src = ":resources:images/animated_characters/female_adventurer/femaleAdventurer_idle.png"
101 self.player_sprite = arcade.Sprite(src, scale=CHARACTER_SCALING)
102 self.player_sprite.center_x = 128
103 self.player_sprite.center_y = 128
104 self.scene.add_sprite("Player", self.player_sprite)
105
106 # --- Other stuff
107 # Create the 'physics engine'
108 self.physics_engine = arcade.PhysicsEnginePlatformer(
109 self.player_sprite, gravity_constant=GRAVITY, walls=self.scene["Platforms"]
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_sprites.use()
120
121 # Draw our Scene
122 # Note, if you a want pixelated look, add pixelated=True to the parameters
123 self.scene.draw()
124
125 # Activate the GUI camera before drawing GUI elements
126 self.camera_gui.use()
127
128 # Draw our score on the screen, scrolling it with the viewport
129 score_text = f"Score: {self.score}"
130 arcade.draw_text(score_text,
131 start_x=10,
132 start_y=10,
133 color=arcade.csscolor.WHITE,
134 font_size=18)
135
136 def update_player_speed(self):
137
138 # Calculate speed based on the keys pressed
139 self.player_sprite.change_x = 0
140
141 if self.left_key_down and not self.right_key_down:
142 self.player_sprite.change_x = -PLAYER_MOVEMENT_SPEED
143 elif self.right_key_down and not self.left_key_down:
144 self.player_sprite.change_x = PLAYER_MOVEMENT_SPEED
145
146 def on_key_press(self, key, modifiers):
147 """Called whenever a key is pressed."""
148
149 # Jump
150 if key == arcade.key.UP or key == arcade.key.W:
151 if self.physics_engine.can_jump():
152 self.player_sprite.change_y = PLAYER_JUMP_SPEED
153
154 # Left
155 elif key == arcade.key.LEFT or key == arcade.key.A:
156 self.left_key_down = True
157 self.update_player_speed()
158
159 # Right
160 elif key == arcade.key.RIGHT or key == arcade.key.D:
161 self.right_key_down = True
162 self.update_player_speed()
163
164 def on_key_release(self, key, modifiers):
165 """Called when the user releases a key."""
166 if key == arcade.key.LEFT or key == arcade.key.A:
167 self.left_key_down = False
168 self.update_player_speed()
169 elif key == arcade.key.RIGHT or key == arcade.key.D:
170 self.right_key_down = False
171 self.update_player_speed()
172
173 def center_camera_to_player(self):
174 # Find where player is, then calculate lower left corner from that
175 screen_center_x = self.player_sprite.center_x - (self.camera_sprites.viewport_width / 2)
176 screen_center_y = self.player_sprite.center_y - (self.camera_sprites.viewport_height / 2)
177
178 # Set some limits on how far we scroll
179 if screen_center_x < 0:
180 screen_center_x = 0
181 if screen_center_y < 0:
182 screen_center_y = 0
183
184 # Here's our center, move to it
185 player_centered = screen_center_x, screen_center_y
186 self.camera_sprites.move_to(player_centered)
187
188 def on_update(self, delta_time):
189 """Movement and game logic"""
190
191 # Move the player with the physics engine
192 self.physics_engine.update()
193
194 # See if we hit any coins
195 coin_hit_list = arcade.check_for_collision_with_list(
196 self.player_sprite, self.scene["Coins"]
197 )
198
199 # Loop through each coin we hit (if any) and remove it
200 for coin in coin_hit_list:
201 # Remove the coin
202 coin.remove_from_sprite_lists()
203 # Add one to the score
204 self.score += 1
205
206 # Position the camera
207 self.center_camera_to_player()
208
209 def on_resize(self, width: int, height: int):
210 """ Resize window """
211 self.camera_sprites.resize(width, height)
212 self.camera_gui.resize(width, height)
213
214
215def main():
216 """Main function"""
217 window = MyGame()
218 window.setup()
219 arcade.run()
220
221
222if __name__ == "__main__":
223 main()