Skip to content
Permalink
Browse files
Tilemap implementation
All platforms are now created through a map (.txt file)
Changed (again) how collision works making it consistent through all platforms.
  • Loading branch information
dacostag committed Apr 29, 2020
1 parent 7607ac8 commit ab485d158d8962bd5d344843fc2f16eb35e6682f
Show file tree
Hide file tree
Showing 10 changed files with 118 additions and 76 deletions.
Binary file not shown.
BIN +33 Bytes (100%) __pycache__/sprites.cpython-38.pyc
Binary file not shown.
BIN +1.35 KB img/grassLeft.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +1.17 KB img/grassMid.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
BIN +1.34 KB img/grassRight.png
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
73 main.py
@@ -33,21 +33,32 @@ class Game:
self.spritesheet1 = SpriteSheet(os.path.join(img_dir, spritesheet1))
self.spritesheet2 = SpriteSheet(os.path.join(img_dir, spritesheet2))

# load sound
# load soundself.
self.sound_dir = os.path.join(self.dir, 'sound')
self.jump_sound = pygame.mixer.Sound(os.path.join(self.sound_dir, 'Jump13.wav'))

# load map
self.map_data = []
with open(os.path.join(self.dir, 'map.txt'), 'rt') as f:
for line in f:
self.map_data.append(line)

def new(self):
# starts a new game not a new program
self.score = 0
self.all_sprites = pygame.sprite.Group()
self.platforms = pygame.sprite.Group()
self.player = Player(self)
self.tile = pygame.sprite.Group()

# spawn walls from map
for row, tiles in enumerate(self.map_data):
for col, tile in enumerate(tiles):
if tile == '1':
Tile(self, col, row)
if tile == 'P':
self.player = Player(self, col, row) #spawns player at 'P' map location
self.all_sprites.add(self.player)
for plat in platform_list:
p = Platform(self, *plat)
self.all_sprites.add(p)
self.platforms.add(p)

pygame.mixer.music.load(os.path.join(self.sound_dir, '04 - Sanctuary.ogg'))
self.run()

@@ -56,7 +67,7 @@ class Game:
pygame.mixer.music.play(loops=-1)
self.playing = True
while self.playing:
self.clock.tick(fps)
self.dt = self.clock.tick(fps) / 1000
self.events()
self.update()
self.draw()
@@ -65,42 +76,25 @@ class Game:
def update(self):
# Game loop - Update
self.all_sprites.update()
# check if player hits platform
hits = pygame.sprite.spritecollide(self.player, self.platforms, False)
# wrap around the screen
if self.player.pos.x > width:
self.player.pos.x = 0
if self.player.pos.x < 0:
self.player.pos.x = width

hits = pygame.sprite.spritecollide(self.player, self.tile, False)
if hits:
lowest = max(hits, key=lambda x: x.rect.bottom)
highest = min(hits, key=lambda x: x.rect.bottom)
#print("Player pos top:", str(self.player.rect.left), "y", str(self.player.pos.x), "bottom",
#str(self.player.rect.right))
if self.player.pos.y < lowest.rect.centery - 5: # if falling on block - player remains on top of it
self.player.pos.y = lowest.rect.top
if self.player.y < lowest.y: # if falling on block - player remains on top of it
self.player.y = lowest.y - 1.3
self.player.vel.y = 0
self.player.jumping = False
# if player hits block from the side
if self.player.rect.right > highest.rect.left or self.player.rect.left < highest.rect.right:
if self.player.pos.y > highest.rect.centery:
if self.player.rect.right > highest.rect.left:
self.player.pos.x = highest.rect.left - 18 # 18 is 1 pixel more then half the width of the player sprite
if self.player.rect.left < highest.rect.right:
self.player.pos.x = highest.rect.right + 18
self.player.vel.x = 0
self.player.vel.y = 2

if self.player.pos.y > lowest.rect.bottom: # if jumping from below - player hits his head on the platform
self.player.rect.top = lowest.rect.bottom + 5
# collision when the player hits the block from below
if self.player.y > lowest.y - 0.5:
self.player.y = lowest.y + 1
self.player.vel.y = 0

# if player reaches 3/5 of width of the screen
if self.player.rect.right >= (width * 0.6):
self.player.pos.x -= abs(self.player.vel.x)
for plat in self.platforms:
plat.rect.x -= abs(self.player.vel.x)

# if player reaches 1/5 of the left side of the screen move screen
if self.player.rect.left <= (width * 0.2):
self.player.pos.x += abs(self.player.vel.x)
for plat in self.platforms:
plat.rect.x += abs(self.player.vel.x)

# Die, by falling of the screen
if self.player.rect.bottom > height + 60:
@@ -120,9 +114,16 @@ class Game:
if event.key == pygame.K_UP:
self.player.jump_cut()

def draw_grid(self):
for x in range(0, width, tilesize):
pygame.draw.line(self.screen, (169, 169, 169), (x, 0), (x, height))
for y in range(0, height, tilesize):
pygame.draw.line(self.screen, (169, 169, 169), (0, y), (width, y))

def draw(self):
# Game loop - draw/render
self.screen.fill((146, 244, 255))
self.draw_grid()
self.all_sprites.draw(self.screen)
self.screen.blit(self.player.image, self.player.rect)
self.draw_text("Score: " + str(self.score), 26, (255, 255, 255), 40, 15)
15 map.txt
@@ -0,0 +1,15 @@
..............................
....P.....1...................
..............................
..............................
...............11.............
..............................
....111.......................
...................111........
...........111................
................111...........
..............................
.....111............111.......
1..........11111..............
1............................1
111111111111111111111111111111
@@ -1,8 +1,9 @@
import os
import pygame

width = 800
height = 425
width = 960 # 960/32 = 30
height = 480 # 480/32 = 15
tilesize = 32 # 30/15 TILE SCREEN
fps = 30
basic_font = 'courier new.ttf'
textX, textY = 10, 10
@@ -17,21 +18,16 @@ sound_folder = os.path.join(game_folder, "sound")
background = pygame.image.load('img/background.jpg')
BG_colour = (69, 219, 222)
score_font = '8-BIT WONDER.ttf'

# Player properties
player_acc = 0.9
player_friction = -0.12
player_gravity = 1.2
player_jump = 17

# Starting platforms
# X Y
platform_list = [(0, 220), (35, 220), (70, 220), (105, 220),
(90, 125)
]

main_floor = []
# Platform/tile images
grass_left = pygame.image.load('img/grassLeft.png')
grass_middle = pygame.image.load('img/grassMid.png')
grass_right = pygame.image.load('img/grassRight.png')

for i in range(0, 50):
main_floor.append((i * 35, height-35))
main_floor.append((i * 35, height-70))

@@ -1,8 +1,6 @@
# Sprite classes
from settings import *
import pygame
from random import choice

vec = pygame.math.Vector2


@@ -21,21 +19,22 @@ class SpriteSheet:


class Player(pygame.sprite.Sprite):
def __init__(self, game):
def __init__(self, game, x, y):
pygame.sprite.Sprite.__init__(self)
self.game = game
self.load_images()
self.image = self.standing_frames[0]
self.image.set_colorkey((0, 0, 0))
self.walking = False
self.jumping = False
self.current_frame = 0
self.last_update = 0
self.load_images()
self.image = self.standing_frames[0]
self.image.set_colorkey((0, 0, 0))
self.rect = self.image.get_rect()
self.rect.center = (width / 2, height / 2)
self.pos = vec(width / 2, height / 2) # x and y position
self.vel = vec(0, 0) # velocity in x and y axis
self.acc = vec(0, 0) # acceleration in x and y axis
self.x = x
self.y = y
self.pos = vec(x * tilesize, y * tilesize)
self.vel = vec(0, 0)
self.acc = vec(0, 0)

def load_images(self):
self.standing_frames = [self.game.spritesheet1.get_image(67, 190, 66, 92),
@@ -71,9 +70,9 @@ class Player(pygame.sprite.Sprite):

def jump(self):
# jump only if standing on a platform
self.rect.y += 2
hits = pygame.sprite.spritecollide(self, self.game.platforms, False)
self.rect.y -= 2
self.y += 1
hits = pygame.sprite.spritecollide(self, self.game.tile, False)
self.y -= 1
if hits and not self.jumping:
self.game.jump_sound.play()
self.jumping = True
@@ -94,9 +93,11 @@ class Player(pygame.sprite.Sprite):
self.vel += self.acc
if abs(self.vel.x) < 0.1:
self.vel.x = 0
self.pos += self.vel + 0.5 * self.acc
self.x += (self.vel.x + 0.5 * self.acc.x) / 32
self.y += (self.vel.y + 0.5 * self.acc.y) / 32

self.rect.midbottom = self.pos # why is it recognized as a typo??
self.rect.x = self.x * tilesize
self.rect.y = self.y * tilesize

def animate(self):
now = pygame.time.get_ticks()
@@ -109,33 +110,32 @@ class Player(pygame.sprite.Sprite):
if (now - self.last_update) > 100:
self.last_update = now
self.current_frame = (self.current_frame + 1) % len(self.walk_frames_l)
bottom = self.rect.bottom
if self.vel.x > 0:
self.image = self.walk_frames_r[self.current_frame]
else:
self.image = self.walk_frames_l[self.current_frame]
self.rect = self.image.get_rect()
self.rect.bottom = bottom
# show idle animation
if not self.jumping and not self.walking:
if (now - self.last_update) > 400:
self.last_update = now
self.current_frame = (self.current_frame + 1) % len(self.standing_frames)
bottom = self.rect.bottom
self.image = self.standing_frames[self.current_frame]
self.rect = self.image.get_rect()
self.rect.bottom = bottom


class Platform(pygame.sprite.Sprite):
class Tile(pygame.sprite.Sprite): # tile based
def __init__(self, game, x, y):
self.groups = game.all_sprites, game.platforms
pygame.sprite.Sprite.__init__(self)
self.groups = game.all_sprites, game.tile
pygame.sprite.Sprite.__init__(self, self.groups)
self.game = game
images = [self.game.spritesheet2.get_image(576, 792, 70, 70),
self.game.spritesheet2.get_image(720, 792, 70, 70)]
self.image = choice(images)
self.image.set_colorkey((0, 0, 0))
self.image = pygame.Surface((tilesize, tilesize))
self.image.fill((0, 128, 0))
self.rect = self.image.get_rect()
self.rect.x = x
self.rect.y = y
self.x = x
self.y = y
self.rect.x = x * tilesize
self.rect.y = y * tilesize

class Powerup(pygame.sprite.Sprite):
pass
@@ -0,0 +1,30 @@
import pygame


class spritesheet(object):
def __init__(self, filename):
self.sheet = pygame.image.load(filename).convert()

# Load a specific image from a specific rectangle
def image_at(self, rectangle, colorkey=None):
"Loads image from x,y,x+offset,y+offset"
rect = pygame.Rect(rectangle)
image = pygame.Surface(rect.size).convert()
image.blit(self.sheet, (0, 0), rect)
if colorkey is not None:
if colorkey is -1:
colorkey = image.get_at((0, 0))
image.set_colorkey(colorkey, pygame.RLEACCEL)
return image

# Load a whole bunch of images and return them as a list
def images_at(self, rects, colorkey=None):
"Loads multiple images, supply a list of coordinates"
return [self.image_at(rect, colorkey) for rect in rects]

# Load a whole strip of images
def load_strip(self, rect, image_count, colorkey=None):
"Loads a strip of images and returns them as a list"
tups = [(rect[0] + rect[2] * x, rect[1], rect[2], rect[3])
for x in range(image_count)]
return self.images_at(tups, colorkey)

0 comments on commit ab485d1

Please sign in to comment.