I am making a platformer where the player changes the terrain by swapping the background color. All of the mechanics function properly, but the rate my program runs gradually gets really, excruciatingly slow and I don't know why. I've tried tidying my code up in places but I can't seem to get it to run at a constant rate. Why would this be happening and how can I fix it? I appreciate any help or tips you guys got!
Here is my complete code:
import pygame, sys
clock = pygame.time.Clock()
from pygame.locals import *
pygame.init()
window_size = (900,600)
window = pygame.display.set_mode(window_size)
pygame.display.set_caption('Pygame Platformer')
moving_right = False
moving_left = False
unit = 30
fall = 10
jump = -10
p_speed = 3.4
black = ( 0, 0, 0)
white = (225, 225, 225)
teal = ( 0, 100, 100)
orange = (200, 75, 0)
grey = ( 60, 60, 60)
red = (170, 0, 0)
current_color = black
dark_color = grey
color_1 = teal
color_2 = red
game_map = [['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','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','2','2','2','2','2','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'],
['2','2','0','0','0','0','0','0','0','0','0','0','0','0','0','0','0','2','2'],
['1','1','2','2','2','2','2','2','2','2','2','2','2','2','2','2','2','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','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','0','0','0','0','0','0','0','3'],]
##############################################################################
class player():
def __init__(self):
self.rect = pygame.Rect(100,100,unit,unit)
self.vertical_momentum = 0
self.player_movement = []
self.jump_timer = 0
def movement(self):
self.player_movement = [0,0]
if moving_right == True:
self.player_movement[0] += p_speed
if moving_left == True:
self.player_movement[0] -= p_speed
self.player_movement[1] += self.vertical_momentum
self.vertical_momentum += 0.4
if self.vertical_momentum > fall:
self.vertical_momentum = fall
def draw(self, display):
pygame.draw.rect(display, dark_color, (self.rect.x, self.rect.y, unit, unit))
class room_0():
def __init__(self, block_map):
self.block_map = game_map
self.dark_blocks = []
self.color_blocks = []
def draw(self, window):
global tile_rects
tile_rects = []
y = 0
for layer in self.block_map:
x = 0
for tile in layer:
if tile == '1':
if current_color != color_1:
current_room.color_blocks.append(color_block(color_1, x*unit, y*unit))
tile_rects.append(pygame.Rect(x*unit,y*unit,unit,unit))
elif tile == '2':
if current_color != color_2:
current_room.color_blocks.append(color_block(color_2, x*unit, y*unit))
tile_rects.append(pygame.Rect(x*unit,y*unit,unit,unit))
elif tile == '3':
self.dark_blocks.append(dark_block(x*unit,y*unit))
tile_rects.append(pygame.Rect(x*unit,y*unit,unit,unit))
x += 1
y += 1
for i in self.dark_blocks:
i.draw(window)
for i in self.color_blocks:
i.draw(window)
class dark_block():
def __init__(self, x_position, y_position):
self.x = x_position
self.y = y_position
def draw(self, window):
pygame.draw.rect(window, dark_color, (self.x, self.y, unit, unit))
class color_block():
def __init__(self, color, x_position, y_position):
self.co = color
self.x = x_position
self.y = y_position
def draw(self, window):
pygame.draw.rect(window, self.co, (self.x, self.y, unit, unit))
tile_rects = []
p = player()
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
def object_movement():
global tile_rects
p.movement()
p.rect,collisions = move(p.rect,p.player_movement,tile_rects)
if collisions['bottom'] == True:
p.jump_timer = 0
p.vertical_momentum = 0
else:
p.jump_timer += 1
if collisions['top'] == True:
p.vertical_momentum = 0
def redraw_game_window():
window.fill(current_color)
current_room.draw(window)
p.draw(window)
pygame.display.update()
##############################################################################
rooms = [room_0(game_map)]
current_room = rooms[0]
t = 0
while True: # game loop
t +=1
print(t)
for event in pygame.event.get(): # event loop
if event.type == QUIT:
pygame.quit()
sys.exit()
if event.type == KEYDOWN:
if event.key == K_ESCAPE:
pygame.quit()
sys.exit()
if event.key == K_d:
moving_right = True
if event.key == K_a:
moving_left = True
if event.key == K_SPACE:
if p.jump_timer < 5:
p.vertical_momentum = jump
if event.key == K_LEFT: # color swapping
if current_color != color_1:
current_color = color_1
dark_color = black
else:
current_color = black
dark_color = grey
if event.key == K_RIGHT:
if current_color != color_2:
current_color = color_2
dark_color = black
else:
current_color = black
dark_color = grey
if event.type == KEYUP:
if event.key == K_d:
moving_right = False
if event.key == K_a:
moving_left = False
object_movement()
redraw_game_window()
clock.tick(60)
The issue is caused by the fact, that the containers (lists) self.dark_blocks
and self.color_blocks
are refilled in every frame, but you missed to clear them. Hence the number of elements int the containers is continuously growing. Since the content of this lists is drawn in every frame, the performance drops. You can't see this effect, because the elements of the lists are drawn on top of each other.
Clear self.dark_blocks
and self.color_blocks
at the begin of room_0.draw
, right after tile_rects
is cleared:
class room_0():
# [...]
def draw(self, window):
global tile_rects
tile_rects = []
self.dark_blocks = []
self.color_blocks = []
# [...]