简体   繁体   中英

Python 2d Ball Collision

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM