The Tiled program takes some getting used to. You start off with a screen like
this, and you can create a new map here:

Then set up your map like this, adjusting the size of the map and the size of your
images accordingly. (All your images need to be the same size. Don’t guess
this number, look at the properties of the image and find how big it is.)

Most of the tiles from kenney.nl are 128x128 pixels. In the image above I’ve got a 7 tile high, by 50 pixel wide
side-scroll map.

After this, you have to create a new “tile set.” Find the button for that:

I use these settings:

You can add the images as tiles to your tileset. I don’t find this obvious, but
you click the wrench icon, then the plus icon:

These “tiles” will be all the images for your map, and the numbers they
associate with:

The numbers of the tiles correspond to the order you added the tiles. I don’t think you can change the mapping
after you create the tileset.

"""Load a map stored in csv format, as exported by the program 'Tiled.'Artwork from: http://kenney.nlTiled available from: http://www.mapeditor.org/"""importarcadeSPRITE_SCALING=0.5SCREEN_WIDTH=800SCREEN_HEIGHT=600# How many pixels to keep as a minimum margin between the character# and the edge of the screen.VIEWPORT_MARGIN=40RIGHT_MARGIN=150TILE_SIZE=128SCALED_TILE_SIZE=TILE_SIZE*SPRITE_SCALINGMAP_HEIGHT=7# PhysicsMOVEMENT_SPEED=5JUMP_SPEED=14GRAVITY=0.5defget_map(filename):""" This function loads an array based on a map stored as a list of numbers separated by commas. """# Open the filemap_file=open(filename)# Create an empty list of rows that will hold our mapmap_array=[]# Read in a line from the fileforlineinmap_file:# Strip the whitespace, and \n at the endline=line.strip()# This creates a list by splitting line everywhere there is a comma.map_row=line.split(",")# The list currently has all the numbers stored as text, and we want it# as a number. (e.g. We want 1 not "1"). So loop through and convert# to an integer.forindex,iteminenumerate(map_row):map_row[index]=int(item)# Now that we've completed processing the row, add it to our map array.map_array.append(map_row)# Done, return the map.returnmap_arrayclassMyWindow(arcade.Window):""" Main application class. """def__init__(self):""" Initializer """# Call the parent classsuper().__init__(SCREEN_WIDTH,SCREEN_HEIGHT)# Sprite listsself.player_list=Noneself.wall_list=None# Set up the playerself.player_sprite=None# Physics engineself.physics_engine=None# Used for scrolling mapself.view_left=0self.view_bottom=0defsetup(self):""" Set up the game and initialize the variables. """# Sprite listsself.player_list=arcade.SpriteList()self.wall_list=arcade.SpriteList()# Set up the playerself.player_sprite=arcade.Sprite("character.png",SPRITE_SCALING)# Starting position of the playerself.player_sprite.center_x=90self.player_sprite.center_y=270self.player_list.append(self.player_sprite)# Get a 2D array made of numbers based on the mapmap_array=get_map("map.csv")# Now that we've got the map, loop through and create the spritesforrow_indexinrange(len(map_array)):forcolumn_indexinrange(len(map_array[row_index])):item=map_array[row_index][column_index]# For this map, the numbers represent:# -1 = empty# 0 = box# 1 = grass left edge# 2 = grass middle# 3 = grass right edgeifitem==0:wall=arcade.Sprite("boxCrate_double.png",SPRITE_SCALING)elifitem==1:wall=arcade.Sprite("grassLeft.png",SPRITE_SCALING)elifitem==2:wall=arcade.Sprite("grassMid.png",SPRITE_SCALING)elifitem==3:wall=arcade.Sprite("grassRight.png",SPRITE_SCALING)ifitem>=0:# Calculate where the sprite goeswall.left=column_index*SCALED_TILE_SIZEwall.top=(MAP_HEIGHT-row_index)*SCALED_TILE_SIZE# Add the spriteself.wall_list.append(wall)# Create out platformer physics engine with gravityself.physics_engine=arcade.PhysicsEnginePlatformer(self.player_sprite,self.wall_list,gravity_constant=GRAVITY)# Set the background colorarcade.set_background_color(arcade.color.AMAZON)# Set the view port boundaries# These numbers set where we have 'scrolled' to.self.view_left=0self.view_bottom=0defon_draw(self):""" Render the screen. """# This command has to happen before we start drawingarcade.start_render()# Draw all the sprites.self.wall_list.draw()self.player_list.draw()defon_key_press(self,key,modifiers):""" Called whenever the mouse moves. """ifkey==arcade.key.UP:# This line below is new. It checks to make sure there is a platform underneath# the player. Because you can't jump if there isn't ground beneath your feet.ifself.physics_engine.can_jump():self.player_sprite.change_y=JUMP_SPEEDelifkey==arcade.key.LEFT:self.player_sprite.change_x=-MOVEMENT_SPEEDelifkey==arcade.key.RIGHT:self.player_sprite.change_x=MOVEMENT_SPEEDdefon_key_release(self,key,modifiers):""" Called when the user presses a mouse button. """ifkey==arcade.key.LEFTorkey==arcade.key.RIGHT:self.player_sprite.change_x=0defupdate(self,delta_time):""" Movement and game logic """self.physics_engine.update()# --- Manage Scrolling ---# Track if we need to change the view portchanged=False# Scroll leftleft_bndry=self.view_left+VIEWPORT_MARGINifself.player_sprite.left<left_bndry:self.view_left-=left_bndry-self.player_sprite.leftchanged=True# Scroll rightright_bndry=self.view_left+SCREEN_WIDTH-RIGHT_MARGINifself.player_sprite.right>right_bndry:self.view_left+=self.player_sprite.right-right_bndrychanged=True# Scroll uptop_bndry=self.view_bottom+SCREEN_HEIGHT-VIEWPORT_MARGINifself.player_sprite.top>top_bndry:self.view_bottom+=self.player_sprite.top-top_bndrychanged=True# Scroll downbottom_bndry=self.view_bottom+VIEWPORT_MARGINifself.player_sprite.bottom<bottom_bndry:self.view_bottom-=bottom_bndry-self.player_sprite.bottomchanged=True# If we need to scroll, go ahead and do it.ifchanged:arcade.set_viewport(self.view_left,SCREEN_WIDTH+self.view_left,self.view_bottom,SCREEN_HEIGHT+self.view_bottom)defmain():window=MyWindow()window.setup()arcade.run()main()