为什么 class 碰撞在 PyGame 中不起作用?
Why is class collision not working in PyGame?
我正在制作一款向雪人扔雪球的游戏。以下是 Snowman
class 和 Snowball
class 的定义:
class Snowman:
def __init__(self,start,end,a,b):
self.x = random.randrange(0,310)
self.y = 0
self.r = pygame.Rect(self.x,self.y,a,b)
class Snowball:
def __init__(self,a,b):
self.x = mousex
self.y = mousey
self.r = pygame.Rect(self.x,self.y,a,b)
如您所见,classes 的 r
属性是它们的矩形。
下面是一个控制雪人AI的脚本。
for s in snowmen:
s.y += 0.5
#above_makes_the_snowmen_approach_the_bottom_of_the_screen.
#below_is_supposed_to_check_for_snowball_collision.
for b in bullets:
if s.r.colliderect(b.r):
snowmen.remove(s)
bullets.remove(b)
print(b.r.colliderect(s.r))
#above_is_a_debugger_that_reports_the_collision.
if s.y < 640:
blit(asnowman,(50,78),(s.x,s.y))
else:
snowmen.remove(s)
问题是当我向其中一个雪人扔雪球时,调试器报告 False
并且雪人没有死。我该如何解决这个问题?
参见 How do I detect collision in pygame?。您需要在碰撞测试之前更新矩形的位置:
s.r.topleft = round(s.x), round(s.y)
b.r.topleft = round(b.x), round(b.y)
if s.r.colliderect(b.r):
请注意,您不能去掉 x
和 y
属性,因为 pygame.Rect
应该代表屏幕上的一个区域,而 pygame.Rect
对象可以只存储积分数据。
The coordinates for Rect objects are all integers. [...]
另请阅读How to remove items from a list while iterating?。一种可能的解决方案是遍历列表的副本:
for s in snowmen[:]:
s.y += 0.5
s.r.topleft = round(s.x), round(s.y)
for b in bullets[:]:
b.r.topleft = round(b.x), round(b.y)
if s.r.colliderect(b.r):
snowmen.remove(s)
bullets.remove(b)
break
虽然您在每个 类 中初始化 Rect
对象以匹配创建对象时的 x
和 y
属性,但它们不会保留在同步。这意味着您只会在矩形 的初始位置 碰撞矩形,而不是物体后来移动到的位置。
解决这个问题的最简单方法可能是添加几行代码来更新 s.r
and/or b.r
,但您也可以开始使用 pygame.sprite.Sprite
,这将更新其 rect
属性以匹配其 x
和 y
属性(我认为反之亦然)。如果你想让自己的 类 表现得有点像 Sprite
而不是一路走下去,我建议将 x
和 y
变成 property
描述符,它引用 Rect
,它成为唯一的真实来源:
class Snowman:
def __init__(self,start,end,a,b):
self.r = pygame.Rect(random.randrange(0,310),0,a,b)
@property
def x(self):
return self.r.left
@x.setter
def x(self, value):
self.r.left = value
@property
def y(self):
return self.r.top
@y.setter
def y(self, value):
self.r.top = value
我正在制作一款向雪人扔雪球的游戏。以下是 Snowman
class 和 Snowball
class 的定义:
class Snowman:
def __init__(self,start,end,a,b):
self.x = random.randrange(0,310)
self.y = 0
self.r = pygame.Rect(self.x,self.y,a,b)
class Snowball:
def __init__(self,a,b):
self.x = mousex
self.y = mousey
self.r = pygame.Rect(self.x,self.y,a,b)
如您所见,classes 的 r
属性是它们的矩形。
下面是一个控制雪人AI的脚本。
for s in snowmen:
s.y += 0.5
#above_makes_the_snowmen_approach_the_bottom_of_the_screen.
#below_is_supposed_to_check_for_snowball_collision.
for b in bullets:
if s.r.colliderect(b.r):
snowmen.remove(s)
bullets.remove(b)
print(b.r.colliderect(s.r))
#above_is_a_debugger_that_reports_the_collision.
if s.y < 640:
blit(asnowman,(50,78),(s.x,s.y))
else:
snowmen.remove(s)
问题是当我向其中一个雪人扔雪球时,调试器报告 False
并且雪人没有死。我该如何解决这个问题?
参见 How do I detect collision in pygame?。您需要在碰撞测试之前更新矩形的位置:
s.r.topleft = round(s.x), round(s.y)
b.r.topleft = round(b.x), round(b.y)
if s.r.colliderect(b.r):
请注意,您不能去掉 x
和 y
属性,因为 pygame.Rect
应该代表屏幕上的一个区域,而 pygame.Rect
对象可以只存储积分数据。
The coordinates for Rect objects are all integers. [...]
另请阅读How to remove items from a list while iterating?。一种可能的解决方案是遍历列表的副本:
for s in snowmen[:]:
s.y += 0.5
s.r.topleft = round(s.x), round(s.y)
for b in bullets[:]:
b.r.topleft = round(b.x), round(b.y)
if s.r.colliderect(b.r):
snowmen.remove(s)
bullets.remove(b)
break
虽然您在每个 类 中初始化 Rect
对象以匹配创建对象时的 x
和 y
属性,但它们不会保留在同步。这意味着您只会在矩形 的初始位置 碰撞矩形,而不是物体后来移动到的位置。
解决这个问题的最简单方法可能是添加几行代码来更新 s.r
and/or b.r
,但您也可以开始使用 pygame.sprite.Sprite
,这将更新其 rect
属性以匹配其 x
和 y
属性(我认为反之亦然)。如果你想让自己的 类 表现得有点像 Sprite
而不是一路走下去,我建议将 x
和 y
变成 property
描述符,它引用 Rect
,它成为唯一的真实来源:
class Snowman:
def __init__(self,start,end,a,b):
self.r = pygame.Rect(random.randrange(0,310),0,a,b)
@property
def x(self):
return self.r.left
@x.setter
def x(self, value):
self.r.left = value
@property
def y(self):
return self.r.top
@y.setter
def y(self, value):
self.r.top = value