XNA: Need help spawning enemies on any side, on a timer tick, then maving them move randomly

StackOverflow https://stackoverflow.com/questions/22721875

  •  23-06-2023
  •  | 
  •  

Domanda

Ok so I am making a 2d shooting game in XNA and have hit a bit of a snag. I am trying to make an enemy class that will allow me to spawn an enemy just off screen every 10 seconds, then have it move randomly in either up, right left or down. After spending the better part of 4 hours scouring the internet all I have found is examples making the enemy move one direction, spawn from one point and so on.

Any help would be much appreciated, my enemy class is a bit of a mess at the minute from dragging together so much code to try and make it work. Here it is as it stands:

using Microsoft.Xna.Framework;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Shark_Wars_2
{
    class Enemy
    {
        List<Vector2> sharkPosition = new List<Vector2>(); //is there a better way for having more than one of the same enemy?
        public Vector2 sharkDirection;

        public int sharkWidth;
        public int sharkHeight;

        public int sharkSpeed;

        float sharkSpawnProbability;

        public Random randomSharkPosition;
        public Random direction;

        double timer = 0;
        float interval = 1000;
        int speed = 1;

        public Enemy()
        {
            sharkPosition = new Vector2(0, 0); //brings up error - see above

            sharkWidth = 64;
            sharkHeight = 44;

            sharkSpeed = 3;

            sharkSpawnProbability = 1 / 10000f;

            randomSharkPosition = new Random(3); //left, right, up, down
            direction = new Random(3);

        }

        public void update(GameTime gameTime)
        {
            //enemy movement
            for (int i = 0; i < sharkPosition.Count; i++)
            {
                //enemy position increases by speed
                sharkPosition[i] = new Vector2(sharkPosition[i].X + sharkDirection.X, sharkPosition[i].Y + sharkDirection.Y);
            }

            timer += gameTime.ElapsedGameTime.TotalMilliseconds;

            //aniamtion
            if (timer >= interval / speed)
            {
                timer = 0;
            }

            //spawn new enemy
            if (randomSharkPosition.NextDouble() < sharkSpawnProbability)
            {
                float spawn = (float)randomSharkPosition.NextDouble() * (1280 - sharkHeight); sharkPosition.Add(new Vector2(sharkDirection.X, sharkDirection.Y));
            }
        }

        // ill worry about drawing after spawning and movement, should be no problem
        public void draw()//(SpriteBatch spritebatch, Texture2D wave)
        {
            for (int i = 0; i < sharkPosition.Count; i++)
            {
                //spritebatch.Draw(shark, new Rectangle((int)sharkPosition[i].X, (int)sharkPosition[i].Y, sharkWidth, sharkHeight);
            }
        }
    }
}

my head is really blocked, I spent a lot of time working out how to make moving background objects and a list of bullets.

I would really like to simplify this down too so if you know of an easier way of doing things I am all ears!

Thanks in advance!

È stato utile?

Soluzione

Your basic problem is that you haven't separated your managment/logic class from your instance objects. You want more separation, like this:

public class EnemyManager
{
   List<Shark> activeSharks = new List<Shark>();
   Timer spawnTimer;

   //Just one random instance per class, this is considered best practice to improve
   //the randomness of the generated numbers
   Random rng = new Random(); //Don't use a specific seed, that reduces randomness!

   public EnemyManager()
   {
      //Min/max time for the next enemy to appear, in milliseconds
      spawnTimer = new Timer(rng.Next(500, 2000));
      spawnTimer.Elapsed += SpawnShark;
      spawnTimer.Start();
   }

   public void SpawnShark(object sender, ElapasedEventArgs e)
   {
       Vector2 newSharkPosition = Vector2.Zero;
       newSharkPosition.X = rng.Next(0, 1280); //Whatever parameters you want    
       newSharkPosition.Y = rng.Next(0, 1280); //Whatever parameters you want    

       Vector2 newSharkDirection.... //Repeat above for direction

       Shark spawnedShark = new Shark(newSharkPosition, newSharkDirection);
       activeSharks.Add(spawnedShark);

       //Min/max time for the next enemy to appear, in milliseconds
      spawnTimer = new Timer(rng.Next(500, 2000));
   }

   public void update(GameTime gameTime)
   {
      foreach(Shark s in activeSharks)
        s.Update(gameTime);
   }

   public void draw(SpriteBatch spritebatch, Texture2D wave)
   {
      foreach(Shark s in activeSharks)
        s.Draw(spritebatch, wave)
   }
}

public class Shark
{
    Vector2 position;
    Vector2 direction;
    const float speed = 3;
    const int height = 44;
    const int width = 64;

    public Shark(Vector3 initPosition, Vector3 direction)
    {
        position = initPosition;
        this.direction = direction;
    }

    //Draw/Update using the local variables.
}

Obviously I didn't write all the code, but that should get you started. First I took all the "instance" specific data and put it into its own object, then the "manager" just holds and manages a collection of these objects. I also refactored the RNG to only have one instance (best practice) and to use the default time-based seed. Seeding it yourself will cause the numbers to come out the same each time you run the program (probably not what you were going for :) ).

Let me know if you don't understand something or I can provide any further assistance!

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top