Skip to content

Commit bb457b4

Browse files
committed
add platformer game tutorial
1 parent 9cfb9b7 commit bb457b4

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+431
-0
lines changed

README.md

+1
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
import pygame
2+
from settings import HEIGHT, WIDTH
3+
4+
pygame.font.init()
5+
6+
class Game:
7+
def __init__(self, screen):
8+
self.screen = screen
9+
self.font = pygame.font.SysFont("impact", 70)
10+
self.message_color = pygame.Color("darkorange")
11+
12+
# if player ran out of life or fell below the platform
13+
def _game_lose(self, player):
14+
player.game_over = True
15+
message = self.font.render('You Lose...', True, self.message_color)
16+
self.screen.blit(message,(WIDTH // 3 + 70, 70))
17+
18+
# if player reach the goal
19+
def _game_win(self, player):
20+
player.game_over = True
21+
player.win = True
22+
message = self.font.render('You Win!!', True, self.message_color)
23+
self.screen.blit(message,(WIDTH // 3, 70))
24+
25+
# checks if the game is over or not, and if win or lose
26+
def game_state(self, player, goal):
27+
if player.life <= 0 or player.rect.y >= HEIGHT:
28+
self._game_lose(player)
29+
elif player.rect.colliderect(goal.rect):
30+
self._game_win(player)
31+
else:
32+
None
33+
34+
def show_life(self, player):
35+
life_size = 30
36+
img_path = "assets/life/life.png"
37+
life_image = pygame.image.load(img_path)
38+
life_image = pygame.transform.scale(life_image, (life_size, life_size))
39+
# life_rect = life_image.get_rect(topleft = pos)
40+
indent = 0
41+
for life in range(player.life):
42+
indent += life_size
43+
self.screen.blit(life_image, (indent, life_size))
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import pygame
2+
3+
class Goal(pygame.sprite.Sprite):
4+
def __init__(self, pos, size):
5+
super().__init__()
6+
img_path = 'assets/goal/gate.png'
7+
self.image = pygame.image.load(img_path)
8+
self.image = pygame.transform.scale(self.image, (size, size))
9+
self.rect = self.image.get_rect(topleft = pos)
10+
11+
# update object position due to world scroll
12+
def update(self, x_shift):
13+
self.rect.x += x_shift
+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
import pygame, sys
2+
from settings import *
3+
from world import World
4+
5+
pygame.init()
6+
7+
screen = pygame.display.set_mode((WIDTH, HEIGHT))
8+
pygame.display.set_caption("Platformer")
9+
10+
class Platformer:
11+
def __init__(self, screen, width, height):
12+
self.screen = screen
13+
self.clock = pygame.time.Clock()
14+
self.player_event = False
15+
16+
self.bg_img = pygame.image.load('assets/terrain/bg.jpg')
17+
self.bg_img = pygame.transform.scale(self.bg_img, (width, height))
18+
19+
def main(self):
20+
world = World(world_map, self.screen)
21+
while True:
22+
self.screen.blit(self.bg_img, (0, 0))
23+
24+
for event in pygame.event.get():
25+
if event.type == pygame.QUIT:
26+
pygame.quit()
27+
sys.exit()
28+
29+
elif event.type == pygame.KEYDOWN:
30+
if event.key == pygame.K_LEFT:
31+
self.player_event = "left"
32+
if event.key == pygame.K_RIGHT:
33+
self.player_event = "right"
34+
if event.key == pygame.K_SPACE:
35+
self.player_event = "space"
36+
elif event.type == pygame.KEYUP:
37+
self.player_event = False
38+
39+
world.update(self.player_event)
40+
pygame.display.update()
41+
self.clock.tick(60)
42+
43+
44+
if __name__ == "__main__":
45+
play = Platformer(screen, WIDTH, HEIGHT)
46+
play.main()
+115
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,115 @@
1+
import pygame
2+
from support import import_sprite
3+
4+
class Player(pygame.sprite.Sprite):
5+
def __init__(self, pos):
6+
super().__init__()
7+
self._import_character_assets()
8+
self.frame_index = 0
9+
self.animation_speed = 0.15
10+
self.image = self.animations["idle"][self.frame_index]
11+
self.rect = self.image.get_rect(topleft = pos)
12+
self.mask = pygame.mask.from_surface(self.image)
13+
14+
# player movement
15+
self.direction = pygame.math.Vector2(0, 0)
16+
self.speed = 5
17+
self.jump_move = -16
18+
19+
# player status
20+
self.life = 5
21+
self.game_over = False
22+
self.win = False
23+
self.status = "idle"
24+
self.facing_right = True
25+
self.on_ground = False
26+
self.on_ceiling = False
27+
self.on_left = False
28+
self.on_right = False
29+
30+
# gets all the image needed for animating specific player action
31+
def _import_character_assets(self):
32+
character_path = "assets/player/"
33+
self.animations = {
34+
"idle": [],
35+
"walk": [],
36+
"jump": [],
37+
"fall": [],
38+
"lose": [],
39+
"win": []
40+
}
41+
for animation in self.animations.keys():
42+
full_path = character_path + animation
43+
self.animations[animation] = import_sprite(full_path)
44+
45+
# animates the player actions
46+
def _animate(self):
47+
animation = self.animations[self.status]
48+
49+
# loop over frame index
50+
self.frame_index += self.animation_speed
51+
if self.frame_index >= len(animation):
52+
self.frame_index = 0
53+
image = animation[int(self.frame_index)]
54+
image = pygame.transform.scale(image, (35, 50))
55+
if self.facing_right:
56+
self.image = image
57+
else:
58+
flipped_image = pygame.transform.flip(image, True, False)
59+
self.image = flipped_image
60+
61+
# set the rect
62+
if self.on_ground and self.on_right:
63+
self.rect = self.image.get_rect(bottomright = self.rect.bottomright)
64+
elif self.on_ground and self.on_left:
65+
self.rect = self.image.get_rect(bottomleft = self.rect.bottomleft)
66+
elif self.on_ground:
67+
self.rect = self.image.get_rect(midbottom = self.rect.midbottom)
68+
elif self.on_ceiling and self.on_right:
69+
self.rect = self.image.get_rect(topright = self.rect.topright)
70+
elif self.on_ceiling and self.on_left:
71+
self.rect = self.image.get_rect(bottomleft = self.rect.topleft)
72+
elif self.on_ceiling:
73+
self.rect = self.image.get_rect(midtop = self.rect.midtop)
74+
75+
# checks if the player is moving towards left or right or not moving
76+
def _get_input(self, player_event):
77+
if player_event != False:
78+
if player_event == "right":
79+
self.direction.x = 1
80+
self.facing_right = True
81+
elif player_event == "left":
82+
self.direction.x = -1
83+
self.facing_right = False
84+
else:
85+
self.direction.x = 0
86+
87+
def _jump(self):
88+
self.direction.y = self.jump_move
89+
90+
# identifies player action
91+
def _get_status(self):
92+
if self.direction.y < 0:
93+
self.status = "jump"
94+
elif self.direction.y > 1:
95+
self.status = "fall"
96+
elif self.direction.x != 0:
97+
self.status = "walk"
98+
else:
99+
self.status = "idle"
100+
101+
# update the player's state
102+
def update(self, player_event):
103+
self._get_status()
104+
if self.life > 0 and not self.game_over:
105+
if player_event == "space" and self.on_ground:
106+
self._jump()
107+
else:
108+
self._get_input(player_event)
109+
elif self.game_over and self.win:
110+
self.direction.x = 0
111+
self.status = "win"
112+
else:
113+
self.direction.x = 0
114+
self.status = "lose"
115+
self._animate()
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
pygame
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
world_map = [
2+
' ',
3+
' ',
4+
' t t ',
5+
' X XXXXXXXXXs XX X ',
6+
' tXXXt XX XX XXXX tt XX ',
7+
' XX XX XXXXX ',
8+
' Xt t t t X G ',
9+
' XXXXXX XXXXs XXXXXXXXXXX XX tt t XXX',
10+
' P XX X XX X X XXXt X XX XX XXX XXXXXXXXs XXXXXX ',
11+
'XXXXXXX X X X X XXXXXXXXX XX XX XXX XX XX XXXXXXX X ',
12+
]
13+
14+
tile_size = 50
15+
WIDTH, HEIGHT = 1000, len(world_map) * tile_size
+11
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
from os import walk
2+
import pygame
3+
4+
def import_sprite(path):
5+
surface_list = []
6+
for _, __, img_file in walk(path):
7+
for image in img_file:
8+
full_path = f"{path}/{image}"
9+
img_surface = pygame.image.load(full_path).convert_alpha()
10+
surface_list.append(img_surface)
11+
return surface_list
+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import pygame
2+
3+
class Tile(pygame.sprite.Sprite):
4+
def __init__(self, pos, size):
5+
super().__init__()
6+
img_path = 'assets/terrain/stone.jpg'
7+
self.image = pygame.image.load(img_path)
8+
self.image = pygame.transform.scale(self.image, (size, size))
9+
self.rect = self.image.get_rect(topleft = pos)
10+
11+
# update object position due to world scroll
12+
def update(self, x_shift):
13+
self.rect.x += x_shift
+29
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import pygame
2+
from support import import_sprite
3+
4+
class Trap(pygame.sprite.Sprite):
5+
def __init__(self, pos, size):
6+
super().__init__()
7+
self.blade_img = import_sprite("assets/trap/blade")
8+
self.frame_index = 0
9+
self.animation_delay = 3
10+
self.image = self.blade_img[self.frame_index]
11+
self.image = pygame.transform.scale(self.image, (size, size))
12+
self.mask = pygame.mask.from_surface(self.image)
13+
self.rect = self.image.get_rect(topleft = pos)
14+
15+
# adds the spinning effect to the Blade trap
16+
def _animate(self):
17+
sprites = self.blade_img
18+
sprite_index = (self.frame_index // self.animation_delay) % len(sprites)
19+
self.image = sprites[sprite_index]
20+
self.frame_index += 1
21+
self.rect = self.image.get_rect(topleft=(self.rect.x, self.rect.y))
22+
self.mask = pygame.mask.from_surface(self.image)
23+
if self.frame_index // self.animation_delay > len(sprites):
24+
self.frame_index = 0
25+
26+
# update object position due to world scroll
27+
def update(self, x_shift):
28+
self._animate()
29+
self.rect.x += x_shift

0 commit comments

Comments
 (0)