0

I am trying to get a list of sprite objects to move randomly across the screen in short linear movements (up, down , left, right). The sprites move randomly, but they all move the same as each other (e.g all move left, all move right, etc), apart from one which moves separately. I want them all to move independently to each other. Code below -

 namespace game2
{
/// <summary>
/// This is the main type for your game
/// </summary>
public class Game1 : Microsoft.Xna.Framework.Game
{
    GraphicsDeviceManager graphics;
    SpriteBatch spriteBatch;

    /// <summary>
    /// Sprite
    /// </summary>
    List<Sprite> spriteList;
    Sprite tempSprite;
    private int spriteNum;


    /// <summary>
    /// General
    /// </summary>
    Random random;
    int randomNum;
    Rectangle viewPort;

    public Game1()
    {
        graphics = new GraphicsDeviceManager(this);
        Content.RootDirectory = "Content";
    }

    /// <summary>
    /// Allows the game to perform any initialization it needs to before starting to run.
    /// This is where it can query for any required services and load any non-graphic
    /// related content.  Calling base.Initialize will enumerate through any components
    /// and initialize them as well.
    /// </summary>
    protected override void Initialize()
    {
        // TODO: Add your initialization logic here

        //Initialize Sprites
        spriteList = new List<Sprite>();
        spriteNum = 4;

        for (int i = 0; i < spriteNum; i++)  //Load in as many sprites as spriteNum specifies
        {
            tempSprite = new Sprite();
            spriteList.Add(tempSprite);      //add in sprites to list       
        }

        //initialise random
        random = new Random();

        //initialise viewport
        viewPort = new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height);

        base.Initialize();
    }

    /// <summary>
    /// LoadContent will be called once per game and is the place to load
    /// all of your content.
    /// </summary>
    protected override void LoadContent()
    {
        // Create a new SpriteBatch, which can be used to draw textures.
        spriteBatch = new SpriteBatch(GraphicsDevice);

        foreach (Sprite s in spriteList)                    //for each sprite in spriteList, load content by passing in Game1's content
        {

            s.LoadContent(this.Content, viewPort, "square");
            s.Position = new Vector2(random.Next(0, viewPort.Width), random.Next(0, viewPort.Height));
        }

        // TODO: use this.Content to load your game content here
    }

    /// <summary>
    /// UnloadContent will be called once per game and is the place to unload
    /// all content.
    /// </summary>
    protected override void UnloadContent()
    {
        // TODO: Unload any non ContentManager content here
    }

    /// <summary>
    /// Allows the game to run logic such as updating the world,
    /// checking for collisions, gathering input, and playing audio.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    protected override void Update(GameTime gameTime)
    {
        // Allows the game to exit
        if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
            this.Exit();



        //update sprites

        foreach (Sprite s in spriteList)
        {

            s.Update(gameTime);
        }
        // TODO: Add your update logic here

        base.Update(gameTime);
    }

    /// <summary>
    /// This is called when the game should draw itself.
    /// </summary>
    /// <param name="gameTime">Provides a snapshot of timing values.</param>
    protected override void Draw(GameTime gameTime)
    {
        GraphicsDevice.Clear(Color.CornflowerBlue);


        spriteBatch.Begin();


        foreach (Sprite s in spriteList)
        {
            s.Draw(this.spriteBatch);
        }


        spriteBatch.End();
        // TODO: Add your drawing code here

        base.Draw(gameTime);
    }
}
}

And here is the sprite class -

namespace game2
 {
class Sprite
{
    //Movement
    public Vector2 Position = new Vector2(0,0);
    private float counter = 0f;
    private float range = 100f;
    private Random random;
    public int randomNum;

    //Properties
    private Texture2D mSpriteTexture;

    //General
    private Rectangle viewPort;

    public void LoadContent(ContentManager theContentManager, Rectangle tempViewport, string asset)
    {
        random = new Random();

        viewPort = tempViewport;

        mSpriteTexture = theContentManager.Load<Texture2D>(asset);
    }

    public void Update(GameTime gameTime)
    {

        if (randomNum == 0)
        {

            if (Position.X + mSpriteTexture.Width < viewPort.Width && counter <= range)
            {
                    Position.X++;
                    counter++;
            }

            else
            {
                randomNum = random.Next(0, 4);
                counter = 0;

            }
        }

        if (randomNum == 1)
        {

            if (Position.X > viewPort.X && counter <= range)
            {
                Position.X--;
                counter++;
            }
            else
            {
                randomNum = random.Next(0, 4);
                counter = 0;

            }

        }

        if (randomNum == 2)
        {

            if (counter <= range)
            {
                Position.Y++;
                counter++;
            }
            else
            {
                randomNum = random.Next(0, 4);
                counter = 0;

            }

        }

        if (randomNum == 3)
        {

            if (counter <= range)
            {
                Position.Y--;
                counter++;
            }
            else
            {
                randomNum = random.Next(0, 4);
                counter = 0;

            }
        }
    }

    public void Draw(SpriteBatch theSpriteBatch)
    {
        theSpriteBatch.Draw(mSpriteTexture, Position, Color.White);
    }
}
}
Jonny Holmes
  • 161
  • 1
  • 14
  • possible duplicate of ["new Random(x)" always generates the same numbers?](http://stackoverflow.com/questions/10239346/new-randomx-always-generates-the-same-numbers) – Adriano Carneiro Jul 09 '14 at 17:40

1 Answers1

1

You are loading all the sprites very quickly in LoadContent normally, this isn't a problem, but each one has its own Random class.

Because of this, many are getting identical seeds (similar to the problem you see when instantiating Random in a for or while loop). RNGs with the same seed will produce the same sequence of values, thus causing the behavior you are seeing.

Passing a single Random instance to all objects that use it should cause your problem to go away.

BradleyDotNET
  • 60,462
  • 10
  • 96
  • 117
  • I just tried getting rid of random = new Random() in the Sprite class's LoadContent method and instead creating the new random in the properties of the Sprite Class only. This still doesn't work. Maybe it's because I am calling random.Next(0,4) within the 'if' loops for the movement, and the same problem is occurring there. – Jonny Holmes Jul 09 '14 at 17:51
  • Same problem. Can you pass the `Random` instance from the `Game` class on the `Sprite` class's constructor? – BradleyDotNET Jul 09 '14 at 17:52
  • If you need a global RNG, it is not a bad idea to implement a `static Random Rng = new Random()` – David Jul 09 '14 at 18:38
  • thanks for the help guys but none of these have worked, I tried passing the Random instance from the game class but I think because I have a 'foreach' loop loading in the content including the random the problem still occurs. – Jonny Holmes Jul 09 '14 at 20:55
  • You'll have to post your updated code, but I don't see anything else wrong off the top of my head. – BradleyDotNET Jul 09 '14 at 21:05
  • I solved it guys! What I did was I created a list of type Random in the game1 class and did foreach(sprite s in spriteList){random = new Random() then randomList.Add(random)}. THen passed it to the sprite and worked with that! – Jonny Holmes Jul 09 '14 at 21:12
  • Clearly you were doing what we suggested wrong then, as a single instance would have worked just as well (if not better). Glad you got ti working though. – BradleyDotNET Jul 09 '14 at 21:14