如何在 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()
我有一个游戏,子弹移动得如此之快以至于在一帧中它已经穿过了屏幕。话虽这么说,它已经撞上了多堵墙。目前,我有一个矩形图像,它从当前子弹所在的位置跨越到下一帧中子弹所在的位置,以免错过可能介于两者之间的任何僵尸。
如果子弹撞到任何墙壁,我也会杀死它,然后再检查它是否与任何僵尸相撞,因为发生的事情是,如果墙后面有一个僵尸,我首先检查僵尸碰撞,它会先杀僵尸再杀子弹
所以基本上,我想知道一种方法来找到子弹与墙壁碰撞的坐标,这样我就不会全速前进子弹,而是将它前进到碰撞之前的位置就是,检查僵尸碰撞,然后杀子弹。
我正在使用遮罩碰撞。
不幸的是,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()