简体   繁体   中英

Circle-circle collision with friction

I'm making a small game with javascript and what I want to do is to make 2 circles collide. I already can detect when they collide, I can calculate the exact time between 2 frames when they collide and I can let them collide without friction and rotation. Now I want to add some kind of friction so they will rotate after colliding.

In my current code, I use a method in my Ball constructor to see if it will collide in the next frame. I also made a Vector2 object.

If you don't understand something of my code, feel free to ask. This is the code I'm currently using:

this.checkCollision=function(ball,delta){
    var that=this;
    var radii=this.r+ball.r;
    var rVelA=Vector2.scale(this.v,delta); //the velocity per frame
    var rVelB=Vector2.scale(ball.v,delta);
    var A=function(t){return Vector2.add(that.p,Vector2.scale(rVelA,t));}; //position in function of time
    var B=function(t){return Vector2.add(ball.p,Vector2.scale(rVelB,t));}; //position in function of time
    var P=Vector2.substract(this.p,ball.p); //relative position
    var V=Vector2.substract(rVelA,rVelB); //relative velocity
    var a=V.getSLength();
    var b=2*(P.x*V.x+P.y*V.y);
    var c=P.getSLength()-radii*radii;
    var D=b*b-4*a*c;
    if(D>=0){
        var t=(-b-Math.sqrt(D))/(2*a);
        if(t<=1&&t>=0){
            var x,y;
            P=A(t); //position of ball A on collision
            var Q=B(t); //position of ball B on collision
            x=(Q.x-P.x)/radii;
            y=(Q.y-P.y)/radii;
            var newXvA=x*x*ball.v.x+x*y*ball.v.y+y*y*that.v.x-y*x*that.v.y;
            var newYvA=x*y*ball.v.x+y*y*ball.v.y-x*y*that.v.x+x*x*that.v.y;
            var newXvB=x*x*that.v.x+x*y*that.v.y+y*y*ball.v.x-y*x*ball.v.y;
            var newYvB=x*y*that.v.x+y*y*that.v.y-x*y*ball.v.x+x*x*ball.v.y;
            //Collider(ball object, collision position, previous velocity, new velocity)
            var colliderA=new Collider(this,P,that.v.clone(),new Vector2(newXvA,newYvA));
            var colliderB=new Collider(ball,Q,ball.v.clone(),new Vector2(newXvB,newYvB));
            //Collision(collider A, collider B, collision time)
            return new Collision(colliderA,colliderB,t);
        }
    }
};

Let's say I have a variable frictionCo for the friction coefficient, how can I calculate the velocity and angular velocity (in rad/s) of the balls after the collision?

My new code

I finally made my game as I wanted by adding friction. The linear velocity is affected by the radial velocity and vice versa.

Here is my new code:

this.checkCollision=function(ball,delta){
    var that=this;
    var radii=this.r+ball.r;
    var rVelA=Vector2.scale(this.v,delta); //the velocity per frame
    var rVelB=Vector2.scale(ball.v,delta);
    var A=function(t){return Vector2.add(that.p,Vector2.scale(rVelA,t));}; //position in function of time
    var B=function(t){return Vector2.add(ball.p,Vector2.scale(rVelB,t));};
    var P=Vector2.substract(this.p,ball.p); //relative position
    var V=Vector2.substract(rVelA,rVelB); //relative velocity
    var a=V.getSLength();
    var b=2*(P.x*V.x+P.y*V.y);
    var c=P.getSLength()-radii*radii;
    var D=b*b-4*a*c;
    if(D>=0){
        var t=(-b-Math.sqrt(D))/(2*a);
        if(t<=1&&t>=0){
            var x,y;
            P=A(t); //position of first ball on collision
            var Q=B(t); //position of other ball on collision
            var angle=Math.atan2(Q.y-P.y,Q.x-P.x);
            var rotVA=this.v.clone().rotate(-angle); //rotate so they collide straight (rotated velocity of A)
            var rotVB=ball.v.clone().rotate(-angle);
            var IA=this.mass*this.r*this.r/2; //Inertia
            var IB=this.mass*this.r*this.r/2;
            var vt=rotVA.y+this.rotV*this.r-rotVB.y+ball.rotV*ball.r;
            var s=Math.sign(vt);
            var x=2*(rotVA.x-rotVB.x)/(1/this.mass+1/ball.mass);
            var dvt=-x*s*frictionCo*(3/this.mass+3/ball.mass);
            if(-s*dvt>s*vt){
                s*=-vt/dvt; //if they stop rotating to adjust the friction
            }
            var newVA=Vector2.add(rotVA,new Vector2(-x/this.mass,-s*frictionCo*x/this.mass)).rotate(angle);
            var newVB=Vector2.add(rotVB,new Vector2(x/ball.mass,s*frictionCo*x/ball.mass)).rotate(angle);
            var newRotA=this.rotV-s*frictionCo*this.r*x/IA;
            var newRotB=ball.rotV-s*frictionCo*ball.r*x/IB;
            //Collider(ball object, collision position, previous velocity, new velocity, new radial velocity)
            var colliderA=new Collider(this,P,that.v.clone(),newVA,newRotA);
            var colliderB=new Collider(ball,Q,ball.v.clone(),newVB,newRotB);
            //Collision(collider A, collider B, collision time)
            return new Collision(colliderA,colliderB,t);
        }
    }
};

When the circles collide, they rub against each other and the friction creates a torque that changes the rotational speed of each circle. The forces will be equal and opposite, but the torques will depend on the individual radii. It's complicated to estimate how long they'll be in contact, but I'd just make up some rule and see how it goes, like the contact time is the same for all collisions. So for some short time, the forces create torques, and the torques change the rotational speed based on the moment of inertia of the circle or disk.

Some details on the frictional force are that: 1) it's usually well approximated as independent of speed, so the direction will always be to oppose the different in surface velocities, but the size won't scale with this velocity difference; 2) in general, friction will depend on the force of contact, which, in a detailed simulation would vary throughout the collision, but you could just estimate it as a constant for all collisions, or make it depend on, say, the total change in linear momentum (which is basically the time average of time impact force).

Response to comments:
It sounds like you're getting confused thinking about "friction". Instead, think of friction only as a force applied tangential to the circle at its surface , and calculate the speeds from there (eg, write a function that changes the circle's speed for an arbitrary force vs time). Then separately calculate the frictional force and give this to the equation. (Btw, you can't generally do this separation in simulations, but it's an added convenience because the frictional force is independent of speed -- though it's not completely independent since it stops changing the speed when the surface speeds match so watch for this small detail).

To calculate the resulting change in speed from the tangential frictional force, use standard rotational dynamics. See, for example, here , or any other hits for "rotational dynamics". Basically, it's like F=ma, except it's now Torque = (moment of interia) * (angular acceleration) . Moment of inertia (I) is a constant for the object, use the frictional force to find the torque (Torque = F*R ), and to find the angular acceleration ( A = T/I ), and use the angular acceleration to find the total change in angular velocity, which will give you the new angular velocity.

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