Python 二维球碰撞
Python 2d Ball Collision
这是我收集的:
from graphics import *
from random import *
from math import *</p>
<p>class Ball(Circle):
def <strong>init</strong>(self, win_width, win_high, point, r, vel1, vel2):
Circle.<strong>init</strong>(self, point, r)</p>
<pre><code> self.width = win_width
self.high = win_high
self.vecti1 = vel1
self.vecti2 = vel2
def collide_wall(self):
bound1 = self.getP1()
bound2 = self.getP2()
if (bound2.y >= self.width):
self.vecti2 = -self.vecti2
self.move(0, -1)
if (bound2.x >= self.high):
self.vecti1 = -self.vecti1
self.move(-1, 0)
if (bound1.x <= 0):
self.vecti1 = -self.vecti1
self.move(1, 0)
if (bound2.y <= 0):
self.vecti2 = -self.vecti2
self.move(0, 1)
def ball_collision(self, cir2):
radius = self.getRadius()
radius2 = cir2.getRadius()
bound1 = self.getP1()
bound3 = cir2.getP1()
center1 = Point(radius + bound1.x,radius + bound1.y)
center2 = Point(radius2 + bound3.x,radius2 + bound3.y)
centerx = center2.getX() - center1.getX()
centery = center2.getY() - center1.getY()
distance = sqrt((centerx * centerx) + (centery * centery))
if (distance <= (radius + radius2)):
xdistance = abs(center1.getX() - center2.getX())
ydistance = abs(center1.getY() - center2.getY())
if (xdistance <= ydistance):
if ((self.vecti2 > 0 & bound1.y < bound3.y) | (self.vecti2 < 0 & bound1.y > bound3.y)):
self.vecti2 = -self.vecti2
if ((cir2.vecti2 > 0 & bound3.y < bound1.y) | (cir2.vecti2 < 0 & bound3.y > bound1.y)):
cir2.vecti2 = -cir2.vecti2
elif (xdistance > ydistance):
if ((self.vecti1 > 0 & bound1.x < bound3.x) | (self.vecti1 < 0 & bound1.x > bound3.x)):
self.vecti1 = -self.vecti1
if ((cir2.vecti1 > 0 & bound3.x < bound1.x) | (cir2.vecti1 < 0 & bound3.x > bound1.x)):
cir2.vecti1 = -cir2.vecti1
def main():
win = GraphWin("Ball screensaver", 700,700)
velo1 = 4
velo2 = 3
velo3 = -4
velo4 = -3
cir1 = Ball(win.getWidth(),win.getHeight(),Point(50,50), 20, velo1, velo2)
cir1.setOutline("red")
cir1.setFill("red")
cir1.draw(win)
cir2 = Ball(win.getWidth(),win.getHeight(),Point(200,200), 20, velo3, velo4)
cir2.setOutline("blue")
cir2.setFill("blue")
cir2.draw(win)
while(True):
cir1.move(cir1.vecti1, cir1.vecti2)
cir2.move(cir2.vecti1, cir2.vecti2)
time.sleep(.010)
cir1.collide_wall()
cir2.collide_wall()
cir1.ball_collision(cir2)
#cir2.ball_collision(cir1)
main()
好的,问题来了。这个数学根本不能正常工作。有时它会完美运行,有时一个球会压倒另一个球,或者它们不会像球碰撞那样做出反应。我正在绞尽脑汁想找出问题所在,但我觉得我现在离项目太近了,看不到它。任何帮助将不胜感激。
将您的 "if" 语句修正为合法且直接。我认为您可能想说类似下面的内容。很难说,因为您还没有记录您的代码。
if cir2.vecti2 > 0 and bound3.y > bound1.y:
cir2.vecti2 = -cir2.vecti2
请注意,bound3 没有值。你会发现其他问题,我敢肯定。
我建议您备份并尝试增量编码。首先,尝试让一个球合法地四处移动,从墙上弹起。放入位置的跟踪打印语句,并标记它们,以便您知道您在代码中的位置。
一旦你成功了,然后添加第二个球。继续打印语句,注释掉您认为不再需要的语句。在整个程序运行之前不要删除它们。
这对你有帮助吗?
我查看了这段代码,认为它需要一些帮助。我开始从中获得乐趣,最终使它变得可行、评论和有趣……适用于 python 3.9。我还添加了一个功能,当球碰撞时它们会变成蓝色,视觉效果很棒!
import random
import math
import graphics
class Ball(graphics.Circle):
def __init__(self, width, high, point, radius, velx, vely):
"""a ball is a circle with velocity"""
super().__init__(point, radius)
self.width = width
self.high = high
self.velx = velx
self.vely = vely
def collide_wall(self):
"""find out if this ball collided with any wall"""
ctrpt = self.getCenter()
radius = self.getRadius()
if (ctrpt.x - radius <= 0):
self.velx = -self.velx
if (ctrpt.x + radius >= self.width):
self.velx = -self.velx
if (ctrpt.y - radius <= 0):
self.vely = -self.vely
if (ctrpt.y + radius >= self.high):
self.vely = -self.vely
self.move()
def ball_collision(self, other):
"""find out if this ball collided with 'other' ball"""
radius = self.getRadius()
selfpt = self.getCenter()
otherpt = other.getCenter()
# calculate distances
dx = abs(selfpt.x - otherpt.x)
dy = abs(selfpt.y - otherpt.y)
radius_distance = math.sqrt((dx * dx) + (dy * dy))
# Check to see if the 2 balls are close enough to be in contact
if (radius_distance <= (2*radius)):
# check if changing the sign will increase the x distance
if dx < abs((selfpt.x - self.velx) - otherpt.x):
self.velx = - self.velx
# check if changing the sign will increase the x distance
if dy < abs((selfpt.y - self.vely) - otherpt.y):
self.vely = - self.vely
return True
return False
def move(self):
"""our move calls the circle's move, with out velocity"""
super().move(self.velx, self.vely)
def event_ball_collision(balls, i, j):
"""change the color of the balls that collided to see effect"""
print(f"EVENT: collision between {i} and {j}")
balls[i].setOutline("blue")
balls[i].setFill("blue")
balls[j].setOutline("blue")
balls[j].setFill("blue")
# this is an array of new balls, so that we can avoid over lapping ball placement
newballs = []
def gen_ball(win, radius):
"""place new ball with some velocity and not overlapping on the balls in the field"""
global newballs
# must have some velocity, cannot be 0,0
velx = vely = 0
while (velx == 0 and vely == 0):
velx = random.randrange(0,3) - 1
vely = random.randrange(0,3) - 1
# create until we have one that doesn't overlap other balls
tryagain = True
while (tryagain):
startx = random.randrange(radius + 1, win.getWidth() - radius)
starty = random.randrange(radius + 1, win.getHeight() - radius)
newball = Ball(win.getWidth(), win.getHeight(), graphics.Point(startx,starty), radius, velx, vely)
newball.setOutline("red")
newball.setFill("red")
# check for collision with previous set of new balls
tryagain = False
for b in newballs:
if newball.ball_collision(b):
tryagain = True
# new ball can be placed without collision, lets keep track of it
# so that we can compare to the next new ball
newballs.append(newball)
newball.draw(win)
return newball
def main(ballnum = 20, radius = 5):
"""Main routine with some important variables"""
win = graphics.GraphWin("Ball Bounce", 800, 400 )
# generate all the balls for the field
balls = [ gen_ball(win, radius) for i in range(ballnum) ]
# move each ball and check for collision either wall or other ball
while(True):
for i in range(ballnum):
balls[i].move()
balls[i].collide_wall()
# check to see if we collided with any other ball on the field
for j in range(ballnum):
if i != j:
if (balls[i].ball_collision(balls[j])):
event_ball_collision(balls, i, j)
main()
这是我收集的:
from graphics import *
from random import *
from math import *</p>
<p>class Ball(Circle):
def <strong>init</strong>(self, win_width, win_high, point, r, vel1, vel2):
Circle.<strong>init</strong>(self, point, r)</p>
<pre><code> self.width = win_width
self.high = win_high
self.vecti1 = vel1
self.vecti2 = vel2
def collide_wall(self):
bound1 = self.getP1()
bound2 = self.getP2()
if (bound2.y >= self.width):
self.vecti2 = -self.vecti2
self.move(0, -1)
if (bound2.x >= self.high):
self.vecti1 = -self.vecti1
self.move(-1, 0)
if (bound1.x <= 0):
self.vecti1 = -self.vecti1
self.move(1, 0)
if (bound2.y <= 0):
self.vecti2 = -self.vecti2
self.move(0, 1)
def ball_collision(self, cir2):
radius = self.getRadius()
radius2 = cir2.getRadius()
bound1 = self.getP1()
bound3 = cir2.getP1()
center1 = Point(radius + bound1.x,radius + bound1.y)
center2 = Point(radius2 + bound3.x,radius2 + bound3.y)
centerx = center2.getX() - center1.getX()
centery = center2.getY() - center1.getY()
distance = sqrt((centerx * centerx) + (centery * centery))
if (distance <= (radius + radius2)):
xdistance = abs(center1.getX() - center2.getX())
ydistance = abs(center1.getY() - center2.getY())
if (xdistance <= ydistance):
if ((self.vecti2 > 0 & bound1.y < bound3.y) | (self.vecti2 < 0 & bound1.y > bound3.y)):
self.vecti2 = -self.vecti2
if ((cir2.vecti2 > 0 & bound3.y < bound1.y) | (cir2.vecti2 < 0 & bound3.y > bound1.y)):
cir2.vecti2 = -cir2.vecti2
elif (xdistance > ydistance):
if ((self.vecti1 > 0 & bound1.x < bound3.x) | (self.vecti1 < 0 & bound1.x > bound3.x)):
self.vecti1 = -self.vecti1
if ((cir2.vecti1 > 0 & bound3.x < bound1.x) | (cir2.vecti1 < 0 & bound3.x > bound1.x)):
cir2.vecti1 = -cir2.vecti1
def main(): win = GraphWin("Ball screensaver", 700,700)
velo1 = 4
velo2 = 3
velo3 = -4
velo4 = -3
cir1 = Ball(win.getWidth(),win.getHeight(),Point(50,50), 20, velo1, velo2)
cir1.setOutline("red")
cir1.setFill("red")
cir1.draw(win)
cir2 = Ball(win.getWidth(),win.getHeight(),Point(200,200), 20, velo3, velo4)
cir2.setOutline("blue")
cir2.setFill("blue")
cir2.draw(win)
while(True):
cir1.move(cir1.vecti1, cir1.vecti2)
cir2.move(cir2.vecti1, cir2.vecti2)
time.sleep(.010)
cir1.collide_wall()
cir2.collide_wall()
cir1.ball_collision(cir2)
#cir2.ball_collision(cir1)
main()
好的,问题来了。这个数学根本不能正常工作。有时它会完美运行,有时一个球会压倒另一个球,或者它们不会像球碰撞那样做出反应。我正在绞尽脑汁想找出问题所在,但我觉得我现在离项目太近了,看不到它。任何帮助将不胜感激。
将您的 "if" 语句修正为合法且直接。我认为您可能想说类似下面的内容。很难说,因为您还没有记录您的代码。
if cir2.vecti2 > 0 and bound3.y > bound1.y:
cir2.vecti2 = -cir2.vecti2
请注意,bound3 没有值。你会发现其他问题,我敢肯定。
我建议您备份并尝试增量编码。首先,尝试让一个球合法地四处移动,从墙上弹起。放入位置的跟踪打印语句,并标记它们,以便您知道您在代码中的位置。
一旦你成功了,然后添加第二个球。继续打印语句,注释掉您认为不再需要的语句。在整个程序运行之前不要删除它们。
这对你有帮助吗?
我查看了这段代码,认为它需要一些帮助。我开始从中获得乐趣,最终使它变得可行、评论和有趣……适用于 python 3.9。我还添加了一个功能,当球碰撞时它们会变成蓝色,视觉效果很棒!
import random
import math
import graphics
class Ball(graphics.Circle):
def __init__(self, width, high, point, radius, velx, vely):
"""a ball is a circle with velocity"""
super().__init__(point, radius)
self.width = width
self.high = high
self.velx = velx
self.vely = vely
def collide_wall(self):
"""find out if this ball collided with any wall"""
ctrpt = self.getCenter()
radius = self.getRadius()
if (ctrpt.x - radius <= 0):
self.velx = -self.velx
if (ctrpt.x + radius >= self.width):
self.velx = -self.velx
if (ctrpt.y - radius <= 0):
self.vely = -self.vely
if (ctrpt.y + radius >= self.high):
self.vely = -self.vely
self.move()
def ball_collision(self, other):
"""find out if this ball collided with 'other' ball"""
radius = self.getRadius()
selfpt = self.getCenter()
otherpt = other.getCenter()
# calculate distances
dx = abs(selfpt.x - otherpt.x)
dy = abs(selfpt.y - otherpt.y)
radius_distance = math.sqrt((dx * dx) + (dy * dy))
# Check to see if the 2 balls are close enough to be in contact
if (radius_distance <= (2*radius)):
# check if changing the sign will increase the x distance
if dx < abs((selfpt.x - self.velx) - otherpt.x):
self.velx = - self.velx
# check if changing the sign will increase the x distance
if dy < abs((selfpt.y - self.vely) - otherpt.y):
self.vely = - self.vely
return True
return False
def move(self):
"""our move calls the circle's move, with out velocity"""
super().move(self.velx, self.vely)
def event_ball_collision(balls, i, j):
"""change the color of the balls that collided to see effect"""
print(f"EVENT: collision between {i} and {j}")
balls[i].setOutline("blue")
balls[i].setFill("blue")
balls[j].setOutline("blue")
balls[j].setFill("blue")
# this is an array of new balls, so that we can avoid over lapping ball placement
newballs = []
def gen_ball(win, radius):
"""place new ball with some velocity and not overlapping on the balls in the field"""
global newballs
# must have some velocity, cannot be 0,0
velx = vely = 0
while (velx == 0 and vely == 0):
velx = random.randrange(0,3) - 1
vely = random.randrange(0,3) - 1
# create until we have one that doesn't overlap other balls
tryagain = True
while (tryagain):
startx = random.randrange(radius + 1, win.getWidth() - radius)
starty = random.randrange(radius + 1, win.getHeight() - radius)
newball = Ball(win.getWidth(), win.getHeight(), graphics.Point(startx,starty), radius, velx, vely)
newball.setOutline("red")
newball.setFill("red")
# check for collision with previous set of new balls
tryagain = False
for b in newballs:
if newball.ball_collision(b):
tryagain = True
# new ball can be placed without collision, lets keep track of it
# so that we can compare to the next new ball
newballs.append(newball)
newball.draw(win)
return newball
def main(ballnum = 20, radius = 5):
"""Main routine with some important variables"""
win = graphics.GraphWin("Ball Bounce", 800, 400 )
# generate all the balls for the field
balls = [ gen_ball(win, radius) for i in range(ballnum) ]
# move each ball and check for collision either wall or other ball
while(True):
for i in range(ballnum):
balls[i].move()
balls[i].collide_wall()
# check to see if we collided with any other ball on the field
for j in range(ballnum):
if i != j:
if (balls[i].ball_collision(balls[j])):
event_ball_collision(balls, i, j)
main()