How can I make all of the background move as opposed to just one platform? - Printable Version +- Python Forum (https://python-forum.io) +-- Forum: Python Coding (https://python-forum.io/forum-7.html) +--- Forum: Game Development (https://python-forum.io/forum-11.html) +--- Thread: How can I make all of the background move as opposed to just one platform? (/thread-23401.html) |
How can I make all of the background move as opposed to just one platform? - HelpMEE - Dec-28-2019 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. RE: How can I make all of the background move as opposed to just one platform? - michael1789 - Dec-28-2019 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. RE: How can I make all of the background move as opposed to just one platform? - HelpMEE - Dec-28-2019 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 RE: How can I make all of the background move as opposed to just one platform? - michael1789 - Dec-28-2019 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. RE: How can I make all of the background move as opposed to just one platform? - HelpMEE - Dec-28-2019 How would I implement that though? RE: How can I make all of the background move as opposed to just one platform? - michael1789 - Dec-28-2019 This is the tutorial I learned it from. https://www.youtube.com/watch?v=uWvb3QzA48c&list=PLsk-HSGFjnaG-BwZkuAOcVwWldfCLu1pq 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 = 0You can also use something like: def moveLeft(self): hits = pygame.sprite.spritecollide(self.player, self.platforms, False) if not hits: self.xVel = 6I think that works. RE: How can I make all of the background move as opposed to just one platform? - HelpMEE - Dec-28-2019 Alright thanks! |