Esempio n. 1
0
 public void UnregisterGhost(GhostPhysicalBody ghost)
 {
     GhostsToRemove.Add(ghost);
 }
Esempio n. 2
0
        //Made this static so we don't accidentally reference properties in the current mob. Want this method to work the same for any two mobs!! 092512ss
        private static void CalculateCollisionForces(Mob other, Mob self, GhostPhysicalBody selfGhost, ref Vector2 selfPositionOffset, ref Vector2 selfNewVelocity, ref Vector2 selfNewNetForces) //bool invertVelocity)
        {
            bool selfIsProjectile = self is Projectile;

            //Calculate collision force
            Vector2 lineToOther = self.CollisionRectangle.Center.ToVector2() - other.CollisionRectangle.Center.ToVector2();
            Vector2 n           = lineToOther; //the collision normal is the direction along the line between the two bodies

            if (n == Vector2.Zero)
            {
                return;
            }
            n.Normalize();
            Vector2 v = self.PhysicalBody.LinearVelocity; // + other.PhysicalBody.LinearVelocity;

            if (v == Vector2.Zero)                        //this actually happens quite often for some reason. Way more often than the other such sanity checks in this method
            {
                return;
            }
            //v = invertVelocity ? -v : v;
            Vector2 u = n * Vector2.Dot(v, n); //need this if not normalized:   n * (Vector2.Dot(v, n) / Vector2.Dot(n, n));
            Vector2 w = v - u;                 //v'=wf-ur, or v'=w-u in a perfectly elastic, frictionless collision (w * Friction - u * Restitution)

            selfNewVelocity = w - u;

            //Redirect net forces (ghost projectile bodies only)
            if (selfGhost != null && selfIsProjectile)
            {
                Vector2 newVelocityDirection = selfNewVelocity;
                if (newVelocityDirection == Vector2.Zero)
                {
                    return;
                }
                newVelocityDirection.Normalize();
                Vector2 oldVelocityDirection = self.PhysicalBody.LinearVelocity;
                if (oldVelocityDirection == Vector2.Zero)
                {
                    return;
                }
                oldVelocityDirection.Normalize();
                float angleBetween = oldVelocityDirection.GetAngleBetweenVectors(newVelocityDirection, Vector2.Zero);
                selfNewNetForces = selfGhost.NetForces.RotateVector(-angleBetween);

                //DEBUG
                //DrawUtility.DrawLine(self.PositionOnScreen,
                //        self.PositionOnScreen + (newVelocityDirection * 100), Color.Red, 2);
            }

            //To prevent a recollision, move along the collision normal away from the other mob
            Vector2 collisionRectangleDiagonal      = new Vector2(self.CollisionRectangle.Width / 2f, self.CollisionRectangle.Height / 2f);
            Vector2 otherCollisionRectangleDiagonal = new Vector2(other.CollisionRectangle.Width / 2f, 0);

            if (lineToOther.Length() < collisionRectangleDiagonal.Length() + otherCollisionRectangleDiagonal.Length())
            {
                if (other.PhysicalBody.IsStatic)
                {
                    selfPositionOffset =
                        (n * ConvertUnits.ToSimUnits(collisionRectangleDiagonal.Length() + otherCollisionRectangleDiagonal.Length())) +
                        ConvertUnits.ToSimUnits(lineToOther.RotateVector(MathHelper.Pi, Vector2.Zero));
                }
                else if (selfGhost != null && !selfIsProjectile)
                {
                    if (self.CollisionRectangle.Width > 100 && other.CollisionRectangle.Width > 100)
                    {
                        Vector2 test = (n * 30 * ConvertUnits.ToSimUnits(collisionRectangleDiagonal.Length() + otherCollisionRectangleDiagonal.Length())) +
                                       ConvertUnits.ToSimUnits(lineToOther.RotateVector(MathHelper.Pi, Vector2.Zero));
                        selfGhost.ApplyForce(test);
                    }
                    selfNewNetForces += n * 50; //arbitrary number. The idea is the two bodies slowly push each other apart, instead of just jumping apart using position
                }
            }
        }
Esempio n. 3
0
 public void RegisterGhost(GhostPhysicalBody ghost)
 {
     GhostsToAdd.Add(ghost);
 }
Esempio n. 4
0
        public virtual void CheckCollide(object sender, EventArgs e)
        {
            if (sender == this)
            {
                return;
            }

            //hack to prevent projectiles spinning around inside of mobs
            if ((this is Projectile && HasCollided.ContainsKey(sender.GetHashCode())) || (sender is Projectile && HasCollided.ContainsKey(GetHashCode())))
            {
                return;
            }

            Mob other = sender as Mob;

            if (IsCollidable && other != null && other.IsCollidable && !AlreadyCollided.Contains(other))
            {
                if (IsPhysicallyIntersecting(other))
                {
                    GhostPhysicalBody ghost      = PhysicalBody as GhostPhysicalBody;
                    GhostPhysicalBody otherGhost = other.PhysicalBody as GhostPhysicalBody;

                    if (ghost == null && otherGhost == null)
                    {
                        return; //two farseer bodies. Collision is handled elsewhere
                    }

                    thisCollidesWithOther = false;
                    otherCollidesWithThis = false;
                    VectorHelper.Zero(ref thisPositionOffset);
                    VectorHelper.Zero(ref otherPositionOffset);
                    VectorHelper.Zero(ref thisNewVelocity);
                    VectorHelper.Zero(ref otherNewVelocity);
                    VectorHelper.Zero(ref thisNewNetForces);
                    VectorHelper.Zero(ref otherNewNetForces);

                    //only apply collision forces if not a projectile or planet
                    thisApplyCollisionForces  = !(other is Projectile) && !PhysicalBody.IsStatic;
                    otherApplyCollisionForces = !(this is Projectile) && !other.PhysicalBody.IsStatic;

                    if (Collide(other) || (IsFixForBigColliding && other.IsFixForBigColliding && CollisionRectangle.Width > 100 && other.CollisionRectangle.Width > 100))
                    {
                        thisCollidesWithOther = true;
                        if (thisApplyCollisionForces)
                        {
                            CalculateCollisionForces(other, this, ghost, ref thisPositionOffset, ref thisNewVelocity, ref thisNewNetForces); //, true);
                        }

                        if (this is Projectile)
                        {
                            HasCollided.AddKeyIfMissing(other.GetHashCode());
                        }
                    }

                    if (other.Collide(this) || (IsFixForBigColliding && other.IsFixForBigColliding && CollisionRectangle.Width > 100 && other.CollisionRectangle.Width > 100))
                    {
                        otherCollidesWithThis = true;
                        if (otherApplyCollisionForces)
                        {
                            CalculateCollisionForces(this, other, otherGhost, ref otherPositionOffset, ref otherNewVelocity, ref otherNewNetForces); //, false);
                        }

                        if (other is Projectile)
                        {
                            HasCollided.AddKeyIfMissing(GetHashCode());
                        }
                    }

                    if (thisCollidesWithOther && thisApplyCollisionForces)
                    {
                        if (ghost != null) //This is null if the instance is a planet or the Gunman (the only Farseer bodies)
                        {
                            PhysicalBody.LinearVelocity = thisNewVelocity;
                            PhysicalBody.Position      += thisPositionOffset;
                            UpdateCollisionRectangle();

                            //normally, would do me.NetForces = newNetForces but need to hack so projectiles don't recollide with large bosses
                            if (!PhysicalBody.IsStatic && !other.PhysicalBody.IsStatic &&
                                (CollisionRectangle.Width >= 150 || other.CollisionRectangle.Width >= 150))
                            {
                                if (!ProjectileHasCollidedWithBoss)
                                {
                                    ghost.NetForces = thisNewNetForces;
                                }
                                //to prevent recollision, if colliding with 'boss' (i.e. large nonstatic mob), disable all further
                                //collisions WITH BOSSES ONLY (don't hack collision algorithm for cases involving small mobs)
                                ProjectileHasCollidedWithBoss = true;
                            }
                            else
                            {
                                ghost.NetForces = thisNewNetForces;
                            }
                        }
                    }

                    if (otherCollidesWithThis && otherApplyCollisionForces)
                    {
                        if (otherGhost != null) //This is null if the instance is a planet or the Gunman (the only Farseer bodies)
                        {
                            other.PhysicalBody.LinearVelocity = otherNewVelocity;
                            other.PhysicalBody.Position      += otherPositionOffset;
                            other.UpdateCollisionRectangle();

                            //normally, would do me.NetForces = newNetForces but need to hack so projectiles don't recollide with large bosses
                            if (!PhysicalBody.IsStatic && !other.PhysicalBody.IsStatic &&
                                (CollisionRectangle.Width >= 150 || other.CollisionRectangle.Width >= 150))
                            {
                                if (!other.ProjectileHasCollidedWithBoss)
                                {
                                    otherGhost.NetForces = otherNewNetForces;
                                }
                                //to prevent recollision, if colliding with 'boss' (i.e. large nonstatic mob), disable all further
                                //collisions WITH BOSSES ONLY (don't hack collision algorithm for cases involving small mobs)
                                other.ProjectileHasCollidedWithBoss = true;
                            }
                            else
                            {
                                otherGhost.NetForces = otherNewNetForces;
                            }
                        }
                    }

                    //Once the first mob handles the collision, we do not try again with the other mob
                    AlreadyCollided.Add(other);
                    //other.AlreadyCollided.Add(this); <- for whatever reason, this breaks collisions with ShardSkimmers. Handle with care
                }
            }
        }