Search code examples
c#arraysxnadraw

XNA drawing and creating an array of objects


Hi all I am trying to create a game, and right now, I have a balloon class, which I want to currently create an amount of them via an array, and then draw then into the game.

Currently however it seems it is either only creating one instance of balloon or only drawing 1 instance. I'v looked over it multiple times, and from what I understand it should be looping through the entire array size (currently set at 10) and creating that many balloons, then updating and drawing that many.

Are you not able to do what I am currently doing with an array? Would I have to create each object sparately?

Here is the code of the two classes concerned.

GameLevel: The class that creates the onjects and draws them.

        public partial class GameLevel : GameScreen
        {
            SpriteBatch spriteBatch;
            protected Game game;

            Texture2D balloonTexture;

            Balloon[] balloons = new Balloon[10];

            public GameLevel(Game game, SpriteBatch spriteBatch)
                : base(game, spriteBatch)
            {
                this.game = game;
                this.spriteBatch = spriteBatch;
            }

            public void LoadContent()
            {

                for (int i = 0; i < balloons.Length; i++)
                {



                    int colour;
                    Random random = new Random();


                    colour = random.Next(1, 6);

                    switch (colour)
                    {
                        case 1: balloonTexture = Game.Content.Load<Texture2D>("Images/BlueBalloon");
                            break;
                        case 2: balloonTexture = Game.Content.Load<Texture2D>("Images/RedBalloon");
                            break;
                        case 3: balloonTexture = Game.Content.Load<Texture2D>("Images/YellowBalloon");
                            break;
                        case 4: balloonTexture = Game.Content.Load<Texture2D>("Images/GreenBalloon");
                            break;
                        case 5: balloonTexture = Game.Content.Load<Texture2D>("Images/PurpleBalloon");
                            break;
                    }
                    balloons[i] = new Balloon(new Rectangle(0, 0, 1152, 648), balloonTexture);
                    balloons[i].SetStartPosition();
                }
            }

            public void Update()
            {

                for (int i = 0; i < balloons.Length; i++)
                {
                    balloons[i].Update();
                }


            }



            public override void Draw(GameTime gameTime)
            {
                for (int i = 0; i < balloons.Length; i++)
                {

                    balloons[i].Draw(spriteBatch);
                }

                base.Draw(gameTime);
            }
        }
    }

Ballon Class:

    public class Balloon
    {

        Vector2 position;
        Vector2 motion;   
        Rectangle bounds;
        Rectangle screenBounds;
        public Texture2D texture;
        float balloonSpeed = 4;

        public Balloon(Rectangle screenBounds, Texture2D texture)     
        {       
            this.texture = texture;
            this.screenBounds = screenBounds;
        }

        public Rectangle Bounds
        {
            get
            {
                bounds.X = (int)position.X;
                bounds.Y = (int)position.Y;
                return bounds;
            }
        }


        public void Update()
        {
            position += motion * balloonSpeed;
        }

        private void CheckWallColision()
        {
            if (position.X < 0)
            {
                position.X = 0;
                motion.X *= -1;
            }

            if (position.X + texture.Width > screenBounds.Width)
            {
                position.X = screenBounds.Width - texture.Width;
                motion.X *= -1;
            }

            if (position.Y < 0)
            {
                position.Y = 0;
                motion.Y *= -1;
            }

            if (position.Y + texture.Height > screenBounds.Height)
            {

                position.Y = screenBounds.Height - texture.Height;
                motion.Y *= -1;
            }
        }

        public void SetStartPosition()
        {
            Random rand = new Random();

            motion = new Vector2(rand.Next(2, 6), -rand.Next(2, 6));
            motion.Normalize();

            position = new Vector2(rand.Next(100, 500), rand.Next(100, 500));

        }


        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(texture, position, Color.White);

        }
    }
}

Solution

  • I believe the reason this is occurring is related to the way the Random object works. When one is constructed, it uses as its seed (from which it will generate all values) the system clock. This means that, if you generate numerous Random instances at the same time, every single one of them will return the same series of values. If you're using these values for positions, every single one of your objects will have the same position, and will be drawn over each other. In your case, because they're all the same size, it looks like only one was ever drawn.

    To fix this, create a single instance of Random and just use Next() on that single instance whenever you need a new position.

    Personally, I consider this a pretty significant design flaw - it doesn't seem amazingly intuitive that a series of Random objects created at the same time will be "random" in the exact same way. But: this is a good example of the fact that "random" values created by C#, and any other language, will in fact be pseudo-random, and when it comes to pseudo-randomness, implementation is very important.