Search code examples
pythonpygamepython-3.5pygame-clock

Why is my character ignoring the clock tick when i add the background?


This is what happens when i don't have a background: https://www.youtube.com/watch?v=S-bv-j8le24

this is the code:

import pygame

pygame.init()

#####Variables#####

white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
gameWindowWidth = 1280
gameWindowHeight = 720
gameRunning = True
clock = pygame.time.Clock()

###################

#####Loading#####

ninja01 = pygame.image.load("C:\\Users\Tom\Desktop\gameImages\charSprite\s_Idle__000.png")
background = pygame.image.load("C:\\Users\Tom\Desktop\gameImages\Background\DistantCity\PNG\m_image.png")

#################

#####Classes#####

class player():
    def __init__(self):
        self.playerX = gameWindowWidth * 0.2
        self.playerY = gameWindowHeight * 0.8
        self.changeOnX = 0

    def changingX(self):
        if event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
            self.changeOnX = 5
        if event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT:
            self.changeOnX = -5
        if event.type == pygame.KEYUP and event.key == pygame.K_RIGHT:
            self.changeOnX = 0
        if event.type == pygame.KEYUP and event.key == pygame.K_LEFT:
            self.changeOnX = 0

    def move(self):
        self.playerX = self.playerX + self.changeOnX

        gameWindow.blit(ninja01, (self.playerX, self.playerY))


################

ninja = player()
gameWindow = pygame.display.set_mode((gameWindowWidth, gameWindowHeight))
pygame.display.set_caption("Platformer Game")

while gameRunning == True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            gameRunning = False


    #gameWindow.blit(background, (0, 0))
    ninja.changingX()
    ninja.move()
    pygame.display.update()
    clock.tick(144)

this is what happens when i do have a background: https://www.youtube.com/watch?v=l89zZQ_8kzg

this is the code:

import pygame

pygame.init()

#####Variables#####

white = (255,255,255)
black = (0,0,0)
red = (255,0,0)
green = (0,255,0)
blue = (0,0,255)
gameWindowWidth = 1280
gameWindowHeight = 720
gameRunning = True
clock = pygame.time.Clock()

###################

#####Loading#####

ninja01 = pygame.image.load("C:\\Users\Tom\Desktop\gameImages\charSprite\s_Idle__000.png")
background = pygame.image.load("C:\\Users\Tom\Desktop\gameImages\Background\DistantCity\PNG\m_image.png")

#################

#####Classes#####

class player():
    def __init__(self):
        self.playerX = gameWindowWidth * 0.2
        self.playerY = gameWindowHeight * 0.8
        self.changeOnX = 0

    def changingX(self):
        if event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
            self.changeOnX = 5
        if event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT:
            self.changeOnX = -5
        if event.type == pygame.KEYUP and event.key == pygame.K_RIGHT:
            self.changeOnX = 0
        if event.type == pygame.KEYUP and event.key == pygame.K_LEFT:
            self.changeOnX = 0

    def move(self):
        self.playerX = self.playerX + self.changeOnX

        gameWindow.blit(ninja01, (self.playerX, self.playerY))


################

ninja = player()
gameWindow = pygame.display.set_mode((gameWindowWidth, gameWindowHeight))
pygame.display.set_caption("Platformer Game")

while gameRunning == True:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            gameRunning = False


    gameWindow.blit(background, (0, 0))
    ninja.changingX()
    ninja.move()
    pygame.display.update()
    clock.tick(144)

The code is exactly the same appart from the fact that "gameWindow.blit(background, (0, 0))" is commented out in the first one.

My question is why is my character going so much slower when i add the background?

Also in the second one his movement speed doesn't change until i lower the clock.tick to around 30 & below.


Solution

  • The timing of all of your entire game loop is being controlled by the Clock.tick method. So you are only running your input and position update code once each frame. The more sprites you have, the more it will slow down this cycle which is what you are observing when you include the background. You can separate the timing of your input and update logic from the rendering cycle and this would solve your problem. Consider the refactor I have performed below:

    import pygame
    
    pygame.init()
    
    #####Variables#####
    
    white = (255,255,255)
    black = (0,0,0)
    red = (255,0,0)
    green = (0,255,0)
    blue = (0,0,255)
    gameWindowWidth = 1280
    gameWindowHeight = 720
    gameRunning = True
    clock = pygame.time.Clock()
    
    ###################
    
    #####Loading#####
    
    ninja01 = pygame.image.load("/path/to/your/ninja/sprite")
    background = pygame.image.load("/path/to/your/background/sprite")
    
    #################
    
    #####Classes#####
    
    class player():
        def __init__(self):
            self.playerX = gameWindowWidth * 0.2
            self.playerY = gameWindowHeight * 0.8
            self.velocity = 0.0
    
        def setVelocity(self, velocity):
            self.velocity = velocity
    
        def update(self, dt):
            self.playerX += self.velocity * dt
    
        def draw(self):
            gameWindow.blit(ninja01, (self.playerX, self.playerY))
    
    
    ################
    
    ninja = player()
    gameWindow = pygame.display.set_mode((gameWindowWidth, gameWindowHeight))
    pygame.display.set_caption("Platformer Game")
    
    fps = 60
    target_frame_time = 1.0 / fps
    current_frame_time = 0.0
    
    while gameRunning == True:
        dt = clock.tick()
    
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                gameRunning = False
            if event.type == pygame.KEYDOWN and event.key == pygame.K_RIGHT:
                ninja.setVelocity(1)
            if event.type == pygame.KEYDOWN and event.key == pygame.K_LEFT:
                ninja.setVelocity(-1)
            if event.type == pygame.KEYUP and event.key == pygame.K_RIGHT:
                ninja.setVelocity(0)
            if event.type == pygame.KEYUP and event.key == pygame.K_LEFT:
                ninja.setVelocity(0)
    
        ninja.update(dt)
    
        current_frame_time += dt
    
        if current_frame_time >= target_frame_time:
            gameWindow.blit(background, (0, 0))
            ninja.draw()
    
            pygame.display.flip()
    
            current_frame_time -= target_frame_time
    

    When update is called on the ninja, the position is calculated using the equation:

    distance = velocity * time
    

    With these code changes, you can now achieve a consistent frame rate while your input and game update logic run continuously.