问题描述
所以我试图用pygame做一个我们当中的游戏。我刚开始,所以我什么都没有,并且现在正在地图上工作。但是,我正在努力解决的一件事是冲突逻辑。该地图目前具有细长的八边形形状,但是我认为无论形状如何,我都会使用pygame多边形之类的东西。当我运行代码时,它会检查玩家(pygame矩形)和墙壁(pygame多边形)之间是否发生碰撞,它说:
TypeError: Argument must be rect style object
我发现这是因为pygame多边形返回了一个矩形,但在碰撞检查器中并未以这种方式进行分类。我尝试了一个名为collision的库,并为碰撞检测付出了巨大的努力,但该播放器仍然能够在墙壁上发生故障。旁注:如果有人想看一下我的代码,我会将代码保存在使用该库的地方,也许可以改善我的错误。
无论如何,将其煮沸:
我需要一种检测多边形和矩形之间的碰撞的方法(真的,最好是在pygame中)
感谢您提供的任何帮助,如果您有任何疑问,请发表评论。
这里是我的代码:
import pygame
pygame.init()
W,H=500,500
screen = pygame.display.set_mode([500,500])
running = True
bcg=(200,200,200)
red=(255,0)
purp=(255,255)
wall=(100,100,100)
class player:
def bg(self):
screen.fill(bcg)
x,y=self.x,self.y
self.outer=(
(x,y),(x+800,(x+1200,y+200),y+600),y+800),(x,(x-400,y+50),(x-350,y+225),y+575),y+750),(x+1150,y+50)
)
pygame.draw.polygon(screen,wall,self.outer)
def __init__(self,color,size=20,speed=0.25):
self.x=0
self.y=0
self.col=color
self.size=size
self.speed=speed
def draw(self):
s=self.size
self.rect=pygame.Rect(W/2-s/2,H/2-s/2,self.size,self.size)
pygame.draw.rect(screen,self.col,self.rect)
def move(self,x,y):
x*=self.speed
y*=self.speed
if not self.rect.colliderect(self.outer):
self.x+=x
self.y+=y
p=player(red)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
p.bg()
keys=pygame.key.get_pressed()
if keys[pygame.K_a]: p.move(1,0)
if keys[pygame.K_d]: p.move(-1,0)
if keys[pygame.K_w]: p.move(0,1)
if keys[pygame.K_s]: p.move(0,-1)
p.draw()
pygame.display.update()
pygame.quit()
解决方法
编写一个函数collideLineLine
,以测试线段是否相交。问题pygame,detecting collision of a rotating rectangle的答案中详细说明了此功能的算法:
def collideLineLine(l1_p1,l1_p2,l2_p1,l2_p2):
# normalized direction of the lines and start of the lines
P = pygame.math.Vector2(*l1_p1)
line1_vec = pygame.math.Vector2(*l1_p2) - P
R = line1_vec.normalize()
Q = pygame.math.Vector2(*l2_p1)
line2_vec = pygame.math.Vector2(*l2_p2) - Q
S = line2_vec.normalize()
# normal vectors to the lines
RNV = pygame.math.Vector2(R[1],-R[0])
SNV = pygame.math.Vector2(S[1],-S[0])
RdotSVN = R.dot(SNV)
if RdotSVN == 0:
return False
# distance to the intersection point
QP = Q - P
t = QP.dot(SNV) / RdotSVN
u = QP.dot(RNV) / RdotSVN
return t > 0 and u > 0 and t*t < line1_vec.magnitude_squared() and u*u < line2_vec.magnitude_squared()
编写函数colideRectLine
,以测试矩形和线段是否相交。要测试线段是否与矩形相交,您必须测试线段是否与矩形的4个边相交:
def colideRectLine(rect,p1,p2):
return (collideLineLine(p1,p2,rect.topleft,rect.bottomleft) or
collideLineLine(p1,rect.bottomleft,rect.bottomright) or
collideLineLine(p1,rect.bottomright,rect.topright) or
collideLineLine(p1,rect.topright,rect.topleft))
下一个函数collideRectPolygon
测试多边形和矩形是否相交。这可以通过在循环中针对矩形测试多边形上的每个线段来实现:
def collideRectPolygon(rect,polygon):
for i in range(len(polygon)-1):
if colideRectLine(rect,polygon[i],polygon[i+1]):
return True
return False
最后,您可以使用collideRectPolygon
进行碰撞测试。但是请注意,在测试中,您需要像玩家正在移动一样使用多边形:
class player:
def bg(self):
screen.fill(bcg)
self.outer = self.createPolygon(self.x,self.y)
pygame.draw.polygon(screen,wall,self.outer)
def createPolygon(self,x,y):
return [
(x,y),(x+800,(x+1200,y+200),y+600),y+800),(x,(x-400,y+50),(x-350,y+225),y+575),y+750),(x+1150,y+50)]
# [...]
def move(self,y):
x *= self.speed
y *= self.speed
polygon = self.createPolygon(self.x + x,self.y + y)
if not collideRectPolygon(self.rect,polygon):
self.x += x
self.y += y
完整示例:
import pygame
pygame.init()
W,H=500,500
screen = pygame.display.set_mode([500,500])
running = True
bcg=(200,200,200)
red=(255,0)
purp=(255,255)
wall=(100,100,100)
def collideLineLine(l1_p1,-S[0])
RdotSVN = R.dot(SNV)
if RdotSVN == 0:
return False
# distance to the intersection point
QP = Q - P
t = QP.dot(SNV) / RdotSVN
u = QP.dot(RNV) / RdotSVN
return t > 0 and u > 0 and t*t < line1_vec.magnitude_squared() and u*u < line2_vec.magnitude_squared()
def colideRectLine(rect,rect.topleft))
def collideRectPolygon(rect,polygon[i+1]):
return True
return False
class player:
def bg(self):
screen.fill(bcg)
self.outer = self.createPolygon(self.x,y+50)]
def __init__(self,color,size=20,speed=0.25):
self.x=0
self.y=0
self.col=color
self.size=size
self.speed=speed
def draw(self):
s=self.size
self.rect=pygame.Rect(W/2-s/2,H/2-s/2,self.size,self.size)
pygame.draw.rect(screen,self.col,self.rect)
def move(self,polygon):
self.x += x
self.y += y
p=player(red)
while running:
for event in pygame.event.get():
if event.type == pygame.QUIT:
running = False
p.bg()
keys=pygame.key.get_pressed()
if keys[pygame.K_a]: p.move(1,0)
if keys[pygame.K_d]: p.move(-1,0)
if keys[pygame.K_w]: p.move(0,1)
if keys[pygame.K_s]: p.move(0,-1)
p.draw()
pygame.display.update()
pygame.quit()