pygame sprite wall collision

后端 未结 3 1745
北恋
北恋 2020-11-28 16:13

I am working on a platform game in python and pygame. The entire code can be found at \"https://github.com/C-Kimber/FBLA_Game\". The issue I am having is with the collision

相关标签:
3条回答
  • 2020-11-28 16:37

    The easiest way to handle collisions with walls is to move the player rect or sprite along the x-axis first, check if it collides with a wall and then set its self.rect.right = wall.rect.left if it's moving to the right or self.rect.left = wall.rect.right if it's moving to the left. Afterwards you do the same with the y-axis. You have to do the movement separately, otherwise you wouldn't know the direction and how to reset the position of the rect.

    import pygame as pg
    from pygame.math import Vector2
    
    
    class Player(pg.sprite.Sprite):
    
        def __init__(self, x, y, walls):
            super().__init__()
            self.image = pg.Surface((30, 50))
            self.image.fill(pg.Color('dodgerblue1'))
            self.rect = self.image.get_rect(center=(x, y))
            self.pos = Vector2(x, y)  # Position vector.
            self.vel = Vector2(0, 0)  # Velocity vector.
            self.walls = walls  # A reference to the wall group.
    
        def update(self):
            self.pos += self.vel
            self.wall_collisions()
    
        def wall_collisions(self):
            """Handle collisions with walls."""
            self.rect.centerx = self.pos.x
            for wall in pg.sprite.spritecollide(self, self.walls, False):
                if self.vel.x > 0:
                    self.rect.right = wall.rect.left
                elif self.vel.x < 0:
                    self.rect.left = wall.rect.right
                self.pos.x = self.rect.centerx
    
            self.rect.centery = self.pos.y
            for wall in pg.sprite.spritecollide(self, self.walls, False):
                if self.vel.y > 0:
                    self.rect.bottom = wall.rect.top
                elif self.vel.y < 0:
                    self.rect.top = wall.rect.bottom
                self.pos.y = self.rect.centery
    
    
    class Wall(pg.sprite.Sprite):
    
        def __init__(self, x, y, w, h):
            super().__init__()
            self.image = pg.Surface((w, h))
            self.image.fill(pg.Color('sienna1'))
            self.rect = self.image.get_rect(topleft=(x, y))
    
    
    def main():
        screen = pg.display.set_mode((640, 480))
        clock = pg.time.Clock()
    
        all_sprites = pg.sprite.Group()
        walls = pg.sprite.Group()
    
        wall = Wall(100, 200, 300, 30)
        wall2 = Wall(230, 70, 30, 300)
        walls.add(wall, wall2)
        all_sprites.add(wall, wall2)
    
        player = Player(300, 300, walls)
        all_sprites.add(player)
    
        done = False
    
        while not done:
            for event in pg.event.get():
                if event.type == pg.QUIT:
                    done = True
    
            keys = pg.key.get_pressed()
            if keys[pg.K_w]:
                player.vel.y = -3
            elif keys[pg.K_s]:
                player.vel.y = 3
            else:
                player.vel.y = 0
            if keys[pg.K_a]:
                player.vel.x = -3
            elif keys[pg.K_d]:
                player.vel.x = 3
            else:
                player.vel.x = 0
    
            all_sprites.update()
            screen.fill((30, 30, 30))
            all_sprites.draw(screen)
    
            pg.display.flip()
            clock.tick(30)
    
    
    if __name__ == '__main__':
        pg.init()
        main()
        pg.quit()
    
    0 讨论(0)
  • 2020-11-28 16:38
    elif self.rect.top <= block.rect.bottom and self.rect.top >= block.rect.bottom - 15:  # Moving up; Hit the bottom side of the wall
            self.rect.top = block.rect.bottom
            self.yvel = 0
    

    Shouldn't yvel be set to a positive number to make it go up?

    0 讨论(0)
  • 2020-11-28 16:59

    Thank you to user sloth! The question he linked gave me some much needed clarity. It took me a bit but I implemented it. I created a function for the collision.

    def wallColl(self, xvel, yvel, colliders):
        for collider in colliders:
            if pygame.sprite.collide_rect(self, collider):
                if xvel > 0:
                    self.rect.right = collider.rect.left
                    self.xvel = 0
                if xvel < 0:
                    self.rect.left = collider.rect.right
                    self.xvel = 0
                if yvel < 0:
                    self.rect.bottom = collider.rect.top
                    self.onGround = True
                    self.jumps = 3
                    self.yvel = 0
                if yvel > 0:
                    self.yvel = 0
                    self.rect.top = collider.rect.bottom
    

    And then I call them in my update function.

    def update(self):
        self.rect.x += self.xvel
        # self.walls is an array of sprites.
        self.wallColl(self.xvel, 0, self.walls) 
    
        self.rect.y -= self.yvel
        self.onGround = False
        self.wallColl(0, self.yvel, self.walls)
    
        self.wallCollisions()
        if self.otherplayers != None:
            self.playerCollisions()
    
        # Gravity
        if self.onGround == False:
            self.yvel-=.0066*self.mass
    
        self.boundries(highbound, lowbound, leftbound, rightbound)
        self.down = False
    

    The actual useage in my game makes usability near perfect. Not 100% though, this is not a perfect answer.

    0 讨论(0)
提交回复
热议问题