Beispiel #1
0
        private void BallCollision(ScreenObject ball1, ScreenObject ball2)
        {
            #region vars

            float   accuracy = Global.currentGame.TEST_accuracy;
            float   tpivot1;
            float   tpivot2;
            double  difference;
            float   d;                   //distance between
            double  phi1;                //angle of collision
            Vector2 Fg12 = Vector2.Zero; //gravitational force by particle 1 on particle 2
            Vector2 Fg21 = Vector2.Zero;
            double  dmin;                //r1 + r2
            float   masses;
            float   axis;                //flag telling collision axis points NESW or NWSE
            //ball 1
            Vector2 displacement1 = Vector2.Zero;
            Vector2 v12;     //velocity on collision axis
            Vector2 a12;     //acceleration on collision axis
            double  v12mag;
            Vector2 v11;     //velocity not on collision axis
            double  v12fmag; //result of 1d collision along axis of collision
            Vector2 v12f;
            Vector2 v1f;
            double  vAlignment1; //alignment of collision to velocity
            double  cvtheta1;    //angle between collision and velocity
            double  vtheta1;     //angle of velocity
            //ball 2
            Vector2 displacement2 = Vector2.Zero;
            Vector2 v22;     //velocity on collision axis
            Vector2 a22;     //acceleration on collision axis
            double  v22mag;
            Vector2 v21;     //velocity not on collision axis
            double  v22fmag; //result of 1d collision along axis of collision
            Vector2 v22f;
            Vector2 v2f;
            double  vAlignment2; //alignment of collision to velocity
            double  cvtheta2;
            double  phi2;        //angle of collision
            double  vtheta2;     //angle of velocity

            double atheta1;
            double catheta1;
            double aAlignment1;
            double a12mag;
            double a22mag;
            double atheta2;
            double catheta2;
            double aAlignment2;

            #endregion

            //if bullet doesnt hit cue, return
            //if (ball1 is Bullet && ball2 is BilliardBall)
            //    if (((BilliardBall)ball2).type != BilliardBall.TYPE_CUE) return;
            //else if (ball2 is Bullet && ball1 is BilliardBall)
            //    if (((BilliardBall)ball1).type != BilliardBall.TYPE_CUE) return;

            d          = Vector2.Distance(ball2.location, ball1.location);
            dmin       = ball1.sRadius + ball2.sRadius;
            difference = dmin - d;

            if (difference > accuracy)
            {
                masses = ball1.mass + ball2.mass;

                if (d < dmin)
                {
                    ball1.hit = true;
                    ball2.hit = true;
                }

                #region displacement correction
                //Because the field is updated discretely, collisions will always overshoot and need corrections
                //correction of location
                //note that with an acceleration, velocity should be corrected as well
                //acceleration will be corrected with gravity section
                //will need recursion here to check for extra collisions after corrections

                tpivot1 = ball1.t;
                tpivot2 = ball2.t;
                //the justification of this while loop is demonstrated in test 1 and 2
                while (!(difference > -accuracy && difference < accuracy) && tpivot1 > accuracy && tpivot2 > accuracy)
                {   //quicksort to t when objs first contact
                    tpivot1 /= 2;
                    tpivot2 /= 2;
                    if (difference > accuracy)
                    {
                        ball1.t -= tpivot1;
                        ball2.t -= tpivot2;
                    }
                    else
                    {
                        ball1.t += tpivot1;
                        ball2.t += tpivot2;
                    }

                    //replace this with modified update from BilliardBall.TEST_BounceOnScreenWalls
                    ball1.ModifiedUpdate();
                    ball2.ModifiedUpdate();

                    d = Vector2.Distance(ball2.location, ball1.location);

                    difference = dmin - d;
                }

                phi1 = Math.Atan2((ball2.location.Y - ball1.location.Y), (ball2.location.X - ball1.location.X));

                #endregion

                if (Math.Abs(difference) < accuracy)
                {
                    #region circular collision detection

                    axis  = (float)Math.Tan(phi1);
                    axis /= Math.Abs(axis);
                    if (float.IsNaN(axis))
                    {
                        axis = -1;
                    }

                    //ball 1
                    vtheta1     = Math.Atan2(ball1.velocity.Y, ball1.velocity.X);
                    cvtheta1    = phi1 - vtheta1;
                    vAlignment1 = Math.Cos(cvtheta1);
                    v12         = new Vector2((float)((ball1.velocity.Length() * vAlignment1) * Math.Cos(phi1)), (float)((ball1.velocity.Length() * vAlignment1) * Math.Sin(phi1)));
                    v11         = ball1.velocity - v12; //split velocity into 2 vectors
                    if (v12.X < 0)
                    {
                        v12mag = v12.Length() * -1;            //flatten along x axis
                    }
                    else
                    {
                        v12mag = v12.Length();
                    }

                    //ball 2
                    phi2        = phi1 + Math.PI;
                    vtheta2     = Math.Atan2(ball2.velocity.Y, ball2.velocity.X);
                    cvtheta2    = phi2 - vtheta2;
                    vAlignment2 = Math.Cos(cvtheta2);
                    v22         = new Vector2((float)((ball2.velocity.Length() * vAlignment2) * Math.Cos(phi2)), (float)((ball2.velocity.Length() * vAlignment2) * Math.Sin(phi2)));
                    v21         = ball2.velocity - v22; //split velocity into 2 vectors
                    if (v22.X < 0)
                    {
                        v22mag = v22.Length() * -1;            //flatten along x axis
                    }
                    else
                    {
                        v22mag = v22.Length();
                    }

                    //conservation of momentum
                    if (ball1.mass == ball2.mass || masses == 0)
                    {
                        v12fmag = v22mag;
                        v22fmag = v12mag;
                    }
                    else
                    {
                        v12fmag = ((ball1.mass - ball2.mass) / masses) * v12mag + ((2 * ball2.mass) / masses) * v22mag; //1d collision
                        v22fmag = ((ball1.mass * 2) / masses) * v12mag + ((ball2.mass - ball1.mass) / masses) * v22mag;
                    }
                    v12f = new Vector2((float)(v12fmag * Math.Abs(Math.Cos(phi1))), (float)(v12fmag * axis * Math.Abs(Math.Sin(phi1)))); //unflatten
                    v22f = new Vector2((float)(v22fmag * Math.Abs(Math.Cos(phi2))), (float)(v22fmag * axis * Math.Abs(Math.Sin(phi2))));
                    v1f  = v12f + v11;
                    v2f  = v22f + v21;

                    ball1.velocity = v1f;
                    ball2.velocity = v2f;

                    #endregion
                }

                //need to use old code if balls bounce into another in one frame
                //can be removed after recursion is implemented
                else
                {
                    #region old displacement correction
                    //Because the field is updated discretely, collisions will always overshoot and need corrections
                    //correction of location
                    //note that with an acceleration, velocity should be corrected as well
                    //acceleration will be corrected with gravity section
                    difference  = dmin;
                    difference -= d;
                    Vector2 dx = new Vector2((float)(difference * Math.Cos(phi1)), (float)(difference * Math.Sin(phi1)));
                    if (masses == 0)
                    {
                        displacement2   = dx / 2;
                        displacement1   = -displacement2;
                        ball2.location += displacement2;
                        ball1.location += displacement1;
                        ball2.updateAbsLoc();
                        ball1.updateAbsLoc();
                    }
                    else
                    {
                        displacement2   = dx * (ball1.mass / masses);
                        displacement1   = -dx * (ball2.mass / masses);
                        ball2.location += displacement2;
                        ball1.location += displacement1;
                        ball2.updateAbsLoc();
                        ball1.updateAbsLoc();
                    }
                    d = Vector2.Distance(ball2.location, ball1.location);
                    #endregion

                    #region old circular collision detection

                    axis  = (float)Math.Tan(phi1);
                    axis /= Math.Abs(axis);
                    if (float.IsNaN(axis))
                    {
                        axis = -1;
                    }

                    //ball 1
                    vtheta1     = Math.Atan2(ball1.velocity.Y, ball1.velocity.X);
                    cvtheta1    = phi1 - vtheta1;
                    vAlignment1 = Math.Cos(cvtheta1);
                    v12         = new Vector2((float)((ball1.velocity.Length() * vAlignment1) * Math.Cos(phi1)), (float)((ball1.velocity.Length() * vAlignment1) * Math.Sin(phi1)));
                    v11         = ball1.velocity - v12; //split velocity into 2 vectors
                    if (v12.X < 0)
                    {
                        v12mag = v12.Length() * -1;            //flatten along x axis
                    }
                    else
                    {
                        v12mag = v12.Length();
                    }
                    //velocity correction
                    if (ball1.oldAcceleration.Length() > 0)
                    {
                        atheta1     = Math.Atan2(ball1.oldAcceleration.Y, ball1.oldAcceleration.X);
                        catheta1    = phi1 - atheta1;
                        aAlignment1 = Math.Cos(catheta1);
                        a12         = new Vector2((float)((ball1.oldAcceleration.Length() * aAlignment1) * Math.Cos(phi1)), (float)((ball1.oldAcceleration.Length() * aAlignment1) * Math.Sin(phi1)));
                        if (a12.X < 0)
                        {
                            a12mag = a12.Length() * -1;
                        }
                        else
                        {
                            a12mag = a12.Length();
                        }
                        if (v12mag < 0)
                        {
                            if (displacement1.X < 0)
                            {
                                v12mag = -(Math.Sqrt((v12mag * v12mag) - 2 * a12mag * displacement1.Length()));                      //Vxf^2 = Vxi^2 + 2 * a * (xf - xi)
                            }
                            else
                            {
                                v12mag = -(Math.Sqrt((v12mag * v12mag) + 2 * a12mag * displacement1.Length()));
                            }
                        }
                        else
                        {
                            if (displacement1.X < 0)
                            {
                                v12mag = Math.Sqrt((v12mag * v12mag) - 2 * a12mag * displacement1.Length());                      //Vxf^2 = Vxi^2 + 2 * a * (xf - xi)
                            }
                            else
                            {
                                v12mag = Math.Sqrt((v12mag * v12mag) + 2 * a12mag * displacement1.Length());
                            }
                        }
                        if (double.IsNaN(v12mag))
                        {
                            v12mag = 0;
                        }
                    }

                    //ball 2
                    phi2        = phi1 + Math.PI;
                    vtheta2     = Math.Atan2(ball2.velocity.Y, ball2.velocity.X);
                    cvtheta2    = phi2 - vtheta2;
                    vAlignment2 = Math.Cos(cvtheta2);
                    v22         = new Vector2((float)((ball2.velocity.Length() * vAlignment2) * Math.Cos(phi2)), (float)((ball2.velocity.Length() * vAlignment2) * Math.Sin(phi2)));
                    v21         = ball2.velocity - v22; //split velocity into 2 vectors
                    if (v22.X < 0)
                    {
                        v22mag = v22.Length() * -1;            //flatten along x axis
                    }
                    else
                    {
                        v22mag = v22.Length();
                    }
                    //velocity correction
                    if (ball2.oldAcceleration.Length() > 0)
                    {
                        atheta2     = Math.Atan2(ball2.oldAcceleration.Y, ball2.oldAcceleration.X);
                        catheta2    = phi2 - atheta2;
                        aAlignment2 = Math.Cos(catheta2);
                        a22         = new Vector2((float)((ball2.oldAcceleration.Length() * aAlignment2) * Math.Cos(phi2)), (float)((ball2.oldAcceleration.Length() * aAlignment2) * Math.Sin(phi2)));
                        if (a22.X < 0)
                        {
                            a22mag = a22.Length() * -1;
                        }
                        else
                        {
                            a22mag = a22.Length();
                        }
                        if (v22mag < 0)
                        {
                            if (displacement2.X < 0)
                            {
                                v22mag = -(Math.Sqrt((v22mag * v22mag) - 2 * a22mag * displacement2.Length()));                      //Vxf^2 = Vxi^2 + 2 * a * (xf - xi)
                            }
                            else
                            {
                                v22mag = -(Math.Sqrt((v22mag * v22mag) + 2 * a22mag * displacement2.Length()));
                            }
                        }
                        else
                        {
                            if (displacement2.X < 0)
                            {
                                v22mag = Math.Sqrt((v22mag * v22mag) - 2 * a22mag * displacement2.Length());                      //Vxf^2 = Vxi^2 + 2 * a * (xf - xi)
                            }
                            else
                            {
                                v22mag = Math.Sqrt((v22mag * v22mag) + 2 * a22mag * displacement2.Length());
                            }
                        }
                        if (double.IsNaN(v22mag))
                        {
                            v22mag = 0;
                        }
                    }

                    //conservation of momentum
                    if (ball1.mass == ball2.mass || masses == 0)
                    {
                        v12fmag = v22mag;
                        v22fmag = v12mag;
                    }
                    else
                    {
                        v12fmag = ((ball1.mass - ball2.mass) / masses) * v12mag + ((2 * ball2.mass) / masses) * v22mag; //1d collision
                        v22fmag = ((ball1.mass * 2) / masses) * v12mag + ((ball2.mass - ball1.mass) / masses) * v22mag;
                    }
                    v12f = new Vector2((float)(v12fmag * Math.Abs(Math.Cos(phi1))), (float)(v12fmag * axis * Math.Abs(Math.Sin(phi1)))); //unflatten
                    v22f = new Vector2((float)(v22fmag * Math.Abs(Math.Cos(phi2))), (float)(v22fmag * axis * Math.Abs(Math.Sin(phi2))));
                    v1f  = v12f + v11;
                    v2f  = v22f + v21;

                    ball1.velocity = v1f;
                    ball2.velocity = v2f;

                    #endregion
                }

                #region friction between particles

                #endregion

                ball1.oldLocation = ball1.location;
                ball1.oldVelocity = ball1.velocity;
                ball2.oldLocation = ball2.location;
                ball2.oldVelocity = ball2.velocity;
            }
            else
            {
                phi1 = Math.Atan2((ball2.location.Y - ball1.location.Y), (ball2.location.X - ball1.location.X));
            }

            //Gravity(ball1, ball2, d, phi1);
        }