/// <summary>
        /// Defines the interaction between this power-up and a target actor
        /// when they touch.
        /// </summary>
        /// <param name="target">The actor that is touching this object.</param>
        /// <returns>True if the objects meaningfully interacted.</returns>
        public override bool Touch(Actor target)
        {
            // if we hit a ship, give it the weapon
            Ship ship = target as Ship;
            if (ship != null)
            {
                ship.SetWeapon(new RocketWeapon(ship));
            }

            return base.Touch(target);
        }
        /// <summary>
        /// Damages all actors in a radius around the mine.
        /// </summary>
        /// <param name="touchedActor">The actor that was originally hit.</param>
        public override void Explode(Actor touchedActor)
        {
            // play the explosion cue
            world.AudioManager.PlayCue("explosionLarge");

            // add a double-particle system effect
            world.ParticleSystems.Add(new ParticleSystem(this.position,
                Vector2.Zero, 64, 32f, 64f, 3f, 0.05f, explosionColors));
            world.ParticleSystems.Add(new ParticleSystem(this.position,
                Vector2.Zero, 16, 128f, 256f, 4f, 0.1f, explosionColors));

            base.Explode(touchedActor);
        }
 /// <summary>
 /// Defines the interaction between this projectile and a target actor
 /// when they touch.
 /// </summary>
 /// <param name="target">The actor that is touching this object.</param>
 /// <returns>True if the objects meaningfully interacted.</returns>
 public override bool Touch(Actor target)
 {
     // add a particle effect if we touched anything
     if (base.Touch(target))
     {
         // make the particle effect slightly more significant if it was a ship
         if (target is Ship)
         {
             world.ParticleSystems.Add(new ParticleSystem(this.position,
                 Vector2.Zero, 16, 32f, 64f, 1f, 0.1f, explosionColors));
         }
         else
         {
             world.ParticleSystems.Add(new ParticleSystem(this.position,
                 Vector2.Zero, 4, 32f, 64f, 1f, 0.05f, explosionColors));
         }
         return true;
     }
     return false;
 }
        /// <summary>
        /// Damages all actors in a radius around the rocket.
        /// </summary>
        /// <param name="touchedActor">The actor that was originally hit.</param>
        public override void Explode(Actor touchedActor)
        {
            // stop the rocket-flying cue
            if (rocketCue != null)
            {
                rocketCue.Stop(AudioStopOptions.Immediate);
                rocketCue.Dispose();
                rocketCue = null;
            }

            // play the explosion cue
            world.AudioManager.PlayCue("explosionMedium");

            // add a double-particle system effect
            world.ParticleSystems.Add(new ParticleSystem(this.position,
                Vector2.Zero, 64, 32f, 64f, 3f, 0.05f, explosionColors));
            world.ParticleSystems.Add(new ParticleSystem(this.position,
                Vector2.Zero, 16, 128f, 256f, 4f, 0.1f, explosionColors));

            base.Explode(touchedActor);
        }
 /// <summary>
 /// Defines the interaction between this actor and a target actor
 /// when they touch.
 /// </summary>
 /// <param name="target">The actor that is touching this object.</param>
 /// <returns>True if the objects meaningfully interacted.</returns>
 public virtual bool Touch(Actor target)
 {
     return true;
 }
 /// <summary>
 /// Kills this actor, in response to the given actor.
 /// </summary>
 /// <param name="source">The actor responsible for the kill.</param>
 public virtual void Die(Actor source)
 {
     if (dead == false)
     {
         // arrrggghhhh
         dead = true;
         // remove this actor from the world
         world.Actors.Garbage.Add(this);
     }
 }
 /// <summary>
 /// Damage this actor by the amount provided.
 /// </summary>
 /// <remarks>
 /// This function is provided in lieu of a Life mutation property to allow 
 /// classes of objects to restrict which kinds of objects may damage them,
 /// and under what circumstances they may be damaged.
 /// </remarks>
 /// <param name="source">The actor responsible for the damage.</param>
 /// <param name="damageAmount">The amount of damage.</param>
 /// <returns>If true, this object was damaged.</returns>
 public virtual bool Damage(Actor source, float damageAmount)
 {
     // reduce life by the given amound
     life -= damageAmount;
     // if life had gone below 0, then we're dead
     // -- 0 health actors are destroyed by any damage
     if (life < 0f)
     {
         Die(source);
     }
     return true;
 }
        /// <summary>
        /// Defines the interaction between this projectile and a target actor
        /// when they touch.
        /// </summary>
        /// <param name="target">The actor that is touching this object.</param>
        /// <returns>True if the objects meaningfully interacted.</returns>
        public override bool Touch(Actor target)
        {
            // check the target, if we have one
            if (target != null)
            {
                // don't bother hitting any power-ups
                if (target is PowerUp)
                {
                    return false;
                }
                // don't hit the owner if the damageOwner flag isn't set
                if ((target == owner) && (this.damageOwner == false))
                {
                    return false;
                }
                // don't hit other projectiles from the same ship
                Projectile projectile = target as Projectile;
                if ((projectile != null) && (projectile.Owner == this.Owner))
                {
                    return false;
                }
                // damage the target
                target.Damage(this, this.damageAmount);
            }

            // either we hit something or the target is null - in either case, die
            Die(target);

            return base.Touch(target);
        }
        /// <summary>
        /// Find a valid point for the actor to spawn.
        /// </summary>
        /// <param name="actor">The actor to find a location for.</param>
        /// <remarks>This query is not bounded, which would be needed in a more complex
        /// game with a likelihood of no valid spawn locations.</remarks>
        /// <returns>A valid location for the user to spawn.</returns>
        public Vector2 FindSpawnPoint(Actor actor)
        {
            if (actor == null)
            {
                throw new ArgumentNullException("actor");
            }

            Vector2 spawnPoint;
            float radius = actor.Radius;

            // fudge the radius slightly so we're not right on top of another actor
            if (actor is Ship)
            {
                radius *= 2f;
            }
            else
            {
                radius *= 1.1f;
            }
            radius = (float)Math.Ceiling(radius);

            Vector2 spawnMinimum = new Vector2(
                safeDimensions.X + radius,
                safeDimensions.Y + radius);
            Vector2 spawnDimensions = new Vector2(
                (float)Math.Floor(safeDimensions.Width - 2f * radius),
                (float)Math.Floor(safeDimensions.Height - 2f * radius));
            Vector2 spawnMaximum = spawnMinimum + spawnDimensions;

            Collision.CircleLineCollisionResult result =
                new Collision.CircleLineCollisionResult();
            bool valid = true;
            while (true)
            {
                valid = true;
                // generate a new spawn point
                spawnPoint = new Vector2(
                    spawnMinimum.X + spawnDimensions.X * (float)random.NextDouble(),
                    spawnMinimum.Y + spawnDimensions.Y * (float)random.NextDouble());
                if ((spawnPoint.X < spawnMinimum.X) ||
                    (spawnPoint.Y < spawnMinimum.Y) ||
                    (spawnPoint.X > spawnMaximum.X) ||
                    (spawnPoint.Y > spawnMaximum.Y))
                {
                    continue;
                }
                // if we don't collide, then one is good enough
                if (actor.Collidable == false)
                {
                    break;
                }
                // check against the walls
                if (valid == true)
                {
                    for (int wall = 0; wall < walls.Length / 2; wall++)
                    {
                        if (Collision.CircleLineCollide(spawnPoint, radius,
                            walls[wall * 2], walls[wall * 2 + 1], ref result))
                        {
                            valid = false;
                            break;
                        }
                    }
                }
                // check against all other actors
                if (valid == true)
                {
                    foreach (Actor checkActor in actors)
                    {
                        if ((actor == checkActor) || checkActor.Dead)
                        {
                            continue;
                        }
                        if (Collision.CircleCircleIntersect(checkActor.Position,
                            checkActor.Radius, spawnPoint, radius))
                        {
                            valid = false;
                            break;
                        }
                    }
                }
                // if we have gotten this far, then the spawn point is good
                if (valid == true)
                {
                    break;
                }
            }
            return spawnPoint;
        }
Exemple #10
0
        /// <summary>
        /// Kills this ship, in response to the given actor.
        /// </summary>
        /// <param name="source">The actor responsible for the kill.</param>
        public override void Die(Actor source)
        {
            if (dead == false)
            {
                // hit the gamepad vibration motors
                FireGamepadMotors(0.75f, 0.25f);
                // play several explosion cues
                world.AudioManager.PlayCue("playerDeath");
                // add several particle systems for effect
                world.ParticleSystems.Add(new ParticleSystem(this.position,
                    Vector2.Zero, 128, 64f, 256f, 3f, 0.05f, explosionColors));
                world.ParticleSystems.Add(new ParticleSystem(this.position,
                    Vector2.Zero, 64, 256f, 1024f, 3f, 0.05f, explosionColors));
                // reset the respawning timer
                respawnTimer = respawnTimerOnDeath;

                // change the score
                Ship ship = source as Ship;
                if (ship == null)
                {
                    Projectile projectile = source as Projectile;
                    if (projectile != null)
                    {
                        ship = projectile.Owner;
                    }
                }
                if (ship != null)
                {
                    if (ship == this)
                    {
                        // reduce the score, since i blew myself up
                        ship.Score--;
                    }
                    else
                    {
                        // add score to the ship who shot this object
                        ship.Score++;
                    }
                }
                else
                {
                    // if it wasn't a ship, then this object loses score
                    this.Score--;
                }

                // ships should not be added to the garbage list, so just set dead
                dead = true;
            }
        }
 /// <summary>
 /// Damage this asteroid by the amount provided.
 /// </summary>
 /// <remarks>
 /// This function is provided in lieu of a Life mutation property to allow 
 /// classes of objects to restrict which kinds of objects may damage them,
 /// and under what circumstances they may be damaged.
 /// </remarks>
 /// <param name="source">The actor responsible for the damage.</param>
 /// <param name="damageAmount">The amount of damage.</param>
 /// <returns>If true, this object was damaged.</returns>
 public override bool Damage(Actor source, float damageAmount)
 {
     // nothing hurst asteroids, nothing!
     return false;
 }
        /// <summary>
        /// Defines the interaction between the asteroid and a target actor
        /// when they touch.
        /// </summary>
        /// <param name="target">The actor that is touching this object.</param>
        /// <returns>True if the objects meaningfully interacted.</returns>
        public override bool Touch(Actor target)
        {
            // if the asteroid has touched a player, then damage it
            Ship player = target as Ship;
            if (player != null)
            {
                // calculate damage as a function of how much the two actor's
                // velocities were going towards one another
                Vector2 playerAsteroidVector =
                    Vector2.Normalize(this.position - player.Position);
                float rammingSpeed =
                    Vector2.Dot(playerAsteroidVector, player.Velocity) -
                    Vector2.Dot(playerAsteroidVector, this.velocity);
                player.Damage(this, this.mass * rammingSpeed * damageScalar);

            }
            // if the asteroid didn't hit a projectile, play the asteroid-touch cue
            if ((target is Projectile) == false)
            {
                this.world.AudioManager.PlayCue("asteroidTouch");
            }
            return base.Touch(target);
        }
 /// <summary>
 /// Damage this power-up by the amount provided.
 /// </summary>
 /// <remarks>
 /// Power-ups cannot be damaged.
 /// </remarks>
 /// <param name="source">The actor responsible for the damage.</param>
 /// <param name="damageAmount">The amount of damage.</param>
 /// <returns>If true, this object was damaged.</returns>
 public override bool Damage(Actor source, float damageAmount)
 {
     return false;
 }
        /// <summary>
        /// Defines the interaction between this power-up and a target actor
        /// when they touch.
        /// </summary>
        /// <param name="target">The actor that is touching this object.</param>
        /// <returns>True if the objects meaningfully interacted.</returns>
        public override bool Touch(Actor target)
        {
            // if it touched a ship, then create a particle system and play a sound
            Ship ship = target as Ship;
            if (ship != null)
            {
                // tickle the ship's vibration motors
                ship.FireGamepadMotors(0f, 0.25f);
                // add a particle system for effect
                world.ParticleSystems.Add(new ParticleSystem(this.Position,
                    Vector2.Zero, 24, 32f, 64f, 2f, 0.1f, particleColors));
                // play the "power-up picked up" cue
                world.AudioManager.PlayCue("powerUpTouch");
                // kill the power-up
                Die(target);
                return false;
            }

            return base.Touch(target);
        }
        /// <summary>
        /// Move the given actor by the given movement, colliding and adjusting
        /// as necessary.
        /// </summary>
        /// <param name="actor">The actor who is moving.</param>
        /// <param name="movement">The desired movement vector for this update.</param>
        /// <returns>The movement vector after considering all collisions.</returns>
        private Vector2 MoveAndCollide(Actor actor, Vector2 movement)
        {
            if (actor == null)
            {
                throw new ArgumentNullException("actor");
            }
            // make sure we care about where this actor goes
            if (actor.Dead || (actor.Collidable == false))
            {
                return movement;
            }
            // make sure the movement is significant
            if (movement.LengthSquared() <= 0f)
            {
                return movement;
            }

            // generate the list of collisions
            Collide(actor, movement);

            // determine if we had any collisions
            if (collisionResults.Count > 0)
            {
                collisionResults.Sort(CollisionResult.Compare);
                foreach (CollisionResult collision in collisionResults)
                {
                    // let the two actors touch each other, and see what happens
                    if (actor.Touch(collision.Actor) && collision.Actor.Touch(actor))
                    {
                        actor.CollidedThisFrame =
                            collision.Actor.CollidedThisFrame = true;
                        // they should react to the other, even if they just died
                        AdjustVelocities(actor, collision.Actor);
                        return Vector2.Zero;
                    }
                }
            }

            return movement;
        }
        /// <summary>
        /// Adjust the velocities of the two actors as if they have collided,
        /// distributing their velocities according to their masses.
        /// </summary>
        /// <param name="actor1">The first actor.</param>
        /// <param name="actor2">The second actor.</param>
        private static void AdjustVelocities(Actor actor1, Actor actor2)
        {
            // don't adjust velocities if at least one has negative mass
            if ((actor1.Mass <= 0f) || (actor2.Mass <= 0f))
            {
                return;
            }

            // determine the vectors normal and tangent to the collision
            Vector2 collisionNormal = Vector2.Normalize(
                actor2.Position - actor1.Position);
            Vector2 collisionTangent = new Vector2(
                -collisionNormal.Y, collisionNormal.X);

            // determine the velocity components along the normal and tangent vectors
            float velocityNormal1 = Vector2.Dot(actor1.Velocity, collisionNormal);
            float velocityTangent1 = Vector2.Dot(actor1.Velocity, collisionTangent);
            float velocityNormal2 = Vector2.Dot(actor2.Velocity, collisionNormal);
            float velocityTangent2 = Vector2.Dot(actor2.Velocity, collisionTangent);

            // determine the new velocities along the normal
            float velocityNormal1New = ((velocityNormal1 * (actor1.Mass - actor2.Mass))
                + (2f * actor2.Mass * velocityNormal2)) / (actor1.Mass + actor2.Mass);
            float velocityNormal2New = ((velocityNormal2 * (actor2.Mass - actor1.Mass))
                + (2f * actor1.Mass * velocityNormal1)) / (actor1.Mass + actor2.Mass);

            // determine the new total velocities
            actor1.Velocity = (velocityNormal1New * collisionNormal) +
                (velocityTangent1 * collisionTangent);
            actor2.Velocity = (velocityNormal2New * collisionNormal) +
                (velocityTangent2 * collisionTangent);
        }
Exemple #17
0
        /// <summary>
        /// Damage this ship by the amount provided.
        /// </summary>
        /// <remarks>
        /// This function is provided in lieu of a Life mutation property to allow 
        /// classes of objects to restrict which kinds of objects may damage them,
        /// and under what circumstances they may be damaged.
        /// </remarks>
        /// <param name="source">The actor responsible for the damage.</param>
        /// <param name="damageAmount">The amount of damage.</param>
        /// <returns>If true, this object was damaged.</returns>
        public override bool Damage(Actor source, float damageAmount)
        {
            // if the safe timer hasn't yet gone off, then the ship can't be hurt
            if (safeTimer > 0f)
            {
                return false;
            }

            // tickle the gamepad vibration motors
            FireGamepadMotors(0f, 0.25f);

            // once you're hit, the shield-recharge timer starts over
            shieldRechargeTimer = 2.5f;

            // damage the shield first, then life
            if (shield <= 0f)
            {
                life -= damageAmount;
            }
            else
            {
                shield -= damageAmount;
                if (shield < 0f)
                {
                    // shield has the overflow value as a negative value, just add it
                    life += shield;
                    shield = 0f;
                }
            }

            // if the ship is out of life, it dies
            if (life < 0f)
            {
                Die(source);
            }

            return true;
        }
 /// <summary>
 /// Kills this projectile, in response to the given actor.
 /// </summary>
 /// <param name="source">The actor responsible for the kill.</param>
 public override void Die(Actor source)
 {
     if (dead == false)
     {
         base.Die(source);
         if (dead && explodes)
         {
             Explode(source);
         }
     }
 }
 /// <summary>
 /// Damages all actors in a radius around the projectile.
 /// </summary>
 /// <param name="touchedActor">The actor that was originally hit.</param>
 public virtual void Explode(Actor touchedActor)
 {
     // if there is no radius, then don't bother
     if (damageRadius <= 0f)
     {
         return;
     }
     // check each actor for damage
     foreach (Actor actor in world.Actors)
     {
         // don't bother if it's already dead
         if (actor.Dead == true)
         {
             continue;
         }
         // don't hurt the actor that the projectile hit, it's already hurt
         if (actor == touchedActor)
         {
             continue;
         }
         // don't hit the owner if the damageOwner flag is off
         if ((actor == owner) && (damageOwner == false))
         {
             continue;
         }
         // measure the distance to the actor and see if it's in range
         float distance = (actor.Position - this.Position).Length();
         if (distance <= damageRadius)
         {
             // adjust the amount of damage based on the distance
             // -- note that damageRadius <= 0 is accounted for earlier
             float adjustedDamage = damageAmount *
                 (damageRadius - distance) / damageRadius;
             // if we're still damaging the actor, then go ahead and apply it
             if (adjustedDamage > 0f)
             {
                 actor.Damage(this, adjustedDamage);
             }
         }
     }
 }
        /// <summary>
        /// Determine all collisions that will happen as the given actor moves.
        /// </summary>
        /// <param name="actor">The actor that is moving.</param>
        /// <param name="movement">The actor's movement vector this update.</param>
        /// <remarks>The results are stored in the cached list.</remarks>
        public void Collide(Actor actor, Vector2 movement)
        {
            collisionResults.Clear();

            if (actor == null)
            {
                throw new ArgumentNullException("actor");
            }
            if (actor.Dead || (actor.Collidable == false))
            {
                return;
            }

            // determine the movement direction and scalar
            float movementLength = movement.Length();
            if (movementLength <= 0f)
            {
                return;
            }

            // check each actor
            foreach (Actor checkActor in actors)
            {
                if ((actor == checkActor) || checkActor.Dead || !checkActor.Collidable)
                {
                    continue;
                }

                // calculate the target vector
                Vector2 checkVector = checkActor.Position - actor.Position;
                float distanceBetween = checkVector.Length() -
                    (checkActor.Radius + actor.Radius);

                // check if they could possibly touch no matter the direction
                if (movementLength < distanceBetween)
                {
                    continue;
                }

                // determine how much of the movement is bringing the two together
                float movementTowards = Vector2.Dot(movement, checkVector);

                // check to see if the movement is away from each other
                if (movementTowards < 0f)
                {
                    continue;
                }

                if (movementTowards < distanceBetween)
                {
                    continue;
                }

                CollisionResult result = new CollisionResult();
                result.Distance = distanceBetween;
                result.Normal = Vector2.Normalize(checkVector);
                result.Actor = checkActor;

                collisionResults.Add(result);
            }
        }