我有一个游戏,其子弹移动得如此之快,以至于它已经在一个帧中穿过屏幕。话虽如此,它已经与多个墙相撞。目前,我有一个矩形图像,从子弹当前所在的位置,到子弹将在下一帧中的位置,以便不会错过任何可能在其间的僵尸。
如果它与任何一个墙碰撞,我也会杀死子弹,然后检查它是否与任何僵尸相撞,因为发生的事情是如果墙后面有一个僵尸并且我先检查了僵尸碰撞,它会杀死它僵尸,然后杀死子弹。
所以基本上,我想知道一种找到子弹与墙碰撞的坐标的方法,这样我就可以将它推进到碰撞前的位置,而不是以全速推进子弹。检查僵尸碰撞,然后杀死子弹。
我正在使用蒙版碰撞。
答案 0 :(得分:2)
如果子弹行进得太快而无法与墙壁或敌人发生碰撞,则需要光线投射(或者以多个小步骤移动子弹)。这是一个简单的光线投射示例,它返回最近的碰撞点。我使用vectors和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()
答案 1 :(得分:0)
不幸的是PyGame
并没有给我们一个内置的方法来返回碰撞点,这很容易做到这一点,所以有一些腿部工作要做。
然而,在我解释之前,你在问题中提到子弹移动得非常快。我不确定我们说话的速度有多快,所以这可能不适用,但在我的经验中,碰撞会在高速下成为热门,特别是如果你在较慢的电脑上工作。
假设^
不适用:
我们可以使用pygame.Rect.colliderect来触发if语句。
if <bullet-rect>.collidepoint(<wall-rect>):
print(bullet_x, bullet_y)
简单地换掉实际的作品,你应该好好去。需要注意的一点是,如果子弹从右向左移动,则必须将子弹的宽度添加到x值,如果子弹从上到下移动,则必须添加子弹&# 39; s高度为y值。
注意:请务必在每个值中添加pygame.Rect(<bullet-rect>)
和pygame.Rect(<wall-rect>)
,否则您将收到错误。