Python Forum
How can I make all of the background move as opposed to just one platform?
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
How can I make all of the background move as opposed to just one platform?
#1
When I collide into a platform, the player is supposed to stop moving, and it did, but it also glitched slightly into the rectangle, so I found a work-around which is supposed to make the background move slightly over in order to compensate, but it only moves one platform, and if you were to repeatedly run into a platform it would cause it to shift indefinitely. I'm also currently just making it equal to the players left and right sides, but when I use Level(self).bgX += 10 inside the if statement in the player class that controls collisions it doesn't work, and I end up just glitching inside of it.

Here is my code:

import pygame

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 255, 255)

SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

class Player(pygame.sprite.Sprite):

    def __init__(self):


        super().__init__()


        width = 40
        height = 60
        self.image = pygame.Surface([width, height])
        self.image.fill(RED)


        self.rect = self.image.get_rect()


        self.xVel = 0
        self.yVel = 0


        self.level = None

    def update(self):
        self.calc_grav()


        Level(self).bgX += self.xVel



        block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
        for block in block_hit_list:
            if self.xVel < 0:
                self.friction()
                block.rect.left = 350 + 40
            elif self.xVel > 0:
                self.friction()
                block.rect.right = 350

        self.rect.y += self.yVel


        block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
        for block in block_hit_list:


            if self.yVel > 0:
                self.rect.bottom = block.rect.top
            elif self.yVel < 0:
                self.rect.top = block.rect.bottom


            self.yVel = 0

            if isinstance(block, MovingPlatform):
                Level(self).bgX += block.xVel

    def calc_grav(self):
        if self.yVel == 0:
            self.yVel = 1
        else:
            self.yVel +=0.5


        if self.rect.y >= SCREEN_HEIGHT - self.rect.height and self.yVel >= 0:
            self.yVel = 0
            self.rect.y = SCREEN_HEIGHT - self.rect.height

    def jump(self):
        self.rect.y += 2
        platform_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
        self.rect.y -= 2


        if len(platform_hit_list) > 0 or self.rect.bottom >= SCREEN_HEIGHT:
            self.yVel = -15

    def moveLeft(self):

        self.xVel = 6

    def moveRight(self):

        self.xVel = -6

    def friction(self):

        self.xVel = 0


class Platform(pygame.sprite.Sprite):

    def __init__(self, width, height):
        super().__init__()

        self.image = pygame.Surface([width, height])
        self.image.fill(GREEN)

        self.rect = self.image.get_rect()


class MovingPlatform(Platform):

    xVel = 0
    yVel = 0

    boundary_top = 0
    boundary_bottom = 0
    boundary_left = 0
    boundary_right = 0

    player = None

    level = None

    def update(self):
        self.rect.x += self.xVel

        hit = pygame.sprite.collide_rect(self, self.player)
        if hit:



            if self.xVel < 0:
                self.player.rect.right = self.rect.left
            else:

                self.player.rect.left = self.rect.right

        self.rect.y += self.yVel


        hit = pygame.sprite.collide_rect(self, self.player)
        if hit:

            if self.yVel < 0:
                self.player.rect.bottom = self.rect.top
            else:
                self.player.rect.top = self.rect.bottom

        if self.rect.bottom > self.boundary_bottom or self.rect.top < self.boundary_top:
            self.yVel *= -1

        cur_pos = self.rect.x - self.level.bgX
        if cur_pos < self.boundary_left or cur_pos > self.boundary_right:
            self.xVel *= -1


class Level(object):

    def __init__(self, player):
        self.platform_list = pygame.sprite.Group()
        self.enemy_list = pygame.sprite.Group()
        self.player = player

        self.background = None


        self.bgX = 0
        self.level_limit = -1000

    def update(self):
        self.platform_list.update()
        self.enemy_list.update()

    def draw(self, screen):

        screen.fill(BLUE)


        self.platform_list.draw(screen)
        self.enemy_list.draw(screen)

        for platform in self.platform_list:
            platform.rect.x += self.player.xVel

        for enemy in self.enemy_list:
            enemy.rect.x += self.player.xVel

class Level_01(Level):

    def __init__(self, player):


        Level.__init__(self, player)

        self.level_limit = -1500


        level = [[210, 70, 500, 500],
                 [210, 70, 800, 400],
                 [210, 70, 1000, 500],
                 [210, 70, 1120, 280],
                 ]


        for platform in level:
            block = Platform(platform[0], platform[1])
            block.rect.x = platform[2]
            block.rect.y = platform[3]
            block.player = self.player
            self.platform_list.add(block)


        block = MovingPlatform(70, 40)
        block.rect.x = 1350
        block.rect.y = 280
        block.boundary_left = 1350
        block.boundary_right = 1600
        block.xVel = 1
        block.player = self.player
        block.level = self
        self.platform_list.add(block)


class Level_02(Level):

    def __init__(self, player):

        Level.__init__(self, player)

        self.level_limit = -1000


        level = [[210, 70, 500, 550],
                 [210, 70, 800, 400],
                 [210, 70, 1000, 500],
                 [210, 70, 1120, 280],
                 ]


        for platform in level:
            block = Platform(platform[0], platform[1])
            block.rect.x = platform[2]
            block.rect.y = platform[3]
            block.player = self.player
            self.platform_list.add(block)

        block = MovingPlatform(70, 70)
        block.rect.x = 1500
        block.rect.y = 300
        block.boundary_top = 100
        block.boundary_bottom = 550
        block.yVel = -1
        block.player = self.player
        block.level = self
        self.platform_list.add(block)


def main():
    pygame.init()


    size = [SCREEN_WIDTH, SCREEN_HEIGHT]
    screen = pygame.display.set_mode(size)

    pygame.display.set_caption("Platformer with moving platforms")

    player = Player()

    level_list = []
    level_list.append(Level_01(player))

    current_level_no = 0
    current_level = level_list[current_level_no]

    active_sprite_list = pygame.sprite.Group()
    player.level = current_level

    player.rect.x = 350
    player.rect.y = SCREEN_HEIGHT - player.rect.height
    active_sprite_list.add(player)


    done = False


    clock = pygame.time.Clock()

    # -------- Main Program Loop -----------
    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.moveLeft()
                if event.key == pygame.K_RIGHT:
                    player.moveRight()
                if event.key == pygame.K_UP:
                    player.jump()

            if event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT and player.xVel > 0:
                    player.friction()
                if event.key == pygame.K_RIGHT and player.xVel < 0:
                    player.friction()

        active_sprite_list.update()

        current_level.update()



        current_position = current_level.bgX
        if current_position < current_level.level_limit:
            if current_level_no < len(level_list)-1:
                player.rect.x = 350
                current_level_no += 1
                current_level = level_list[current_level_no]
                player.level = current_level
            else:

                done = True


        current_level.draw(screen)
        active_sprite_list.draw(screen)


        clock.tick(60)


        pygame.display.flip()

    pygame.quit()

if __name__ == "__main__":
    main()
Is there a way to make the entire background shift as opposed to just the platform? It would also help if someone could tell me why you can't just hold the right arrow key and jump simultaneously after you collide with a platform.
Reply
#2
I think it is best just to fix your original collision detection than coming up with a "work round" like this. You've just replaced one glitch with another.

Do you still have the original code where it glitched into the platform? That is definitely the thing to fix IMHO.
Reply
#3
Yes I do.
Here is the previous code:

import pygame

BLACK = (0, 0, 0)
WHITE = (255, 255, 255)
GREEN = (0, 255, 0)
RED = (255, 0, 0)
BLUE = (0, 255, 255)
 
SCREEN_WIDTH = 800
SCREEN_HEIGHT = 600

class Player(pygame.sprite.Sprite):
 
    def __init__(self):
 

        super().__init__()
 

        width = 40
        height = 60
        self.image = pygame.Surface([width, height])
        self.image.fill(RED)
 

        self.rect = self.image.get_rect()
 

        self.xVel = 0
        self.yVel = 0
 

        self.level = None
 
    def update(self):
        self.calc_grav()
 

        Level(self).bgX += self.xVel
 
 

        block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
        for block in block_hit_list:
            if self.xVel < 0:
                self.rect.right = block.rect.left
                self.friction()
            elif self.xVel > 0:
                self.rect.left = block.rect.right
                self.friction()
 
        self.rect.y += self.yVel
 

        block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
        for block in block_hit_list:
 

            if self.yVel > 0:
                self.rect.bottom = block.rect.top
            elif self.yVel < 0:
                self.rect.top = block.rect.bottom
 

            self.yVel = 0
 
            if isinstance(block, MovingPlatform):
                Level(self).bgX += block.xVel
 
    def calc_grav(self):
        if self.yVel == 0:
            self.yVel = 1
        else:
            self.yVel +=0.5
 

        if self.rect.y >= SCREEN_HEIGHT - self.rect.height and self.yVel >= 0:
            self.yVel = 0
            self.rect.y = SCREEN_HEIGHT - self.rect.height
 
    def jump(self):
        self.rect.y += 2
        platform_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
        self.rect.y -= 2
 

        if len(platform_hit_list) > 0 or self.rect.bottom >= SCREEN_HEIGHT:
            self.yVel = -15
 
    def moveLeft(self):

        self.xVel = 6
 
    def moveRight(self):

        self.xVel = -6
 
    def friction(self):

        self.xVel = 0
 
 
class Platform(pygame.sprite.Sprite):
 
    def __init__(self, width, height):
        super().__init__()
 
        self.image = pygame.Surface([width, height])
        self.image.fill(GREEN)
 
        self.rect = self.image.get_rect()
 
 
class MovingPlatform(Platform):

    xVel = 0
    yVel = 0
 
    boundary_top = 0
    boundary_bottom = 0
    boundary_left = 0
    boundary_right = 0
 
    player = None
 
    level = None
 
    def update(self):
        self.rect.x += self.xVel
 
        hit = pygame.sprite.collide_rect(self, self.player)
        if hit:

 

            if self.xVel < 0:
                self.player.rect.right = self.rect.left
            else:

                self.player.rect.left = self.rect.right
 
        self.rect.y += self.yVel
 

        hit = pygame.sprite.collide_rect(self, self.player)
        if hit:

            if self.yVel < 0:
                self.player.rect.bottom = self.rect.top
            else:
                self.player.rect.top = self.rect.bottom
 
        if self.rect.bottom > self.boundary_bottom or self.rect.top < self.boundary_top:
            self.yVel *= -1
 
        cur_pos = self.rect.x - self.level.bgX
        if cur_pos < self.boundary_left or cur_pos > self.boundary_right:
            self.xVel *= -1
 
 
class Level(object):
 
    def __init__(self, player):
        self.platform_list = pygame.sprite.Group()
        self.enemy_list = pygame.sprite.Group()
        self.player = player
         
        self.background = None
     

        self.bgX = 0
        self.level_limit = -1000
 
    def update(self):
        self.platform_list.update()
        self.enemy_list.update()
 
    def draw(self, screen):
 
        screen.fill(BLUE)
 

        self.platform_list.draw(screen)
        self.enemy_list.draw(screen)

        for platform in self.platform_list:
            platform.rect.x += self.player.xVel
 
        for enemy in self.enemy_list:
            enemy.rect.x += self.player.xVel
 
class Level_01(Level):
 
    def __init__(self, player):
 

        Level.__init__(self, player)
 
        self.level_limit = -1500
 

        level = [[210, 70, 500, 500],
                 [210, 70, 800, 400],
                 [210, 70, 1000, 500],
                 [210, 70, 1120, 280],
                 ]
 

        for platform in level:
            block = Platform(platform[0], platform[1])
            block.rect.x = platform[2]
            block.rect.y = platform[3]
            block.player = self.player
            self.platform_list.add(block)
 

        block = MovingPlatform(70, 40)
        block.rect.x = 1350
        block.rect.y = 280
        block.boundary_left = 1350
        block.boundary_right = 1600
        block.xVel = 1
        block.player = self.player
        block.level = self
        self.platform_list.add(block)
 
 
class Level_02(Level):
 
    def __init__(self, player):
 
        Level.__init__(self, player)
 
        self.level_limit = -1000
 

        level = [[210, 70, 500, 550],
                 [210, 70, 800, 400],
                 [210, 70, 1000, 500],
                 [210, 70, 1120, 280],
                 ]
 

        for platform in level:
            block = Platform(platform[0], platform[1])
            block.rect.x = platform[2]
            block.rect.y = platform[3]
            block.player = self.player
            self.platform_list.add(block)
 
        block = MovingPlatform(70, 70)
        block.rect.x = 1500
        block.rect.y = 300
        block.boundary_top = 100
        block.boundary_bottom = 550
        block.yVel = -1
        block.player = self.player
        block.level = self
        self.platform_list.add(block)
 
 
def main():
    pygame.init()
 

    size = [SCREEN_WIDTH, SCREEN_HEIGHT]
    screen = pygame.display.set_mode(size)
 
    pygame.display.set_caption("Platformer with moving platforms")
 
    player = Player()
 
    level_list = []
    level_list.append(Level_01(player))
 
    current_level_no = 0
    current_level = level_list[current_level_no]
 
    active_sprite_list = pygame.sprite.Group()
    player.level = current_level
 
    player.rect.x = 350
    player.rect.y = SCREEN_HEIGHT - player.rect.height
    active_sprite_list.add(player)
 

    done = False
 

    clock = pygame.time.Clock()
 
    # -------- Main Program Loop -----------
    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.moveLeft()
                if event.key == pygame.K_RIGHT:
                    player.moveRight()
                if event.key == pygame.K_UP:
                    player.jump()
 
            if event.type == pygame.KEYUP:
                if event.key == pygame.K_LEFT and player.xVel > 0:
                    player.friction()
                if event.key == pygame.K_RIGHT and player.xVel < 0:
                    player.friction()
 
        active_sprite_list.update()
 
        current_level.update()
 


        current_position = current_level.bgX
        if current_position < current_level.level_limit:
            if current_level_no < len(level_list)-1:
                player.rect.x = 350
                current_level_no += 1
                current_level = level_list[current_level_no]
                player.level = current_level
            else:

                done = True
 

        current_level.draw(screen)
        active_sprite_list.draw(screen)
 

        clock.tick(60)
 

        pygame.display.flip()
 
    pygame.quit()
 
if __name__ == "__main__":
    main()

 
        

Here is the section I think is causing the problem
block_hit_list = pygame.sprite.spritecollide(self, self.level.platform_list, False)
        for block in block_hit_list:
            if self.xVel < 0:
                self.rect.right = block.rect.left
                self.friction()
            elif self.xVel > 0:
                self.rect.left = block.rect.right
                self.friction()
Friction sets the xVel to zero

@michael1789
Reply
#4
I think your problem is actually here:
  def moveLeft(self):
                       
        self.xVel = 6
                       <-------- Check for collision then move if there is none.  If there is, 
                                 self.xVel = 0
  
    def moveRight(self):
 
        self.xVel = -6


It's just if you push a key the screen moves. But if there is a block in the way then you don't want that to happen.
Reply
#5
How would I implement that though?
Reply
#6
This is the tutorial I learned it from.

https://www.youtube.com/watch?v=uWvb3QzA...WldfCLu1pq

He uses:
def update(self):
        # Game Loop - Update
        self.all_sprites.update()
        hits = pg.sprite.spritecollide(self.player, self.platforms, False)
        if hits:
            self.player.pos.y = hits[0].rect.top
            self.player.vel.y = 0
You can also use something like:
def moveLeft(self):
                        
     hits = pygame.sprite.spritecollide(self.player, self.platforms, False)
     if not hits:
         self.xVel = 6
I think that works.
Reply
#7
Alright thanks!
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  [PyGame] Players not falling from the platform, and some other errors. urmom33 1 1,564 Jan-23-2023, 10:28 PM
Last Post: deanhystad
  How to make an image move in relation to another in PYGAME CompleteNewb 1 2,280 Nov-10-2021, 03:38 PM
Last Post: metulburr
  [PyGame] how to make objects move at a precise amount of time? Zhaleh 2 2,547 Aug-02-2020, 02:52 PM
Last Post: Zhaleh
  How to make a walljump + move between rooms ? dMn420 1 2,530 Jul-17-2019, 08:49 PM
Last Post: SheeppOSU

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020