如何在 pygame 中检测碰撞?

2024-11-19 08:39:00
admin
原创
13
摘要:问题描述:我使用下面的类创建了一个子弹列表和一个精灵列表。如何检测子弹是否与精灵发生碰撞,然后删除该精灵和子弹?#Define the sprite class class Sprite: def __init__(self,x,y, name): self.x=x ...

问题描述:

我使用下面的类创建了一个子弹列表和一个精灵列表。如何检测子弹是否与精灵发生碰撞,然后删除该精灵和子弹?

#Define the sprite class
class Sprite:

    def __init__(self,x,y, name):
        self.x=x

        self.y=y

        self.image = pygame.image.load(name)

        self.rect = self.image.get_rect()

    def render(self):
        window.blit(self.image, (self.x,self.y))


# Define the bullet class to create bullets          
class Bullet:

    def __init__(self,x,y):
        self.x = x + 23
        self.y = y
        self.bullet = pygame.image.load("user_bullet.BMP")
        self.rect = self.bullet.get_rect()

    def render(self):
        window.blit(self.bullet, (self.x, self.y))

解决方案 1:

在 PyGame 中,碰撞检测是使用pygame.Rect对象完成的。Rect对象提供了各种检测对象之间碰撞的方法。即使是矩形和圆形物体(例如桨和球)之间的碰撞也可以通过两个矩形物体(桨和球的边界矩形)之间的碰撞来检测。

一些例子:

  • pygame.Rect.collidepoint

测试某个点是否位于矩形内

![IT科技](https://i.sstatic.net/5jD0C.png) repl.it/@Rabbid76/PyGame-collidepoint

IT科技

import pygame

pygame.init()
window = pygame.display.set_mode((250, 250))
rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(100, 100)

run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    point = pygame.mouse.get_pos()
    collide = rect.collidepoint(point)
    color = (255, 0, 0) if collide else (255, 255, 255)

    window.fill(0)
    pygame.draw.rect(window, color, rect)
    pygame.display.flip()

pygame.quit()
exit()
  • pygame.Rect.colliderect

测试两个矩形是否重叠

另请参阅如何在 pygame 中检测两个矩形物体或图像之间的碰撞

![IT科技](https://i.sstatic.net/5jD0C.png) repl.it/@Rabbid76/PyGame-colliderect

碰撞

import pygame

pygame.init()
window = pygame.display.set_mode((250, 250))
rect1 = pygame.Rect(*window.get_rect().center, 0, 0).inflate(75, 75)
rect2 = pygame.Rect(0, 0, 75, 75)

run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    rect2.center = pygame.mouse.get_pos()
    collide = rect1.colliderect(rect2)
    color = (255, 0, 0) if collide else (255, 255, 255)

    window.fill(0)
    pygame.draw.rect(window, color, rect1)
    pygame.draw.rect(window, (0, 255, 0), rect2, 6, 1)
    pygame.display.flip()

pygame.quit()
exit()

此外,pygame.Rect.collidelistpygame.Rect.collidelistall可用于矩形与矩形列表之间的碰撞测试。pygame.Rect.collidedictpygame.Rect.collidedictall可用于矩形与矩形字典之间的碰撞测试。

pygame.sprite.Sprite和物体的碰撞可以通过、或 来pygame.sprite.Group检测。使用这些方法时,碰撞检测算法可以通过参数指定:pygame.sprite.spritecollide()`pygame.sprite.groupcollide()pygame.sprite.spritecollideany()collided`

collided 参数是一个回调函数,用于计算两个精灵是否发生碰撞。

可能的collided调用包括collide_rect, collide_rect_ratio, collide_circle, collide_circle_ratio,collide_mask

一些例子:

  • pygame.sprite.spritecollide()

![IT科技](https://i.sstatic.net/5jD0C.png) repl.it/@Rabbid76/PyGame-spritecollide

IT科技

import pygame

pygame.init()
window = pygame.display.set_mode((250, 250))

sprite1 = pygame.sprite.Sprite()
sprite1.image = pygame.Surface((75, 75))
sprite1.image.fill((255, 0, 0))
sprite1.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(75, 75)
sprite2 = pygame.sprite.Sprite()
sprite2.image = pygame.Surface((75, 75))
sprite2.image.fill((0, 255, 0))
sprite2.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(75, 75)

all_group = pygame.sprite.Group([sprite2, sprite1])
test_group = pygame.sprite.Group(sprite2)

run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    sprite1.rect.center = pygame.mouse.get_pos()
    collide = pygame.sprite.spritecollide(sprite1, test_group, False)

    window.fill(0)
    all_group.draw(window)
    for s in collide:
        pygame.draw.rect(window, (255, 255, 255), s.rect, 5, 1)
    pygame.display.flip()

pygame.quit()
exit()

对于与遮罩的碰撞,请参阅如何制作碰撞遮罩?或Pygame 遮罩碰撞

另请参阅碰撞和交叉

  • pygame.sprite.spritecollide()/collide_circle

![IT科技](https://i.sstatic.net/5jD0C.png) repl.it/@Rabbid76/PyGame-spritecollidecollidecircle

IT科技

import pygame

pygame.init()
window = pygame.display.set_mode((250, 250))

sprite1 = pygame.sprite.Sprite()
sprite1.image = pygame.Surface((80, 80), pygame.SRCALPHA)
pygame.draw.circle(sprite1.image, (255, 0, 0), (40, 40), 40)
sprite1.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(80, 80)
sprite1.radius = 40
sprite2 = pygame.sprite.Sprite()
sprite2.image = pygame.Surface((80, 89), pygame.SRCALPHA)
pygame.draw.circle(sprite2.image, (0, 255, 0), (40, 40), 40)
sprite2.rect = pygame.Rect(*window.get_rect().center, 0, 0).inflate(80, 80)
sprite2.radius = 40 

all_group = pygame.sprite.Group([sprite2, sprite1])
test_group = pygame.sprite.Group(sprite2)

run = True
while run:
    for event in pygame.event.get():
        if event.type == pygame.QUIT:
            run = False

    sprite1.rect.center = pygame.mouse.get_pos()
    collide = pygame.sprite.spritecollide(sprite1, test_group, False, pygame.sprite.collide_circle)

    window.fill(0)
    all_group.draw(window)
    for s in collide:
        pygame.draw.circle(window, (255, 255, 255), s.rect.center, s.rect.width // 2, 5)
    pygame.display.flip()

pygame.quit()
exit()

这对你的代码意味着什么?

pygame.Surface.get_rect.get_rect()返回一个与Surface对象大小相同的矩形,由于Surface对象没有位置,因此该矩形始终从 (0, 0) 开始。矩形的位置可以通过关键字参数指定。例如,可以使用关键字参数指定矩形的中心。这些关键字参数在返回之前center应用于的属性(请参阅关键字参数列表)。
请参阅 *为什么我的碰撞测试总是返回“true”,为什么图像矩形的位置总是错误的 (0, 0)?pygame.Rect`pygame.Rect`

您根本不需要and的x和属性。请改用属性的位置:y`SpriteBulletrect`

#Define the sprite class
class Sprite:
    def __init__(self, x, y, name):
        self.image = pygame.image.load(name)
        self.rect = self.image.get_rect(topleft = (x, y))

    def render(self):
        window.blit(self.image, self.rect)

# Define the bullet class to create bullets          
class Bullet:
    def __init__(self, x, y):
        self.bullet = pygame.image.load("user_bullet.BMP")
        self.rect = self.bullet.get_rect(topleft = (x + 23, y))

    def render(self):
        window.blit(self.bullet, self.rect)

用于检测和pygame.Rect.colliderect()实例之间的碰撞。
请参阅如何在 pygame 中检测两个矩形物体或图像之间的碰撞:Sprite Bullet

my_sprite = Sprite(sx, sy, name)
my_bullet = Bullet(by, by)
while True:
    # [...]

    if my_sprite.rect.colliderect(my_bullet.rect):
        printe("hit")

解决方案 2:

据我对 pygame 的了解,您只需要使用该colliderect方法检查两个矩形是否重叠。一种方法是在您的Bullet类中使用一个方法来检查碰撞:

def is_collided_with(self, sprite):
    return self.rect.colliderect(sprite.rect)

然后你可以像这样调用它:

sprite = Sprite(10, 10, 'my_sprite')
bullet = Bullet(20, 10)
if bullet.is_collided_with(sprite):
    print('collision!')
    bullet.kill()
    sprite.kill()

解决方案 3:

有一个非常简单的方法可以用于您尝试使用内置方法执行的操作。

这是一个例子。

import pygame
import sys

class Sprite(pygame.sprite.Sprite):
    def __init__(self, pos):
        pygame.sprite.Sprite.__init__(self)
        self.image = pygame.Surface([20, 20])
        self.image.fill((255, 0, 0))
        self.rect = self.image.get_rect()

        self.rect.center = pos

def main():
    pygame.init()
    clock = pygame.time.Clock()
    fps = 50
    bg = [255, 255, 255]
    size =[200, 200]


    screen = pygame.display.set_mode(size)

    player = Sprite([40, 50])
    player.move = [pygame.K_LEFT, pygame.K_RIGHT, pygame.K_UP, pygame.K_DOWN]
    player.vx = 5
    player.vy = 5


    wall = Sprite([100, 60])

    wall_group = pygame.sprite.Group()
    wall_group.add(wall)

    player_group = pygame.sprite.Group()
    player_group.add(player)

    # I added loop for a better exit from the game
    loop = 1
    while loop:
        for event in pygame.event.get():
            if event.type == pygame.QUIT:
                loop = 0

        key = pygame.key.get_pressed()

        for i in range(2):
            if key[player.move[i]]:
                player.rect.x += player.vx * [-1, 1][i]

        for i in range(2):
            if key[player.move[2:4][i]]:
                player.rect.y += player.vy * [-1, 1][i]

        screen.fill(bg)

        # first parameter takes a single sprite
        # second parameter takes sprite groups
        # third parameter is a do kill command if true
        # all group objects colliding with the first parameter object will be
        # destroyed. The first parameter could be bullets and the second one
        # targets although the bullet is not destroyed but can be done with
        # simple trick bellow
        hit = pygame.sprite.spritecollide(player, wall_group, True)

        if hit:
            # if collision is detected call a function in your case destroy
            # bullet
            player.image.fill((255, 255, 255))

        player_group.draw(screen)
        wall_group.draw(screen)

        pygame.display.update()
        clock.tick(fps)

    pygame.quit()
    # sys.exit


if __name__ == '__main__':
    main()

解决方案 4:

为项目符号创建一个组,然后将项目符号添加到该组中。

我会这样做:在玩家课堂上:

def collideWithBullet(self):
    if pygame.sprite.spritecollideany(self, 'groupName'):
        print("CollideWithBullet!!")
        return True

在主循环中的某处:

def run(self):
    if self.player.collideWithBullet():
         print("Game Over")

希望这对你有用!

解决方案 5:

在 Sprite 类中,尝试使用以下代码在 Sprite 类中添加一个self.mask属性

self.mask = pygame.mask.from_surface(self.image)

和一个函数:collide_mask

    def collide_mask(self, mask):
        collided = False
        mask_outline = mask.outline()
        self.mask_outline = self.mask.outline()
        for point in range(len(mask_outline)):
            mask_outline[point] = list(mask_outline[point])
            mask_outline[point][0] += bullet.x
            mask_outline[point][1] += bullet.y
        for point in range(len(self.mask_outline)):
            self.mask_outline[point] = list(mask_outline[point])
            self.mask_outline[point][0] += self.x
            self.mask_outline[point][1] += self.y
        for point in mask_outline:
            for self_mask_point in self.mask_outline:
                if point = self_mask_point:
                    collided = True
        return collided
相关推荐
  为什么项目管理通常仍然耗时且低效?您是否还在反复更新电子表格、淹没在便利贴中并参加每周更新会议?这确实是耗费时间和精力。借助软件工具的帮助,您可以一目了然地全面了解您的项目。如今,国内外有足够多优秀的项目管理软件可以帮助您掌控每个项目。什么是项目管理软件?项目管理软件是广泛行业用于项目规划、资源分配和调度的软件。它使项...
项目管理软件   601  
  华为IPD与传统研发模式的8大差异在快速变化的商业环境中,产品研发模式的选择直接决定了企业的市场响应速度和竞争力。华为作为全球领先的通信技术解决方案供应商,其成功在很大程度上得益于对产品研发模式的持续创新。华为引入并深度定制的集成产品开发(IPD)体系,相较于传统的研发模式,展现出了显著的差异和优势。本文将详细探讨华为...
IPD流程是谁发明的   7  
  如何通过IPD流程缩短产品上市时间?在快速变化的市场环境中,产品上市时间成为企业竞争力的关键因素之一。集成产品开发(IPD, Integrated Product Development)作为一种先进的产品研发管理方法,通过其结构化的流程设计和跨部门协作机制,显著缩短了产品上市时间,提高了市场响应速度。本文将深入探讨如...
华为IPD流程   9  
  在项目管理领域,IPD(Integrated Product Development,集成产品开发)流程图是连接创意、设计与市场成功的桥梁。它不仅是一个视觉工具,更是一种战略思维方式的体现,帮助团队高效协同,确保产品按时、按质、按量推向市场。尽管IPD流程图可能初看之下显得错综复杂,但只需掌握几个关键点,你便能轻松驾驭...
IPD开发流程管理   8  
  在项目管理领域,集成产品开发(IPD)流程被视为提升产品上市速度、增强团队协作与创新能力的重要工具。然而,尽管IPD流程拥有诸多优势,其实施过程中仍可能遭遇多种挑战,导致项目失败。本文旨在深入探讨八个常见的IPD流程失败原因,并提出相应的解决方法,以帮助项目管理者规避风险,确保项目成功。缺乏明确的项目目标与战略对齐IP...
IPD流程图   8  
热门文章
项目管理软件有哪些?
云禅道AD
禅道项目管理软件

云端的项目管理软件

尊享禅道项目软件收费版功能

无需维护,随时随地协同办公

内置subversion和git源码管理

每天备份,随时转为私有部署

免费试用