A very nice program by DaFluffyPotato to see how you can make a platform game with python and pygame.
The links to the video tutorial
Chapter 1
Chapter 2
Chapter 3
Chapter 4
Chapter 5 (physics in depth analysis)
Chapter 6
Chapter 7
Chapter 8
Chapter 9 – Enemies
Just added a few ours earlier, this seems to be very interesting, so, take a look at it.
Messing around with the map
You can download this project clicking on the this link.
The main code
import pygame, sys, os clock = pygame.time.Clock() from pygame.locals import * pygame.init() # initiates pygame pygame.display.set_caption('Pygame Platformer') WINDOW_SIZE = (600,400) screen = pygame.display.set_mode(WINDOW_SIZE,0,32) # initiate the window display = pygame.Surface((300,200)) # used as the surface for rendering, which is scaled moving_right = False moving_left = False vertical_momentum = 0 air_timer = 0 true_scroll = [0,0] def load_map(path): f = open(path + '.txt','r') data = f.read() f.close() data = data.split('\n') game_map = [] for row in data: game_map.append(list(row)) return game_map global animation_frames animation_frames = {} def load_animation(path,frame_durations): global animation_frames animation_name = path.split('/')[-1] animation_frame_data = [] n = 0 for frame in frame_durations: animation_frame_id = animation_name + '_' + str(n) img_loc = path + '/' + animation_frame_id + '.png' # player_animations/idle/idle_0.png animation_image = pygame.image.load(img_loc).convert() animation_image.set_colorkey((255,255,255)) animation_frames[animation_frame_id] = animation_image.copy() for i in range(frame): animation_frame_data.append(animation_frame_id) n += 1 return animation_frame_data def change_action(action_var,frame,new_value): if action_var != new_value: action_var = new_value frame = 0 return action_var,frame animation_database = {} animation_database['run'] = load_animation('player_animations/run',[7,7]) animation_database['idle'] = load_animation('player_animations/idle',[7,7,40]) game_map = load_map('map') grass_img = pygame.image.load('grass.png') dirt_img = pygame.image.load('dirt.png') player_action = 'idle' player_frame = 0 player_flip = False player_rect = pygame.Rect(100,100,5,13) background_objects = [[0.25,[120,10,70,400]],[0.25,[280,30,40,400]],[0.5,[30,40,40,400]],[0.5,[130,90,100,400]],[0.5,[300,80,120,400]]] def collision_test(rect,tiles): hit_list = [] for tile in tiles: if rect.colliderect(tile): hit_list.append(tile) return hit_list def move(rect,movement,tiles): collision_types = {'top':False,'bottom':False,'right':False,'left':False} rect.x += movement[0] hit_list = collision_test(rect,tiles) for tile in hit_list: if movement[0] > 0: rect.right = tile.left collision_types['right'] = True elif movement[0] < 0: rect.left = tile.right collision_types['left'] = True rect.y += movement[1] hit_list = collision_test(rect,tiles) for tile in hit_list: if movement[1] > 0: rect.bottom = tile.top collision_types['bottom'] = True elif movement[1] < 0: rect.top = tile.bottom collision_types['top'] = True return rect, collision_types while True: # game loop display.fill((146,244,255)) # clear screen by filling it with blue true_scroll[0] += (player_rect.x-true_scroll[0]-152)/20 true_scroll[1] += (player_rect.y-true_scroll[1]-106)/20 scroll = true_scroll.copy() scroll[0] = int(scroll[0]) scroll[1] = int(scroll[1]) pygame.draw.rect(display,(7,80,75),pygame.Rect(0,120,300,80)) for background_object in background_objects: obj_rect = pygame.Rect(background_object[1][0]-scroll[0]*background_object[0],background_object[1][1]-scroll[1]*background_object[0],background_object[1][2],background_object[1][3]) if background_object[0] == 0.5: pygame.draw.rect(display,(14,222,150),obj_rect) else: pygame.draw.rect(display,(9,91,85),obj_rect) tile_rects = [] y = 0 for layer in game_map: x = 0 for tile in layer: if tile == '1': display.blit(dirt_img,(x*16-scroll[0],y*16-scroll[1])) if tile == '2': display.blit(grass_img,(x*16-scroll[0],y*16-scroll[1])) if tile != '0': tile_rects.append(pygame.Rect(x*16,y*16,16,16)) x += 1 y += 1 player_movement = [0,0] if moving_right == True: player_movement[0] += 2 if moving_left == True: player_movement[0] -= 2 player_movement[1] += vertical_momentum vertical_momentum += 0.2 if vertical_momentum > 3: vertical_momentum = 3 if player_movement[0] == 0: player_action,player_frame = change_action(player_action,player_frame,'idle') if player_movement[0] > 0: player_flip = False player_action,player_frame = change_action(player_action,player_frame,'run') if player_movement[0] < 0: player_flip = True player_action,player_frame = change_action(player_action,player_frame,'run') player_rect,collisions = move(player_rect,player_movement,tile_rects) if collisions['bottom'] == True: air_timer = 0 vertical_momentum = 0 else: air_timer += 1 player_frame += 1 if player_frame >= len(animation_database[player_action]): player_frame = 0 player_img_id = animation_database[player_action][player_frame] player_img = animation_frames[player_img_id] display.blit(pygame.transform.flip(player_img,player_flip,False),(player_rect.x-scroll[0],player_rect.y-scroll[1])) for event in pygame.event.get(): # event loop if event.type == QUIT: pygame.quit() sys.exit() if event.type == KEYDOWN: if event.key == K_RIGHT: moving_right = True if event.key == K_LEFT: moving_left = True if event.key == K_UP: if air_timer < 6: vertical_momentum = -5 if event.type == KEYUP: if event.key == K_RIGHT: moving_right = False if event.key == K_LEFT: moving_left = False screen.blit(pygame.transform.scale(display,WINDOW_SIZE),(0,0)) pygame.display.update() clock.tick(60)
The map (in a text file)
This is a map modified by me to make it… longer.
100000000000000002220000000000000000000000000000000000000000000000000000000000000000000000000000000000000002220000000000 110000022222000000000000220000000000022222000000000000000000000000022222000000000000000000000000022222000000000000000011 110000000000000000000000000000000000010001110000000000000000000000000000000000000000000000000000000000000000000000000011 220000000000000002200000022000220000010000000002200000022000220000000000000002200000022000220000000000000000000000000011 110000000000000221100002211200112222222222022221100002211200112222222222222221100002211200112222210000000000000000000011 111000000000000100001111111110111100000000011111111111111111111111111111111111111111111111111111110000000222000000011111 111100000000000100011111111110000001111000111111111111111111100011111110000000011111111111111111111110000010000000111111 111111111111111111111111111111111111111111100011111111111111111111111112222222211111111111111111111111000010000000111111 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111 111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111111
The grafic
The dirt
The grass
The idle images
The run images
The structure of the files
and into player_animation (where the players images are)
New sprite
Running
idle