How does bullet reflect of the wall

家住魔仙堡 提交于 2020-05-09 10:47:57

问题


I've been working on this project about tanks (based on game Tank Trouble) and I've made walls appear on the screen. How can I make that when projectiles/bullets collide with the wall they ricochet from it?

In the future, I am planning on the bullet colliding with a player/enemy.

Any help will be appreciated!

Here is game code:

class Game:

    def __init__(self):
        self.run = True
        self.screen_width = 1060
        self.screen_height = 798
        self.image = pygame.image.load("bin/sprites/background/background1.png")
        self.image = pygame.transform.scale(self.image, (self.screen_width, self.screen_height))
        self.screen = pygame.display.set_mode((self.screen_width, self.screen_height))

        # all_sprites is used to update and draw all sprites together.
        self.all_sprites = pygame.sprite.Group()

        # for collision detection with enemies.
        self.bullet_group = pygame.sprite.Group()

        # for collision detection with walls.
        self.wall_list = pygame.sprite.Group()

        self.tank = Tank()
        self.all_sprites.add(self.tank)

        self.enemy = Enemy()
        self.all_sprites.add(self.enemy)

        keys = pygame.key.get_pressed()
        if keys[pygame.K_SPACE]:
            self.bullet_group.add(bullet)
            self.all_sprites.add(bullet)

        # -------------- Walls --------------

        self.wallx = [0, 0, 1044, 0, 0, 260, 146, 130, 146, 146, 130, 146, 390, 522, 390, 260, 390, 406, 522, 522, 522, 652,
                 652, 782, 914, 782, 782, 914, 914, 914, 652, 652, 782, ]
        self.wally = [0, 0, 0, 782, 260, 0, 130, 130, 522, 390, 652, 652, 0, 0, 130, 260, 260, 390, 260, 260, 522, 130, 130,
                 0, 0, 260, 390, 390, 522, 652, 522, 652, 522, ]
        self.wallWidth = [16, 1060, 16, 1060, 130, 16, 130, 16, 130, 130, 16, 130, 16, 16, 148, 146, 16, 132, 16, 130, 16,
                     278, 16, 16, 16, 278, 148, 16, 148, 148, 146, 146, 16, ]
        self.wallHeight = [798, 16, 798, 16, 16, 130, 16, 408, 16, 16, 146, 16, 146, 146, 16, 16, 408, 16, 146, 16, 260, 16,
                      296, 146, 146, 16, 16, 148, 16, 16, 16, 16, 276]

        for i in range(len(self.wallx)):
            self.wall = Wall(self.wallx[i], self.wally[i], self.wallWidth[i], self.wallHeight[i])
            self.wall_list.add(self.wall)
            self.all_sprites.add(self.wall)



    def handle_events(self):

        self.enemy.handle_events()

        # responsible for colliding with walls
        tank_pos = pygame.math.Vector2(self.tank.pos)
        self.tank.handle_events()
        if pygame.sprite.spritecollide(self.tank, self.wall_list, False):
            self.tank.pos = tank_pos
            self.tank.rect.center = round(tank_pos[0]), round(tank_pos[1])


        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                self.run = False
                pygame.quit()
                sys.exit()
            elif event.type == pygame.KEYDOWN:
                if event.key == pygame.K_ESCAPE:
                    self.run = False
                if event.key == pygame.K_SPACE:
                    bullet = Bullet(self.tank)
                    self.bullet_group.add(bullet)
                    self.all_sprites.add(bullet)

    def update(self):
        # Calls `update` methods of all contained sprites.
        self.all_sprites.update()

    def player_score(self):
        font = pygame.font.SysFont("bin/font/Montserrat.ttf", 35)
        tank_score = font.render("PLAYER: " + str(self.tank.score), 1, white)
        self.screen.blit(tank_score, (200, 750))


    def draw(self):
        self.screen.blit(self.image, (0, 0))
        self.all_sprites.draw(self.screen)  # Draw the contained sprites.
        self.player_score()
        pygame.display.update()


class Tank(pygame.sprite.Sprite):

    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("bin/sprites/player/player_tank1.png")
        self.org_image = self.image.copy()

        # A nicer way to set the start pos with `get_rect`.
        self.rect = self.image.get_rect(center=(70, 600))

        self.vel = 3

        self.angle = 270  # starts looking right
        self.direction = pygame.Vector2(1, 0)
        self.pos = pygame.Vector2(self.rect.center)

        self.hp = 1
        self.score = 0

    def handle_events(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_LEFT]:
            self.angle += 3
        if keys[pygame.K_RIGHT]:
            self.angle -= 3
        if keys[pygame.K_UP] and self.rect.left - 5 > 0 and self.rect.top - 5 > 0 and self.rect.right + 5 < 1060 and self.rect.bottom + 5 < 798:
            self.move(-3)
        if keys[pygame.K_DOWN] and self.rect.left - 5 > 0 and self.rect.top - 5 > 0 and self.rect.right + 5 < 1060 and self.rect.bottom + 5 < 798:
            self.move(3)

        self.direction = pygame.Vector2(1, 0).rotate(-self.angle)
        self.image = pygame.transform.rotate(self.org_image, self.angle)
        self.rect = self.image.get_rect(center=self.rect.center)

    def move(self, vel):
        direction = pygame.Vector2(0, vel).rotate(-self.angle)
        self.pos += direction
        self.rect.center = round(self.pos[0]), round(self.pos[1])



class Enemy(pygame.sprite.Sprite):

    def __init__(self):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("bin/sprites/enemy/enemy_tank.png")
        self.org_image = self.image.copy()

        self.spawnx = [600, 850, 860]  # spawning x coord
        self.spawny = [70, 200, 700]  # spawning y coord
        self.i = random.randint(0, len(self.spawnx) - 1)

        # A nicer way to set the start pos with `get_rect`.
        self.rect = self.image.get_rect(center=(self.spawnx[self.i], self.spawny[self.i]))

        self.vel = 3
        self.hp = 1
        self.score = 0

        if self.i == 0:
            self.angle = 180
        elif self.i == 1:
            self.angle = 90
        elif self.i == 2:
            self.angle = 0

        self.direction = pygame.Vector2(1, 0)
        self.pos = pygame.Vector2(self.rect.center)

    def handle_events(self):
        keys = pygame.key.get_pressed()
        if keys[pygame.K_a]:
            self.angle += 3
        if keys[pygame.K_d]:
            self.angle -= 3
        if keys[pygame.K_w]:
            self.move(-3)
        if keys[pygame.K_s]:
            self.move(3)

        self.direction = pygame.Vector2(1, 0).rotate(-self.angle)
        self.image = pygame.transform.rotate(self.org_image, self.angle)
        self.rect = self.image.get_rect(center=self.rect.center)

    def move(self, vel):
        direction = pygame.Vector2(0, vel).rotate(-self.angle)
        self.pos += direction
        self.rect.center = round(self.pos[0]), round(self.pos[1])


class Wall(pygame.sprite.Sprite):

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

        # Make a wall, of the size specified in the parameters
        self.image = pygame.Surface([width, height])
        self.image.fill(dark_gray) # change wall color

        # Make our top-left corner the passed-in location.
        self.rect = self.image.get_rect()
        self.rect.y = y
        self.rect.x = x


class Bullet(pygame.sprite.Sprite):

    def __init__(self, tank):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.image.load("bin/sprites/bullet/bullet.png")
        self.image = pygame.transform.scale(self.image, (16, 16))
        self.rect = self.image.get_rect()
        self.rect.centerx = tank.rect.centerx + 3  # How much pixels from tank turret on x axis
        self.rect.centery = tank.rect.centery - 25  # How much pixels from tank turret on y axis
        self.angle = tank.angle
        self.pos = pygame.Vector2(self.rect.center)
        self.direction = pygame.Vector2(0, -10).rotate(-self.angle)
        self.lives = 4  # how many times bounces

    def update(self):
        game = Game()



        self.pos += self.direction
        self.rect.center = round(self.pos[0]), round(self.pos[1])


        if self.rect.left < 0 or self.rect.left < game.wall.rect.y:
            self.direction.x *= -1
            self.rect.left = 0
            self.pos.x = self.rect.centerx
            self.lives -= 1
            if self.lives == 0:
                return self.kill()
            bounce.play()

        if self.rect.right > 1060:
            self.direction.x *= -1
            self.rect.right = 1060
            self.pos.x = self.rect.centerx
            self.lives -= 1
            if self.lives == 0:
                return self.kill()
            bounce.play()

        if self.rect.top < 0:
            self.direction.y *= -1
            self.rect.top = 0
            self.pos.y = self.rect.centery
            self.lives -= 1
            if self.lives == 0:
                return self.kill()
            bounce.play()

        if self.rect.bottom > 798:
            self.direction.y *= -1
            self.rect.right = 798
            self.pos.y = self.rect.centery
            self.lives -= 1
            if self.lives == 0:
                return self.kill()
            bounce.play()

回答1:


I have a solution. First check for a collision with bullet.rect.colliderect(wall.rect), then check if the center of the bullet is left of the wall, then it must be colliding on the left side, using this logic, you can do the same for the other sides.

So in the bullet update, i added:

for wall in game.wall_list:
     if self.rect.colliderect(wall.rect): #if collided
         if self.rect.centerx < wall.rect.left: 
             self.direction.x *= -1
             self.rect.right = wall.rect.left
             self.lives -= 1
             if self.lives == 0:
                 return self.kill()    
             break # break so dont check every other wall
         if self.rect.centerx > wall.rect.right:
             self.direction.x *= -1
             self.rect.left = wall.rect.right
             self.lives -= 1
             if self.lives == 0:
                 return self.kill()    
             break  
         if self.rect.centery < wall.rect.top:
             self.direction.y *= -1
             self.rect.bottom = wall.rect.top
             self.lives -= 1
             if self.lives == 0:
                 return self.kill()    
             break    
         if self.rect.centery > wall.rect.bottom:
             self.direction.y *= -1
             self.rect.top = wall.rect.bottom
             self.lives -= 1
             if self.lives == 0:
                 return self.kill()    
             break 


来源:https://stackoverflow.com/questions/61135231/how-does-bullet-reflect-of-the-wall

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!