Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Ball Physics problem Python

I am trying to make a ball bounce within a box correctly, specifically handling corners at specific angles and handling a corner head on. I have a problem, because my ball keeps coming out of the box. I have this function that tells if my ball is out of the box and it handles corners and walls. The code is this:

    if ((self._x > self._Grid.getWidth()) or (self._x < 0)):
        print("RandomNode:outside paramaters: x! self._x = %s , self._velx = %s" % (self._x , self._velx))
    if ((self._y > self._Grid.getLength())  or (self._y < 0)):
        print("RandomNode:outside paramaters: y!")
    if ((self._velx + self._x) > self._Grid.getWidth()):
        diff = self._Grid.getWidth()-self._x
        self._velx *= -1
        if (diff == 0):
            self._x -= self._velx
        else:
            self._x+= diff
        tampered = True
        #print("eqn1: self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))

    if (self._velx + self._x < 0):
        diff = self._x
        self._velx *= -1
        if (diff == 0):
            self._x += self._velx
        else:
            self._x-= diff
        tampered = True
        #print("eqn2: self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))


    if ((self._vely + self._y) > self._Grid.getLength()):
        diff = self._Grid.getLength()-self._y
        self._vely *= -1
        if (diff == 0):
            self._y -= self._vely
            if (tampered == True):
                if ((self._velx * -1 == self._vely) or (self._velx == self._vely)):
                    self._x += self._velx
                    self._y += self._vely
                    #print("eqn31:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
                else:
                    self._x += (self._velx - diff)
                    self._y += self._vely
                    #print("eqn32:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
            else:
                tampered = True
                #print("eqn33:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))


        else:
            self._y+= diff
            if (tampered == True):
                if ((self._velx * -1 == self._vely) or (self._velx == self._vely)):
                    self._x += self._velx
                    self._y += self._vely
                    #print("eqn31:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
                else:
                    self._x += (self._velx - diff)
                    self._y += self._vely
                    #print("eqn32:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
            else:
                tampered = True
                #print("eqn33:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))

    if (self._vely + self._y < 0):
        diff = self._y
        self._vely *= -1
        if (diff == 0):
            self._y += self._vely
            if (tampered == True):
                if ((self._velx * -1 == self._vely) or (self._velx == self._vely)):
                    self._x += self._velx
                    self._y += self._vely
                    #print("eqn41:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
                else:
                    self._x += (self._velx + diff)
                    self._y += self._vely
                    #print("eqn42:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
            else:
                tampered = True
                #print("eqn43:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))

        else:
            self._y-= diff
            if (tampered == True):
                if ((self._velx * -1 == self._vely) or (self._velx == self._vely)):
                    self._x += self._velx
                    self._y += self._vely
                    #print("eqn41:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
                else:
                    self._x += (self._velx + diff)
                    self._y += self._vely
                    #print("eqn42:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
            else:
                tampered = True
                #print("eqn43:self._x = %s , self._y = %s , self._velx= %s, self._vely= %s" % (self._x, self._y, self._velx, self._vely))
    return tampered

I don't know why it is not working. x and y are obviously its coordinates. Velx and Vely are its x and y velocities. Tampered is a Boolean that prevents the ball from moving normally and only being moved within check.

Here is my question. What is wrong with this code? OR....is there a template written in python somewhere on the net or where ever, or a code that you have used that does the exact thing I am trying to handle and do? Please revise the code at will, just let me know. Any links to this already solved would be great as well. Thanks.

like image 389
TheChes44 Avatar asked Feb 23 '23 22:02

TheChes44


2 Answers

Rewrite this code. It is way too complex for the simple problem you're trying to solve.

First, a 2D motion of a ball is just 2 1D problems. You can completely separate X and Y. For example, hitting a corner is completely equivalent of hitting a wall in X axis + hitting a wall in Y axis. Hitting a wall in X just reverses the X velocity (and possibly loses some energy if you want to simulate that). Hitting a wall in Y reverses Y velocity.

Second, since the handling of X and Y is so similar, extract a method out of it

def handle_axis_movement(location, velocity):
    "returns updated location and velocity"
    ...

self.x, self.vel_x = handle_axis_movement(self.x, self.vel_x)
self.y, self.vel_y = handle_axis_movement(self.y, self.vel_y)

This will cut the amount of code (and bugs) in half.

Third, you don't have to treat diff==0 and diff<0 seperately. Both cases mean the ball hit a wall, and should reverse its velocity. Then you should correct the location to account for the fact that it couldn't have passed through the wall.

location += velocity
if location > max_bound:
    location = max_bound - (location - max_bound)
    velocity *= -1
if location < min_bound:
    location = min_bound - (location - min_bound)
    velocity *= -1       
like image 106
Ofri Raviv Avatar answered Feb 26 '23 20:02

Ofri Raviv


You shouldn't be reinventing this wheel when pymunk does it for you so well. ;)

like image 37
Joe Avatar answered Feb 26 '23 22:02

Joe