nch*_*pmn 7 python pygame physics collision-detection
我正在制作一个游戏,其中球在一个更大的圆圈内部反弹.较大的圆圈不会移动.
这是我目前用于这些冲突的代码:
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)
Run Code Online (Sandbox Code Playgroud)
它基于Peter Collingridge 在这里的精彩教程.
圆和球对象都是类,具有(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
Run Code Online (Sandbox Code Playgroud)
内森先生,谢谢你
Gar*_*ees 13
如果不回答您的问题,我想评论您的实施策略并推荐一种新方法.你用极坐标形式表示球的速度,ball.angle和ball.speed.
我认为这对你来说通常很不方便.例如,在碰撞代码中,您最终调用atan2将矢量(dx,dy)转换为角度,然后调用sin并cos再次将角度转换回矢量.(另外,如果你试图将你的代码概括为三维,你会发现自己处于一个痛苦的世界.)所以,除非你有特殊的要求需要极坐标,我建议你做其他人做的事,即代表笛卡尔坐标系中球的速度为矢量(vx,vy).
我还建议将物理方法从静态方法("当前与对象B碰撞的对象A?")更改为动态方法("将对象A在下一个移动步骤中与对象B碰撞?").在静态物理系统中,在运动步骤结束时,您经常会遇到彼此相交的物体,然后您必须找出让它们再次分离的最佳方法,这很难做到.
如果你同时进行这两项操作,那么在没有任何三角测量的情况下直接弹球是很简单的.
步骤1.使用Minkowski添加将圆/圆碰撞转换为点/圆碰撞:

步骤2.考虑一个时间段,其中球在p =(px,py)处开始并且移动v =(vx,vy).它与圆相交吗?除此之外,您可以使用标准线段/圆测试,但测试的意义相反.
步骤3.找到碰撞点c =(cx,cy).球以与在该点处与圆相切的线t反弹的方式反弹离开圆圈.对于以原点为中心的圆,切线向量只是(-cy,cx),我相信你可以弄清楚如何为其他圆计算它.

请参阅此答案,了解如何根据摩擦系数和恢复系数计算球的新路径.
步骤4.不要忘记球可能仍然有一些距离沿着新的向量w移动.如果时间步长足够大或速度足够高,则可能在同一时间段内再次发生碰撞.
Pet*_*dge 12
我很高兴你喜欢我的教程.我喜欢你的变化,它实际上应该更简单.
首先,我认为您需要将碰撞测试更改为:
if distance >= circle.size - ball.size:
Run Code Online (Sandbox Code Playgroud)
因为球的尺寸越大,其中心与圆心之间的距离就越小.这应该使球在正确的位置(圆圈内)弹跳.
然后我认为你只需要交换x和y的标志,一切都应该有效.
ball.x += math.sin(angle)
ball.y -= math.cos(angle)
Run Code Online (Sandbox Code Playgroud)
要将球移动正确的距离,您可以计算重叠:
overlap = math.hypot(dx, dy) - (circle.size - ball.size)
if overlap >= 0:
tangent = math.atan2(dy, dx)
ball.angle = 2 * tangent - ball.angle
ball.speed *= elasticity
angle = 0.5 * math.pi + tangent
ball.x += math.sin(angle)*overlap
ball.y -= math.cos(angle)*overlap
Run Code Online (Sandbox Code Playgroud)
祝好运
| 归档时间: |
|
| 查看次数: |
7924 次 |
| 最近记录: |