1
votes

Sorry about all of the code, but I am completely new to Visual C# and XNA.

This program is out of Learning XNA 4.0 by Aaron Reed. My professor modified some of the stuff its supposed to do (the book covers some of this but not all of it). Most of the code is copied from the book.

These are the minimum requirements for the finished product:

  1. You may use any 2 images in place of 3 Rings and Skull ball (or you can still use the same if you wish) – one is a player (3 Rings) and the other is a participant (also called an enemy)
  2. The player sprite can move only using the Arrow Keys (Mouse is not activated)
  3. The participant sprites are automated they move freely (randomly if you wish) and they bounce off the boundaries (in any manner you choose to)
  4. At the beginning of the game there are 1 player and 5 participant sprites
  5. The game lasts for exactly 120 seconds, at the end of the game if the player sprite has destroyed all the participant (enemy sprites) on the screen print a message indicating the player wins; otherwise print a message that the player loses
  6. Every 10 seconds a new incarnation of an enemy sprite emerges at any location
  7. The player sprite can destroy an enemy sprite only when it collides AND the “A” key is pressed at the same time. If the “A” key is pressed without a collision then 2 incarnations of the enemy occurs
  8. The enemy sprites must move at a reasonable speed (not very slow I mean) for the game to be meaningful
  9. You need to have some sounds in your program – a background sound that always plays, a sound that plays when an enemy is destroyed, a different sound when the player fires but the enemy does not get destroyed because there was no collision, a sound when a new enemy emerges (every 10 seconds)

I'm trying to make the enemies (skullballs) evade the player (threerings) but the enemies either don't respond on all sides (the player is on the right or left and the enemy doesn't evade until the player is above or below), and when the enemies do evade, they disappear offscreen shaking (they just suddenly go straight up or down and they're shaking rapidly.

When the new enemy spawns after 10 seconds, starting from the top-left corner, it bounces off the bottom wall and then disappears offscreen when it goes back up.

The skull also doesn't spawn randomly around the screen after 10 seconds.

Also I don't know how to make 2 more enemies spawn when the A button is pressed with no collision.

SpriteManager.cs

namespace Assignment_2
{
    public class SpriteManager : Microsoft.Xna.Framework.DrawableGameComponent
    {
        //SpriteBatch for drawing
        SpriteBatch spriteBatch;

        //A sprite for the player and a list of automated sprites
        UserControlledSprite player;
        List<Sprite> spriteList = new List<Sprite>();

        int enemySpawnMinMilliseconds = 10000;
        int enemySpawnMaxMilliseconds = 10000;
        int enemyMinSpeed = 10;
        int enemyMaxSpeed = 10;
        int nextSpawnTime = 0;

        public SpriteManager(Game game)
            : base(game)
        {
            // TODO: Construct any child components here
        }

        public override void Initialize()
        {
            // TODO: Add your initialization code here
            ResetSpawnTime();
            base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(Game.GraphicsDevice);

            //Load the player sprite
            player = new UserControlledSprite(
                Game.Content.Load<Texture2D>(@"Images/threerings"),
                Vector2.Zero, new Point(75, 75), 10, new Point(0, 0),
                new Point(6, 8), new Vector2(6, 6));

            //Load several different automated sprites into the list to test
            //spriteList.Add(new AutomatedSprite(
            //    Game.Content.Load<Texture2D>(@"Images/skullball"),
            //    new Vector2(150, 150), new Point(75, 75), 10, new Point(0, 0),
            //    new Point(6, 8), new Vector2(3, 0), "skullcollision"));
            //spriteList.Add(new AutomatedSprite(
            //    Game.Content.Load<Texture2D>(@"Images/skullball"),
            //    new Vector2(300, 150), new Point(75, 75), 10, new Point(0, 0),
            //    new Point(6, 8), new Vector2(-2, 0), "skullcollision"));
            ////spriteList.Add(new AutomatedSprite(
            ////    Game.Content.Load<Texture2D>(@"Images/skullball"),
            ////    new Vector2(150, 300), new Point(75, 75), 10, new Point(0, 0),
            ////    new Point(6, 8), new Vector2(3, 4), "skullcollision"));
            ////spriteList.Add(new AutomatedSprite(
            ////    Game.Content.Load<Texture2D>(@"Images/skullball"),
            ////    new Vector2(300, 400), new Point(75, 75), 10, new Point(0, 0),
            ////    new Point(6, 8), new Vector2(0, -3), "skullcollision"));
            ////spriteList.Add(new AutomatedSprite(
            ////    Game.Content.Load<Texture2D>(@"Images/skullball"),
            ////    new Vector2(200, 300), new Point(75, 75), 10, new Point(0, 0),
            ////    new Point(6, 8), new Vector2(-3, 7), "skullcollision"));
            spriteList.Add(new EvadingSprite(
                Game.Content.Load<Texture2D>(@"Images/skullball"),
                new Vector2(150, 150), new Point(75, 75), 10, new Point(0, 0),
                new Point(6, 8), new Vector2(3, 0), "skullcollision", this, .75f, 150));
            spriteList.Add(new EvadingSprite(
                Game.Content.Load<Texture2D>(@"Images/skullball"),
                new Vector2(300, 150), new Point(75, 75), 10, new Point(0, 0),
                new Point(6, 8), new Vector2(-2, 0), "skullcollision", this, .75f, 150));
            spriteList.Add(new EvadingSprite(
                Game.Content.Load<Texture2D>(@"Images/skullball"),
                new Vector2(150, 300), new Point(75, 75), 10, new Point(0, 0),
                new Point(6, 8), new Vector2(3, 4), "skullcollision", this, .75f, 150));
            spriteList.Add(new EvadingSprite(
                Game.Content.Load<Texture2D>(@"Images/skullball"),
                new Vector2(300, 400), new Point(75, 75), 10, new Point(0, 0),
                new Point(6, 8), new Vector2(0, -3), "skullcollision", this, .75f, 150));
            spriteList.Add(new EvadingSprite(
                Game.Content.Load<Texture2D>(@"Images/skullball"),
                new Vector2(200, 300), new Point(75, 75), 10, new Point(0, 0),
                new Point(6, 8), new Vector2(-3, 7), "skullcollision", this, .75f, 150));
            base.LoadContent();
        }

        public override void Update(GameTime gameTime)
        {
            nextSpawnTime -= gameTime.ElapsedGameTime.Milliseconds;
            if (nextSpawnTime < 0)
            {
                SpawnEnemy();

                //reset spawn timer
                ResetSpawnTime();
            }
            // Update player
            player.Update(gameTime, Game.Window.ClientBounds);

            // Update all sprites
            for (int i = 0; i < spriteList.Count; ++i)
            {
                Sprite s = spriteList[i];

                s.Update(gameTime, Game.Window.ClientBounds);

                // Check for collisions
                if (s.collisionRect.Intersects(player.collisionRect) && (Keyboard.GetState().IsKeyDown(Keys.A)))
                {
                    // Play collision sound
                    if (s.collisionCueName != null)
                        ((Game1)Game).PlayCue(s.collisionCueName);

                    // Remove collided sprite from the game
                    spriteList.RemoveAt(i);
                    --i;
                }
            }

            base.Update(gameTime);
        }

        public override void Draw(GameTime gameTime)
        {
            spriteBatch.Begin(SpriteSortMode.FrontToBack, BlendState.AlphaBlend);

            // Draw the player
            player.Draw(gameTime, spriteBatch);

            // Draw all sprites
            foreach (Sprite s in spriteList)
                s.Draw(gameTime, spriteBatch);

            spriteBatch.End();
            base.Draw(gameTime);
        }
        // Return current position of the player sprite
        public Vector2 GetPlayerPosition()
        {
            return player.GetPosition;
        }

        private void SpawnEnemy()
        {
            Vector2 speed = Vector2.Zero;
            Vector2 position = Vector2.Zero;

            // Default frame size
            Point frameSize = new Point(75, 75);
            // Create the sprite. NOTE: This sprite bounces off the bottom wall then goes back and disappears offscreen
            spriteList.Add(
                new EvadingSprite(Game.Content.Load<Texture2D>(@"images\skullball"),
                position, new Point(75, 75), 10, new Point(0, 0),
                new Point(6, 8), new Vector2(3, 4), "skullcollision", this, .75f, 150)); 

        }

         private void ResetSpawnTime()
         {
             nextSpawnTime = ((Game1)Game).rnd.Next(
             enemySpawnMinMilliseconds,
             enemySpawnMaxMilliseconds);
         }
    }
}

EvadingSprite

class EvadingSprite : Sprite
{
    // Save a reference to the sprite manager to
    // use to get the player position
    SpriteManager spriteManager;

    // Variables to delay evasion until player is close 
    float evasionSpeedModifier;
    int evasionRange;
    bool evade = false;

    public EvadingSprite(Texture2D textureImage, Vector2 position,
        Point frameSize, int collisionOffset, Point currentFrame,
        Point sheetSize, Vector2 speed, string collisionCueName,
        SpriteManager spriteManager, float evasionSpeedModifier,
        int evasionRange)
        : base(textureImage, position, frameSize, collisionOffset,
        currentFrame, sheetSize, speed, collisionCueName)
    {
        this.spriteManager = spriteManager;
        this.evasionSpeedModifier = evasionSpeedModifier;
        this.evasionRange = evasionRange;
    }

    public EvadingSprite(Texture2D textureImage, Vector2 position,
        Point frameSize, int collisionOffset, Point currentFrame,
        Point sheetSize, Vector2 speed, int millisecondsPerFrame,
        string collisionCueName, SpriteManager spriteManager,
        float evasionSpeedModifier, int evasionRange)
        : base(textureImage, position, frameSize, collisionOffset,
        currentFrame, sheetSize, speed, millisecondsPerFrame,
        collisionCueName)
    {
        this.spriteManager = spriteManager;
        this.evasionSpeedModifier = evasionSpeedModifier;
        this.evasionRange = evasionRange;
    }

    public override Vector2 direction
    {
        get { return speed; }
    }

    public override void Update(GameTime gameTime, Rectangle clientBounds)
    {
        // First, move the sprite along its direction vector
        position += speed;

        // Use the player position to move the sprite closer in
        // the X and/or Y directions
        Vector2 player = spriteManager.GetPlayerPosition();

        if (evade)
        {
            // Move away from the player horizontally
            if (player.X < position.Y)
                position.X += Math.Abs(speed.Y);
            else if (player.X > position.X)
                position.X -= Math.Abs(speed.Y);

            // Move away from the player vertically
            if (player.Y < position.Y)
                position.Y += Math.Abs(speed.X);
            else if (player.Y > position.Y)
                position.Y -= Math.Abs(speed.X);

        }
        else
        {
            if (Vector2.Distance(position, player) < evasionRange)
            {
                // Player is within evasion range,
                // reverse direction and modify speed
                speed *= -evasionSpeedModifier;
                evade = true;
            }
        }

        //make them bounce off walls
        if (position.X > clientBounds.Width - frameSize.X ||
            position.X < 0)
            speed *= -1;

        if (position.Y > clientBounds.Height - frameSize.Y ||
            position.Y < 0)
            speed *= -1;
        base.Update(gameTime, clientBounds);
    }
}
1
I think your question is to broad and contains way to much code. Please be specific and clear where you are having problems and what the end result should be like. "I'm trying to make sprites evade." is not very informative. Where is the evade code? What are you planning on doing? etc.Measuring
@Measuring I cut it down a bit. Is it clearer now?user3313728
Yes, it's better now. So in the update of the enemy there seems to be a possible loop where you set the evade = true you never actually set it to false (this would also makes sense because you see enemies shaking). Have you tried debugging that part?Measuring
@Measuring If you mean to hit F5, then yes I tried that (I already have bool evade = false as a class variable, and when I put that at the top of the update method, the skulls just stopped in place). If not, then how do you debug specific parts. Another problem I have is when the new sprite spawns after 10 seconds, starting from the top-left corner, it bounces off the bottom wall and then disappears offscreen when it goes back up.user3313728
You can use breakpoints and Debug.Listeners, Debug.WriteLine to output information at (for example) the evade logic. As for your second issue, I would take 1 issue at a time. Solve one, maybe it solves more issues with your code. Take some time and go step by step. (Search interweb for using breakpoints).Measuring

1 Answers

1
votes

For your collision code:

    if (position.Y > clientBounds.Height - frameSize.Y ||
        position.Y < 0)
        speed *= -1;

You are telling the sprite to go only go up. Basically when it hits -1 on the y its moving in the positive direction until it goes positive in which case its moving negative. So you keep switching between positive and negative off screen. My recommendation would be to split those statements up into two, that way when your not evading you are accurately bouncing off the walls.

    if (position.X > clientBounds.Width - frameSize.X)
        speed *= -1;
    else if (position.X<=0)
        speed*=1;
    if (position.Y > ClientBounds.Height - frameSize.Y)
          speed *= -1;
    else if(position.Y > 0)
          speed *= 1;