如何在 Pygame 中获得 coordinates/area 的碰撞

How to get coordinates/area of collision in Pygame

我有一个游戏,子弹移动得如此之快以至于在一帧中它已经穿过了屏幕。话虽这么说,它已经撞上了多堵墙。目前,我有一个矩形图像,它从当前子弹所在的位置跨越到下一帧中子弹所在的位置,以免错过可能介于两者之间的任何僵尸。

如果子弹撞到任何墙壁,我也会杀死它,然后再检查它是否与任何僵尸相撞,因为发生的事情是,如果墙后面有一个僵尸,我首先检查僵尸碰撞,它会先杀僵尸再杀子弹

所以基本上,我想知道一种方法来找到子弹与墙壁碰撞的坐标,这样我就不会全速前进子弹,而是将它前进到碰撞之前的位置就是,检查僵尸碰撞,然后杀子弹。

我正在使用遮罩碰撞。

不幸的是,PyGame 没有为我们提供返回碰撞点的内置方法,因此需要做一些简单的工作。

但是,在我解释之前,你在问题中提到子弹移动得非常快。我不确定我们说话的速度有多快,所以这可能不适用,但根据我的经验,碰撞会在高速时碰碰运气,尤其是当你在一台速度较慢的计算机上工作时。

假设 ^ 不适用:

我们可以使用 pygame.Rect.colliderect 来触发 if 语句。

if <bullet-rect>.collidepoint(<wall-rect>):
  print(bullet_x, bullet_y)

只需将 和 换成实际的矩形,您就可以开始了。需要注意的一件事是,如果项目符号从右向左移动,则必须将项目符号的宽度添加到 x 值,如果项目符号从上到下移动,则必须将项目符号的高度添加到 y 值.

注意:请记住为每个值添加 pygame.Rect(<bullet-rect>)pygame.Rect(<wall-rect>),否则您将收到 错误

如果子弹行进得太快而无法与墙壁或敌人发生碰撞,您需要射线投射(或者分多个小步移动子弹)。这是一个简单的光线投射示例,returns 最近的碰撞点。我使用 vectors and pygame.Rect.collidepoint 查看 heading 向量上的点是否与障碍物碰撞。

import sys
import pygame as pg
from pygame.math import Vector2


class Wall(pg.sprite.Sprite):

    def __init__(self, x, y, w, h, *groups):
        super().__init__(*groups)
        self.image = pg.Surface((w, h))
        self.image.fill(pg.Color('goldenrod4'))
        self.rect = self.image.get_rect(topleft=(x, y))


def ray_cast(origin, target, obstacles):
    """Calculate the closest collision point.

    Adds the normalized `direction` vector to the `current_pos` to
    move along the heading vector and uses `pygame.Rect.collidepoint`
    to see if `current_pos` collides with an obstacle.

    Args:
        origin (pygame.math.Vector2, tuple, list): Origin of the ray.
        target (pygame.math.Vector2, tuple, list): Endpoint of the ray.
        obstacles (pygame.sprite.Group): A group of obstacles.

    Returns:
        pygame.math.Vector2: Closest collision point or target.
    """
    current_pos = Vector2(origin)
    heading = target - origin
    # A normalized vector that points to the target.
    direction = heading.normalize()
    for _ in range(int(heading.length())):
        current_pos += direction
        for sprite in obstacles:
            # If the current_pos collides with an
            # obstacle, return it.
            if sprite.rect.collidepoint(current_pos):
                return current_pos
    # Otherwise return the target.
    return Vector2(target)


def main():
    screen = pg.display.set_mode((640, 480))
    clock = pg.time.Clock()
    all_sprites = pg.sprite.Group()
    walls = pg.sprite.Group()
    Wall(100, 170, 90, 20, all_sprites, walls)
    Wall(200, 100, 20, 140, all_sprites, walls)
    Wall(400, 60, 150, 100, all_sprites, walls)

    pos = Vector2(320, 440)
    done = False

    while not done:
        for event in pg.event.get():
            if event.type == pg.QUIT:
                done = True

        all_sprites.update()
        collision_point = ray_cast(pos, pg.mouse.get_pos(), walls)
        screen.fill((30, 30, 30))
        all_sprites.draw(screen)
        pg.draw.line(screen, (50, 190, 100), pos, pg.mouse.get_pos(), 2)
        pg.draw.circle(screen, (40, 180, 250), [int(x) for x in collision_point], 5)

        pg.display.flip()
        clock.tick(30)


if __name__ == '__main__':
    pg.init()
    main()
    pg.quit()
    sys.exit()