Here is what I have mustered up:
from graphics import *
from random import *
from math import *
class Ball(Circle): def init(self, win_width, win_high, point, r, vel1, vel2): Circle.init(self, point, r)
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()
Ok so here is the problem. This Math is not working correctly at all. Sometimes it works perfectly sometimes one ball overpowers the other ball or they don't react like a ball collision should. I am racking my brain trying to figure out what the problem is but I feel I am too close to the project at the moment to see it. Any help would be appreciated.
Fix your "if" statements to be legal and straightforward. I think that you might be trying to say something like what's below. It's hard to tell, since you haven't documented your code.
if cir2.vecti2 > 0 and bound3.y > bound1.y:
cir2.vecti2 = -cir2.vecti2
Note that bound3 has no value. You will find other problems, I'm sure.
I suggest that you back up and try incremental coding. First, try getting one ball to move around legally, bouncing off walls. Put in tracing print statements for the position, and label them so you know where you are in your code.
Once you have that working, then add the second ball. Continue with the print statements, commenting out the ones you don't think you need any more. Don't delete them until you have the whole program working.
Does this get you going?
I looked through this code, and thought it needed some help. I started to have fun with it,and I ended up making it workable, commented, and fun... works with python 3.9. Also I added a feature, when balls collide they change to blue, makes for a great visual effect!
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()
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.