So I am trying to create a moving camera that follows the player in pygame, I read few guides also the popular one on stack overflow(for refrence: this one) and still having problem making it work.
Basically my problem is that the game just "freeze" I cant move the player and gravity is not in effect although I can still press a button on the keyboard and exit the game, also tried with few prints in some lines and the program is not stuck for sure.
Here is my code:
import pygame
pygame.init()
# global constants
SCREEN_WIDTH, SCREEN_HEIGHT = 800, 640
RESOLUTION = (SCREEN_WIDTH, SCREEN_HEIGHT)
BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
BLUE = (0, 0, 255)
class Player(pygame.sprite.Sprite):
def __init__(self, x, y):
# get sprite class attributes
super(Player, self).__init__()
# create the player image and hit box
self.image = pygame.Surface([32, 32])
self.image.fill(BLACK)
self.rect = self.image.get_rect()
# the player pos
self.rect.x = x
self.rect.y = y
self.facing = "left"
# player movement vectors
self.change_x = 0
self.change_y = 0
self.walls = None
# current level the player is in
self.level = None
# change the movement vectors
def change_speed(self, x, y):
self.change_x += x
self.change_y += y
def update(self):
# move the player
# calc the gravity effect
self.calc_gravity()
# move left/right
self.rect.x += self.change_x
# see if we hit anything
block_hit_list = pygame.sprite.spritecollide(self, self.level.block_list, False)
for block in block_hit_list:
# if we are moving right,
# set our right side to the left side of the item we hit
if self.change_x > 0:
self.rect.right = block.rect.left
elif self.change_x < 0:
# otherwise if we are moving left, do the opposite
self.rect.left = block.rect.right
# move up/down
self.rect.y += self.change_y
# check and see if we hit anything
block_hit_list = pygame.sprite.spritecollide(self, self.level.block_list, False)
for block in block_hit_list:
# reset our position based on the top/bottom of the object
if self.change_y > 0:
self.rect.bottom = block.rect.top
elif self.change_y < 0:
self.rect.top = block.rect.bottom
# stop our vertical movement
self.change_y = 0
def calc_gravity(self):
# calculate effect of gravity
if self.change_y == 0:
self.change_y = 1
else:
# maximum downward velocity
if self.change_y < 10:
# gravity
self.change_y += 0.45
else:
pass
# the player's jump
def jump(self):
# move down a bit and see if there is a platform below us
# move down 2 pixels because it doesn't work well if we only move down
# 1 when working with a platform moving down
self.rect.y += 2
block_hit_list = pygame.sprite.spritecollide(self, self.level.block_list, False)
self.rect.y -= 2
# If it is ok to jump, set our speed upwards
if len(block_hit_list) > 0 or self.rect.bottom >= SCREEN_HEIGHT:
self.change_y = -7
# player-controlled movement
def go_left(self):
self.change_x = -5
self.facing = "left"
def go_right(self):
self.change_x = 5
self.facing = "right"
def stop(self):
self.change_x = 0
# blocks the player can stand on or to limit his movement in the map
class Blocks(pygame.sprite.Sprite):
# create the block
def __init__(self, width, height):
super(Blocks, self).__init__()
self.image = pygame.Surface([width, height])
self.image.fill(BLUE)
self.rect = self.image.get_rect()
# super class for levels, each level will be a sub class of Level and have a different layout
class Level(object):
def __init__(self, player):
self.block_list = pygame.sprite.Group()
self.player = player
# updates the level
def update(self):
self.block_list.update()
# draw all the level objects
def draw(self, screen):
# the background
screen.fill(WHITE)
self.block_list.draw(screen)
# level one sub class
class LevelOne(Level):
def __init__(self, player):
super(LevelOne, self).__init__(player)
self.level_width = 2500
self.level_height = 1400
# level one blocks
blocks_loc = [[0, 0, 10, 800], [10, 790, 2500, 10], [2500, 0, 10, 800]]
for x in blocks_loc:
block = Blocks(x[2], x[3])
block.rect.x = x[0]
block.rect.y = x[1]
self.block_list.add(block)
# camera class that follows the player around the screen
class Camera(object):
def __init__(self, width, height):
self.camera = pygame.Rect(0, 0, width, height)
self.width = width
self.height = height
def apply(self, entity):
return entity.rect.move(self.camera.topleft)
def update(self, target):
x = -target.rect.x + int(SCREEN_WIDTH/2)
y = -target.rect.y + int(SCREEN_HEIGHT/2)
self.camera = pygame.Rect(x, y, self.width, self.height)
# create the game screen
screen = pygame.display.set_mode(RESOLUTION)
# window title
pygame.display.set_caption("test")
# create the player object
player = Player(600, 50)
# create the levels
levels_list = []
levels_list.append(LevelOne(player))
active_sprite_list = pygame.sprite.Group()
current_level_num = 0
current_level = levels_list[current_level_num]
player.level = current_level
active_sprite_list.add(player)
camera = Camera(current_level.level_width, current_level.level_height)
# the clock will be used for the frame rate of the game
clock = pygame.time.Clock()
# flag to know when the game is done
done = False
while not done:
for event in pygame.event.get():
if event.type == pygame.QUIT:
done = True
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_LEFT:
player.go_left()
if event.key == pygame.K_RIGHT:
player.go_right()
if event.key == pygame.K_UP:
player.jump()
if event.key == pygame.K_ESCAPE:
done = True
if event.type == pygame.KEYUP:
if event.key == pygame.K_LEFT and player.change_x < 0:
player.stop()
if event.key == pygame.K_RIGHT and player.change_x > 0:
player.stop()
# update part
current_level.update()
active_sprite_list.update()
camera.update(player)
# draw part
current_level.draw(screen)
for sprite in active_sprite_list:
screen.blit(sprite.image, camera.apply(sprite))
# refresh part
pygame.display.flip()
clock.tick(60)
pygame.quit()