Calculating direction after circle-circle collision

Started by
6 comments, last by Finalspace 6 years, 5 months ago

I know how to calculate the scalar of the velocity vector after a collision with 2 circles (as per this link: https://gamedevelopment.tutsplus.com/tutorials/how-to-create-a-custom-2d-physics-engine-the-basics-and-impulse-resolution--gamedev-6331)

These circles cannot rotate and do not have friction but can have different masses, however I cannot seem to find out any way to find the unit vector that I need to multiply the scalar of velocity by to get the new velocity of the particles after the collision.

I also know how to check if 2 circles are colliding.

Also, I am only dealing with this in a purely "maths-sense" (ie. the circles have a center and a radius), and would like to know how I can represent these circles on the screen in python 3.0.

The vector class:

class Vector():
def __init__(self,x,y):
    self.x = x
    self.y = y

def add(self, newVector):
    return Vector(self.x+newVector.x, self.y+newVector.y)

def subtract(self,newVector):
    return Vector(self.x-newVector.x, self.y-newVector.y)

def equals(self, newVector):
    return Vector(newVector.x,newVector.y)

def scalarMult(self, scalar):
    return Vector(self.x*scalar, self.y*scalar)

def dotProduct(self, newVector):
    return (self.x*newVector.x)+(self.y*newVector.y

def distance(self):
    return math.sqrt((self.x)**2 +(self.y)**2)

The circle class:

class Particles():
def __init__(self,currentPos, oldPos, accel, dt,mass, center, radius):
    self.currentPos = currentPos
    self.oldPos = oldPos
    self.accel = accel
    self.dt = dt
    self.mass = mass
    self.center = center
    self.radius = radius

def doVerletPosition(currentPos, oldPos, accel, dt):
    a = currentPos.subtract(oldPos)
    b = currentPos.add(a)
    c = accel.scalarMult(dt)
    d = c.scalarMult(dt)
    return d.add(b)

def doVerletVelocity(currentPos, oldPos, dt):
    deltaD = (currentPos.subtract(oldPos))
    return deltaD.scalarMult(1/dt)

def collisionDetection(self, center, radius):
    xCenter = (self.radius).xComponent()
    yCenter = (self.radius).yComponent()
    xOther = radius.xComponent()
    yOther = radius.yComponent()
    if ((xCenter - xOther)**2 + (yCenter-yOther)**2 < (self.radius + radius)**2):
        return True
    else:
        return False

I do know about AABBs, but I am only using around 10 particles for now, and AABBs are not necessary now.

Advertisement

The usual billiard physics will hopefully help you. It can be narrow down to weighted disks easily. I haven't read that link thought. But at first glance it covers what you are looking for.

Ah that is somehow easy Its not that hard:

- You take the difference between the two centers in world space: R = B - A

- Normalize that and you have your direction: N = R / |R|

- Calculate the penetration distance by subtracting the summed radius of both circles from the projected difference by the direction (btw: This distance is the length of the difference): d = (RadiusA+RadiusB) - Dot(R, N)

- Calculate relative velocity: VAB = VA - VB

- Calculate impulse strength: j = -(1 + e) * Dot(VAB, N) / (1/MassA + 1/MassB);

- Calculate and apply impulse on velocities:

VA -= j * (1 / MassA) * N

VB += j * (1 / MassB) * N

 

Thats one step. Next step is to resolve penetration. This is handled in the "how to create a custom 2D physics engine" series as well - so check that out.

Quote

Calculate impulse, done: I = N * d

This obviously has not the dimensions of an impulse.

34 minutes ago, Dirk Gregorius said:

This obviously has not the dimensions of an impulse.

Right, its not an impulse at all! My bad. Its a minimum translation vector!

An impulse would be at the relative velocity projected along the direction divided by the sum of their masses.

Quote

An impulse would be at the relative velocity projected along the direction divided by the sum of their masses.

Nope, impulse = mass * velocity. Not velocity divided by mass. You are also not taking the rotational effects into account. E.g. the inertia contribution seen by the impulse at the application point in the direction of the normal. This is sometimes referred to as effective mass.


float EffectiveMassInv = 1/m1 + 1/m2 + dot(n, InvI1 * n) + dot(n, InvI2 * n);
float EffectiveMass = 1 / EffectiveMassInv;

Then you can compute equal and opposite impulses on each body like


float Lambda = EffectiveMass * -RelVelocity;
Body1->ApplyImpulseAt( -n * Lambda, ContactPoint );
Body2->ApplyImpulseAt( n, Lambda, ContactPoint );

 

 

On 17.10.2017 at 7:56 PM, Dirk Gregorius said:

Nope, impulse = mass * velocity. Not velocity divided by mass. You are also not taking the rotational effects into account. E.g. the inertia contribution seen by the impulse at the application point in the direction of the normal. This is sometimes referred to as effective mass.



float EffectiveMassInv = 1/m1 + 1/m2 + dot(n, InvI1 * n) + dot(n, InvI2 * n);
float EffectiveMass = 1 / EffectiveMassInv;

Then you can compute equal and opposite impulses on each body like



float Lambda = EffectiveMass * -RelVelocity;
Body1->ApplyImpulseAt( -n * Lambda, ContactPoint );
Body2->ApplyImpulseAt( n, Lambda, ContactPoint );

 

 

The OP dont care about rotations, so i havent included it. 

This topic is closed to new replies.

Advertisement