Ejemplo n.º 1
0
        // Description:	Perform a collision between two balls.
        //
        // Note: This code doesn't give great results at high velocities, because the
        // collision isn't detected until after the balls are closer than their minimum
        // distance. A better version would take their current position and backtrack by
        // part of the last increment of each ball to find the spot where they were when
        // they actually collided.
        public void Collide(Ball ball2, bool specialCheck)
        {
            Vector pos1 = new Vector(position.X, position.Y);
            Vector pos2 = new Vector(ball2.position.X, ball2.position.Y);

            /*
             * Figure out the center vector. We would normally use a unit vector, but we can't
             * do that easily in integers, so we remember that the dot product of a unit vector
             * with another vector is the same as the dot product of the non-unit vector with the
             * vector divided by the length of the non-unit vector. Basically, wherever we want to
             * use the unit vector, we have to use the center vector and remember the length factor.
             */
            Vector c = pos1 - pos2;

            float t = c.Length;

            if (t == 0.0f)
            {
                t = 0.01f;
            }

            /*
             * Figure out the projections of the velocity vectors on the center vector. The dot
             * products give us a signed length of the velocity vectors aint the line of impact.
             * We then compute the new final velocities using conservation of momentum and the
             * velocity relation (velocity of recession = velocity of approach)
             * Momentum:
             *  m1v1f + m2v2f = m1v1i + m2v2i
             * Velocity:
             *  v2f - v1f = -(v2i - v1i)
             *
             * Solving for v2f, we get (after a few manipulations)
             *  V2f = 2M1V1i + (M2 - M1)V2i
             *        ---------------------
             *               M1 + M2
             *
             * Note that this simplifies in the equal mass case to V2f = v1i
             *
             * We then use the velocity relation to determine V1f:
             * V1f = V2f + V2i - V1i
             */
            float v1i = Vector.DotProduct(velocity, c) / (t * t);
            float v2i = Vector.DotProduct(ball2.velocity, c) / (t * t);

            float v2f = (2 * mass * v1i + (ball2.mass - mass) * v2i) /
                        (mass + ball2.mass);
            float v1f = v2f + v2i - v1i;

            /*
             * Scale the final velocities by the elasticity factor. This probably isn't rigorous,
             * but the references I have don't do much with this, other than mention that the
             * solution is non-trivial.
             * All balls are currently equally elastic. This could be changed later by adding a
             * separate factor, and multiplying the factors together.
             */
            v2f *= setup.elasticityBall;
            v1f *= setup.elasticityBall;

            Vector c1 = c * v1i;
            Vector c2 = c * v2i;

            /*
             * Weed out some antisocial behavior - the balls may be moving towards each other. If
             * we don't, we may have already calculated this collision. Anyway, if the dot product
             * of c and c1 > 0 (they point in the same direction), the balls are travelling
             * towards each other, and we should continue.
             * NOTE: I'm not sure how well this works...
             */
            if (specialCheck)
            {
                if (Vector.DotProduct(c, c1) > 0)
                {
                    if (Vector.DotProduct(c, c2) < 0)
                    {
                        return;
                    }
                    if (c1.Length > c2.Length)
                    {
                        return;
                    }
                }
                else
                {
                    if (Vector.DotProduct(c, c2) < 0)
                    {
                        if (c1.Length < c2.Length)
                        {
                            return;
                        }
                    }
                }
            }

            /*
             * Figure out the perpendicular vectors, so we can deal with the velocities along the
             * center axis only.
             */
            Vector p1 = velocity - c1;
            Vector p2 = ball2.velocity - c2;


            Vector f1 = c * v1f;
            Vector f2 = c * v2f;

            /*
             * Finally, add back in the perpendicular velocities to get the final results...
             */
            velocity       = f1 + p1;
            ball2.velocity = f2 + p2;
        }
Ejemplo n.º 2
0
        // Description:	Handle gravity and collisions between the current ball and another
        public void GravityCollide(Ball ball2)
        {
            /*
             * If we're doing gravity, the calculations can be reused for collisions (if enabled)
             * If we're doing collisions only, we have some short-circuit cases...
             */
            if (setup.gravityBall != 0)
            {
                MyPointF dist   = position - ball2.position;
                float    distSq = dist.X * dist.X + dist.Y * dist.Y;

                /*
                 * Collision (no short-circuit - already have distance squared)
                 */
                if (setup.collisions)
                {
                    int centerDistance   = size + ball2.size;
                    int centerDistanceSq = centerDistance * centerDistance;

                    if (distSq <= centerDistanceSq)
                    {
                        Collide(ball2, true);
                        distSq = 0;                                     // set to zero to disable gravity for this iteration
                    }
                }

                if (distSq != 0)
                {
                    float distCu = (float)(Math.Sqrt(distSq) * distSq);
                    float sx     = (setup.gravityBall * gval * dist.X);
                    float sy     = (setup.gravityBall * gval * dist.Y);
                    velocity.X       -= (sx * ball2.mass) / distCu;
                    velocity.Y       -= (sy * ball2.mass) / distCu;
                    ball2.velocity.X += (sx * mass) / distCu;
                    ball2.velocity.Y += (sy * mass) / distCu;
                }
            }
            else
            {
                /*
                 * No gravity, optimize collision
                 */
                if (!setup.collisions)
                {
                    return;
                }

                /*
                 * Trivial rejection...
                 */
                float centerDistance = size + ball2.size;

                float distx = Math.Abs(position.X - ball2.position.X);

                if (distx > centerDistance)
                {
                    return;
                }

                float disty = Math.Abs(position.Y - ball2.position.Y);

                if (disty > centerDistance)
                {
                    return;
                }

                /*
                 * Passed trivial reject. Are we really close enough?
                 * We factor out sqrt() operation to speed things up, and to gain precision
                 */

                float centerDistanceSq = centerDistance * centerDistance;
                float distSq           = distx * distx + disty * disty;

                if (distSq > centerDistanceSq)
                {
                    return;
                }

                /*
                 * Do the collision!
                 */
                Collide(ball2, true);
            }
        }