【问题标题】:Pygame tutorial - tank with collision detectionPygame 教程 - 带有碰撞检测的坦克
【发布时间】:2021-05-17 16:05:24
【问题描述】:

我是 Pygame 的新手,正在尝试学习精灵和碰撞检测。我找到了一些代码并尝试为其添加一些功能。

基本思想是我有一个可以原地旋转的多边形。当用户按下空格键时,多边形会发射一个可以在框架周围反弹的弹丸。如果弹丸再次击中多边形,我想相当程序

首先,这里是代码

import pygame

class Player(pygame.sprite.Sprite):
    def __init__(self):
        super().__init__()
        self.image = pygame.Surface((32, 32))
        self.image.fill((0, 0, 0))
        self.image.set_colorkey((0, 0, 0))
        self.fire_from = (36, 20)
        pygame.draw.polygon(self.image, pygame.Color('dodgerblue'), ((0, 0), (32, 16), (0, 32)))
        self.org_image = self.image.copy()
        self.angle = 0
        self.direction = pygame.Vector2(1, 0)
        self.rect = self.image.get_rect(center=(200, 200))
        self.pos = pygame.Vector2(self.rect.center)

    def update(self, events, dt):

        for e in events:
            if e.type == pygame.KEYDOWN:
                if e.key == pygame.K_SPACE:
                    bullet = Projectile(self.fire_from, self.direction.normalize())
                    self.groups()[0].add(bullet)
        pressed = pygame.key.get_pressed()

        if pressed[pygame.K_LEFT]:
            self.angle += 3
        if pressed[pygame.K_RIGHT]:
            self.angle -= 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)

class Projectile(pygame.sprite.Sprite):
    def __init__(self, pos, direction):
        super().__init__()
        self.image = pygame.Surface((8, 8))
        self.image.fill((0, 0, 0))
        self.image.set_colorkey((0, 0, 0))
        pygame.draw.circle(self.image, pygame.Color('orange'), (4, 4), 4)
        self.rect = self.image.get_rect(center=pos)
        self.direction = direction
        self.pos = pygame.Vector2(self.rect.center)
        self.max_bounce = 10

    def update(self, events, dt):

        #print(self.pos)
        # Bounding box of the screen
        screen_r = pygame.display.get_surface().get_rect()

        # where we would move next
        next_pos = self.pos + self.direction * dt

        # we hit a wall
        if not screen_r.contains(self.rect):

            # after 10 hits, destroy self
            self.max_bounce -= 1
            if self.max_bounce == 0:
                return self.kill()

            # horizontal reflection
            if next_pos.x > screen_r.right or next_pos.x < screen_r.left:
                self.direction.x *= -1

            # vertical reflection
            if next_pos.y > screen_r.bottom or next_pos.y < screen_r.top:
                self.direction.y *= -1

            # move after applying reflection
            next_pos = self.pos + self.direction * dt

        # set the new position
        self.pos = next_pos
        self.rect.center = self.pos

def main():
    pygame.init()
    screen = pygame.display.set_mode((500, 500))
    tank = Player()
    sprites = pygame.sprite.Group()
    sprites.add(tank)
    #print(tank.groups()[0])
    clock = pygame.time.Clock()
    dt = 0
    running = True
    while running:
        #print(tank.groups()[0])
        events = pygame.event.get()
        for e in events:
            if e.type == pygame.QUIT:
                return
        sprites.update(events, dt)
        screen.fill((30, 30, 30))
        sprites.draw(screen)
        pygame.display.update()

        ## ALWAYS DETECTS A COLLISION, WHY?
        if len(tank.groups()[0])>1:
            if pygame.sprite.spritecollideany(tank, tank.groups()[0]):
                running = False

        dt = clock.tick(60)

if __name__ == '__main__':
    main()

我在这里收集到 Player 类(即我的坦克)本身有一个精灵组,它在发射时将每个射弹添加到其中。此外,射弹来自多边形的矩形内(因此它总是最初碰撞)

我只想将至少 1 次反弹的弹丸添加到精灵组中,这可能吗?或者...有更好的方法吗?

有什么帮助或指点吗?

谢谢 空

【问题讨论】:

    标签: python pygame


    【解决方案1】:

    tank 与自身发生碰撞,因为它是tank.groups()[0] 的成员:

    if pygame.sprite.spritecollideany(tank, tank.groups()[0]):
    

    添加一个只包含项目符号的

    class Player(pygame.sprite.Sprite):
        def __init__(self):
            # [...]
    
            self.bullets = pygame.sprite.Group()
    
        def update(self, events, dt):
    
            for e in events:
                if e.type == pygame.KEYDOWN:
                    if e.key == pygame.K_SPACE:
                        bullet = Projectile(self.fire_from, self.direction.normalize())
                        self.groups()[0].add(bullet)
                        self.bullets.add(bullet)
    
            # [...]
    

    使用此进行碰撞测试:

    def main():
        # [...]
    
        while running:
            # [...]
    
            pygame.display.update()
    
            if pygame.sprite.spritecollideany(tank, tank.bullets):
                running = False
    
            dt = clock.tick(60)
    

    【讨论】:

    • 非常感谢,我之前也尝试过这样做,但一直对不同的精灵组感到困惑!但这是有道理的,Player 类拥有自己的一组精灵(即发射的子弹)。但问题是,为什么我们在播放器类中需要两个精灵组?
    • @NullPointer 你不需要它们。但是,您想通过 1 次调用 (sprites.draw(screen)) 绘制所有精灵。
    • 好的,有道理,谢谢Rabbid,我想我已经掌握了这个窍门,非常感谢!
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-01-16
    • 1970-01-01
    • 1970-01-01
    • 2016-06-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多