I am creating a simple 2D platformer in Pygame. In this project I have been trying to use classes much more for good practice. My current problem is that I am trying to make the screen center on the player, however I cannot find a way to do this with the way my code is currently set up.
In addition, I plan to later add a way to make the screen follow the player with a small amount of lag, following faster as it gets further away. However, making the camera center on the player is my main concern.
When the player is moving right, I have all the "PlatformRects" move left at the same speed. I have tried different speeds, setting the player to zero speed and just moving the "PlatformRects" almost works (related comment in code in the "update" func of the "Player" class). I had also tried making the "PlatformRects" movement depend on the position of the player, but I couldn't get this to work either.
I would appreciate any help. Here's my code (I trimmed out a lot of irrelevant code, like animating and such):
import pygame, sys, random
#---Classes----------------------------------------#
class PlatformRect(pygame.sprite.Sprite):
def __init__(self,x_pos,y_pos,size_x,size_y,path,players):
super().__init__()
self.x_pos = x_pos
self.y_pos = y_pos
self.size_x = size_x
self.size_y = size_y
self.players = players
self.can_jump1 = None
if path == "null":
self.image = pygame.Surface((self.size_x,self.size_y))
self.rect = self.image.get_rect(topleft = (self.x_pos,self.y_pos))
else:
self.image = pygame.transform.scale(pygame.image.load(path).convert_alpha(),(size_x,size_y))
self.rect = self.image.get_rect(topleft = (self.x_pos,self.y_pos))
def collision_check(self):
if pygame.sprite.spritecollide(self,self.players,False):
collision_paddle = pygame.sprite.spritecollide(self,self.players,False)[0].rect
if player.movement_y > 0 and abs(self.rect.top - collision_paddle.bottom) < 10: #load of checks to ensure the correct side is being collided
collision_paddle.bottom = self.rect.top
player.movement_y = 0
self.can_jump1 = True
elif player.movement_y < 0 and abs(self.rect.bottom - collision_paddle.top) < 10 and not abs(self.rect.right - collision_paddle.left) < 10 and not abs(self.rect.left - collision_paddle.right) < 10:
collision_paddle.top = self.rect.bottom
player.movement_y *= -0.2
print("moving bottom")
elif player.movement_x < 0 and abs(self.rect.right - collision_paddle.left) < 10 and not abs(self.rect.bottom - collision_paddle.top) < 10:
collision_paddle.left = self.rect.right
print("moving left")
elif player.movement_x > 0 and abs(self.rect.left - collision_paddle.right) < 10 and not abs(self.rect.bottom - collision_paddle.top) < 10:
collision_paddle.right = self.rect.left
print("moving right")
else:
self.can_jump1 = self.rect.top == self.players.sprites()[0].rect.bottom
def can_jump_check(self):
return self.can_jump1
def update(self):
self.collision_check()
self.rect.centerx -= player.movement_x #trying to get rects to move the same distance as the player, if player moves 2 pixels right, rect moves 2 pixels left?
self.rect.centery -= 0
class Player(pygame.sprite.Sprite):
def __init__(self,x_pos,y_pos,size_x,size_y,speed_x,acceleration_y):
super().__init__()
self.x_pos = x_pos
self.y_pos = y_pos
self.size_x = size_x
self.size_y = size_y
self.speed_x = speed_x
self.shift_pressed = False
self.acceleration_y = acceleration_y
self.movement_x = 0
self.movement_y = 0
self.image = pygame.Surface((self.size_x,self.size_y))
self.image.fill("red")
self.rect = self.image.get_rect(center = (self.x_pos,self.y_pos))
def screen_constrain(self):
if self.rect.bottom >= sresy:
self.rect.bottom = sresy
def update(self):
if abs(self.movement_y) <= 8:
self.movement_y += GRAVITY
self.rect.centery += self.movement_y
if self.shift_pressed == False:
self.rect.centerx += self.movement_x #if set to 0, scrolling kindof works, although camera still scrolls even if player is stuck on block
elif self.shift_pressed == True:
self.rect.centerx += 2*self.movement_x
self.screen_constrain()
class GameManager:
def __init__(self,player_group,platform_group):
self.player_group = player_group
self.platform_group = platform_group
self.can_jump = True
def run_game(self):
#---drawing---#
self.player_group.draw(screen)
self.platform_group.draw(screen)
#---updating---#
self.player_group.update()
self.platform_group.update()
def game_checking(self):
#---checking---#
self.can_jump = any(p.can_jump_check() for p in self.platform_group)
return self.can_jump
#---Setup------------------------------------------#
#---constants-----#
global GRAVITY
GRAVITY = 0.25
#---Gamevariables-----#
can_jump = True
shift_pressed = False
music_playing = False
#---colour---#
bg_colour = (50,50,50)
white_colour = (255,255,255)
black_colour = (0,0,0)
#---res---#
resx = 900
resy = 700
resx_moved = resx - 50
resy_moved = resy - 50
sresx = 850 #base surface size, to be scaled up to resx_moved and resy_moved
sresy = 650
#---game map---#
game_map = [[0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,0],
[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],
[0,0,0,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1],
[0,1,1,1,1,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1]]
#---start window-----#
pygame.init()
clock = pygame.time.Clock()
screendisplay = pygame.display.set_mode((resx,resy))
screendisplay.fill(bg_colour)
pygame.display.set_caption("PlatformerGame")
screen = pygame.Surface((sresx,sresy))
screen.fill(white_colour)
#---startgame-----#
player = Player(425,325,50,50,2,30)
player_group = pygame.sprite.GroupSingle()
player_group.add(player)
platform_list = []
y_gm = 0
for row in game_map:
x_gm = 0
for tile in row:
if tile == 1:
platform_list.append(PlatformRect(x_gm * 50, y_gm * 50, 50, 50, "null",player_group)) #sets platform at given positions and size
x_gm += 1
y_gm += 1
platform_group = pygame.sprite.Group()
platform_group.add(platform_list)
game_manager = GameManager(player_group,platform_group)
#---Loop--------------------------------------------#
while True:
#---events-----#
for event in pygame.event.get():
if event.type == pygame.QUIT:
pygame.quit()
sys.exit()
if event.type == pygame.KEYDOWN:
if event.key == pygame.K_ESCAPE: #emergency
pygame.quit()
sys.exit()
if event.key == pygame.K_SPACE:
if can_jump == True:
player.movement_y = 0
player.movement_y -= player.acceleration_y * GRAVITY
if event.key == pygame.K_LSHIFT: #sprinting
player.shift_pressed = True
if event.key == pygame.K_a:
player.movement_x -= player.speed_x
if event.key == pygame.K_d:
player.movement_x += player.speed_x
if event.type == pygame.KEYUP:
if event.key == pygame.K_SPACE:
if player.movement_y < 0:
player.movement_y = 0
if event.key == pygame.K_a:
player.movement_x += player.speed_x
if event.key == pygame.K_d:
player.movement_x -= player.speed_x
if event.key == pygame.K_LSHIFT:
player.shift_pressed = False
#---background---#
surf = pygame.transform.scale(screen,(resx_moved,resy_moved)) #changes resolution
screendisplay.blit(surf,(25,25))
screen.fill(white_colour)
#---running---#
game_manager.run_game()
if not game_manager.game_checking() == True and player.rect.bottom < sresy: #checking if can_jump is true
can_jump = False
else:
can_jump = True
#---updating-----#
pygame.display.update()
clock.tick(120)
I will of course clarify anything about my code if it is not clear.