我在做一个游戏,球在一个大得多的圆的内部反弹。大圆圈不动。
下面是我当前用于这些冲突的代码:
def collideCircle(circle, ball):
"""Check for collision between a ball and a circle"""
dx = circle.x - ball.x
dy = circle.y - ball.y
distance = math.hypot(dx, dy)
if distance >= circle.size + ball.size:
# We don't need to change anything about the circle, just the ball
tangent = math.atan2(dy, dx)
ball.angle = 2 * tangent - ball.angle
ball.speed *= elasticity + 0.251
angle = 0.5 * math.pi + tangent
ball.x -= math.sin(angle)
ball.y += math.cos(angle)
它是基于彼得·柯林格里奇的精彩教程over here。
圆和球对象都是类,具有(x,y)、半径、角度和速度。
但是,我对这种方法有两个问题:
在研究了可能的解决方案之后,特别是“快速圆碰撞检测”[由于垃圾邮件链接限制而删除的链接],虽然在Java中使用的是相同的方法,但这些都是处理外部碰撞的,而我正在研究的是将球反弹到圆的内部。
下面是Ball()和Circle()的类定义:
class Ball():
def __init__(self, (x,y), size):
"""Setting up the new instance"""
self.x = x
self.y = y
self.size = size
self.colour = (0,128,255)
self.thickness = 0
self.speed = 0.01
self.angle = math.pi/2
def display(self):
"""Draw the ball"""
pygame.draw.circle(screen, self.colour, (int(self.x), int(self.y)), self.size, self.thickness)
def move(self):
"""Move the ball according to angle and speed"""
self.x += math.sin(self.angle) * self.speed
self.y -= math.cos(self.angle) * self.speed
(self.angle, self.speed) = addVectors((self.angle, self.speed), gravity)
self.speed *= drag
class Circle():
def __init__(self, (x,y), size):
"""Set up the new instance of the Circle class"""
self.x = x
self.y = y
self.size = size
self.colour = (236, 236, 236)
self.thickness = 0
self.angle = 0 # Needed for collision...
self.speed = 0 # detection against balls
def display(self):
"""Draw the circle"""
pygame.draw.circle(screen, self.colour, (int(self.x), int(self.y)), self.size, self.thickness
提前谢谢你,内森
在不回答你的问题的情况下,我想评论一下你的实施策略,并推荐一种新的方法。以极坐标的形式表示球的速度,如
ball.angle
和ball.speed
。我想这对你来说通常是不方便的。例如,在冲突代码中,您最终调用
atan2
将向量(dx
,dy
)转换为角度,然后调用sin
和cos
将角度再次转换为向量。(同样,如果你试图将你的代码推广到三维空间,你会发现自己身处一个痛苦的世界。)所以,除非你有特殊的要求,需要极坐标,我建议你做其他人都做的事情,即用笛卡尔坐标表示球的速度作为矢量(vx
,vy
)。我还建议改变你的物理方法,从静态的方法(“物体a当前是否与物体B发生碰撞?”)到adynamicone(“对象a在下一个移动步骤中是否会与对象B发生碰撞?”)。在静态物理系统中,你经常在一个运动步骤结束时发现物体相互交叉,然后你必须找出使它们再次分离的最佳方法,这是很难做到的。
如果你同时做这两件事,你很容易在没有任何三角学的情况下弹起球。
第一步。使用Minkowski addition将圆/圆碰撞转换为点/圆碰撞:
第二步。考虑一个时间段,在该时间段中,球从p=(px,py)开始并移动v=(vx,vy)。它和圆相交吗?您可以使用standard line segment/circle test来实现这一点,但测试的意义是相反的。
第三步。找到碰撞点c=(cx,cy)。球从圆上反弹的方式与它从与该点的圆相切的线上反弹的方式相同。对于一个以原点为中心的圆,切向量只是(-cy,cx),我相信你可以找出如何计算其他圆的切向量。
如何根据摩擦系数和恢复系数计算球的新路径。
第四步。别忘了,球可能还有一段距离要沿新向量移动。如果时间步长足够大或速度足够高,则可能在同一时间段内再次发生碰撞。
我很高兴你喜欢我的教程。我喜欢你的变化,它实际上应该更简单。
首先,我认为您需要将碰撞测试更改为:
因为球的尺寸越大,它的中心和圆心之间的距离就越小。这将使球在正确的位置(圆内)反弹。
然后我想你只需要换x和y的符号,一切都应该正常。
要按正确的距离移动球,可以计算重叠:
祝你好运
大多数图形包使用左上角作为绘图代码的开始。最有可能需要两组坐标,一组是与之碰撞/移动的坐标,另一组是用于绘制的坐标(x-radius,y-radius)。
另外,在没有考虑太多的情况下,交叉点的检查是否应该是
distance + ball.size >= circle.size
?如果我正确理解设置的话,球与中心的距离加上它的半径应该小于圆的半径。相关问题 更多 >
编程相关推荐