using arrays for drawing multiple balls

Started by
10 comments, last by Bruno Filip 8 years, 4 months ago

Hy everyone I have been trying to figure this out, to create a new ball if X is pressed,

this is the farrest I went and I just don't know how to do this, when I run it it loads but when I press X error says:

An unhandled exception of type 'System.NullReferenceException' occurred in First.exe <-----------------------


 ball[count].Update();

So here is my code:

Game1.cs


public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Sprite backgnd;
        Item[] ball;
        int count = 0;
        int x = 80;
        int y = 80;
        
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
            graphics.PreferredBackBufferHeight = 600;
            graphics.PreferredBackBufferWidth = 750;
       }

        protected override void Initialize()
        {

            ball = new Item[5];
            base.Initialize();
        }


        protected override void LoadContent()
        {

            spriteBatch = new SpriteBatch(GraphicsDevice);
            backgnd = new Background(Content.Load<Texture2D>("map"), new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height));
            
            if (count <= 4)
            {
                ball[count] = new Item(Content.Load<Texture2D>("ball"), new Rectangle(x, y, 80, 80), new bool());
            }
        }

       
        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
// ------------------------------------------------------------------------------------------------------------XXXXX
            if (Keyboard.GetState().IsKeyDown(Keys.X))
            {
                ball[count].Check1 = true;
                count++;
            }
         
            ball[count].Update();
            base.Update(gameTime);
        }
        
  protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
           
            spriteBatch.Begin();
            backgnd.Draw(spriteBatch);
            if (ball[count].Check1 == true)
            {
                foreach (Item count in ball)
                {
                    count.Draw(spriteBatch);
                    y += 90;
                    x += 90;
                }
           }
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }

Sprite class:


namespace First
{
    class Sprite
    {
        public Texture2D texturee;
        public Rectangle rectan;
        public bool Check1;

        public virtual void Update()
        {

        }

        public void Draw(SpriteBatch spriteBatch)
        {
            spriteBatch.Draw(texturee, rectan, Color.White);
        }

        
    }


    // ---------------------------------------------------------------------Background
    class Background : Sprite
    {
        public Background(Texture2D newTexture, Rectangle newRectangle)
        {
            texturee = newTexture;
            rectan = newRectangle;
        }
    }



    // ----------------------------------------------------------------------Item
    class Item : Sprite
    {
        

        public Item(Texture2D newTexture, Rectangle newRectangle, bool newCheck)
        {
            Check1 = newCheck;
            texturee = newTexture;
            rectan = newRectangle;
        }

        public override void Update()
        {
            if (Keyboard.GetState().IsKeyDown(Keys.Right) && Check1 == true)
            {
                rectan.X += 2;
            }

            if(Keyboard.GetState().IsKeyDown(Keys.Left) && Check1 == true)
            {
                rectan.X -= 2;
            }

            
        }
    }
}

Thanks in advanced!

Advertisement

You aren't initializing the ball[] array properly I think..


            if (count <= 4)
            {
                ball[count] = new Item(Content.Load<Texture2D>("ball"), new Rectangle(x, y, 80, 80), new bool());
            }

- Shouldn't you do this for every ball[], or at least when you register the X?


            if (Keyboard.GetState().IsKeyDown(Keys.X))
            {
                ball[count].Check1 = true;
                count++;
            }

Here you increment count, but you aren't calling your LoadContent() and whatever else is needed, therefore the ball[count] after this segment is uninitialized and something will surely fail when updating or drawing. In your LoadContent() you only init ball[0] (count is 0 to begin with), if you call LoadContent only at the program startup. So either call LoadContent() every time you increment count, or make it loop through your entire array to setup all of the ball in advance. :)
Also, you might want to test for (count < 4) before doing a count++ or it will overflow quickly (your array is only a size of 5 as far as I can tell)..

.:vinterberg:.

This is what I did:


if (Keyboard.GetState().IsKeyDown(Keys.X))
            {
                ball[count].Check1 = true;
                count++;
                LoadContent();
            }

It runs but when I press X it crashes and:

http://oi66.tinypic.com/2lclqfl.jpg

What are you trying to do? It looks like you want to spawn a new ball every frame while the X key is being held down. Is that your intention?

In that case, you need to use a List instead of a fixed array, which is resizes when you add items to it.

Why do you have a count member variable anyway? What purpose does it serve? Arrays know their sizes (so do Lists).

Im trying to spawn a ball, move it around, then press X again to draw another on the screen, then I would move it too and then press X again to spawn another one.

I triend using count so I won't have to type 5 lines of code in Load Content, just one, and to idk it seemed logical to use it in arrays when Im not sure if I will spawn 2 balls or 4


I triend using count so I won't have to type 5 lines of code in Load Content

That's what for-loops are for.

At any rate, your code is check for a key being held down, not a key being pressed and released. https://msdn.microsoft.com/en-us/library/bb203902.aspx?f=255&MSPPError=-2147217396


It runs but when I press X it crashes and:

You need to check for "count < 5" too (you didn't check for out of bounds before doing a count++), when you press X you will spawn many balls (see what phil_t wrote). If you hold down X, you will spawn a ball every 1/60 second and your 5 balls maximum is reached within milliseconds, because you aren't checking for a release before allowing for a new pressed check. The link phil_t wrote is really helpful :D

.:vinterberg:.

Alright so I've done what you guys have told me, here is Game1.cs now:


using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;


namespace First
{  


    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Sprite backgnd;
        Item[] ball;
        int count = 0;
        int x = 80;
        int y = 80;
        KeyboardState oldState;


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


        protected override void Initialize()
        {


            ball = new Item[5];
            base.Initialize();
            oldState = Keyboard.GetState();
        }




        protected override void LoadContent()
        {


            spriteBatch = new SpriteBatch(GraphicsDevice);
            backgnd = new Background(Content.Load<Texture2D>("map"), new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height));
            
            if (count < 5)
            {
                ball[count] = new Item(Content.Load<Texture2D>("ball"), new Rectangle(x, y, 80, 80), new bool());
            }
        }


       
        protected override void UnloadContent()
        {
        }


        protected override void Update(GameTime gameTime)
        {
            KeyboardState newState = Keyboard.GetState();
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
// ------------------------------------------------------------------------------------------------------------XXXXX
            if (newState.IsKeyDown(Keys.X))
            {
                if (!oldState.IsKeyDown(Keys.X))
                {
                    ball[count].Check1 = true;
                    count++;
                    LoadContent();
                }
            }


            ball[count].Update();
            base.Update(gameTime);
        }
        
  protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
           
            spriteBatch.Begin();
            backgnd.Draw(spriteBatch);
            if (ball[count].Check1 == true)
            {
                foreach (Item count in ball)
                {
                    count.Draw(spriteBatch);
                    y += 90;
                    x += 90;
                }
           }
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}

But I still have the same problem after pressing X (screenshot of a problem 5 posts above)

Looked at your code again, see some problems still:

In your LoadContent() you load spritebatch+backgnd every time, secondly your LoadContent() initializes ball[count] with a new Item(..) (didn't notice this before) and the ball[] array is already created in your Initialize() with a "ball = new Item[5];" .. Also, in your Draw() you do a "if (ball[count].Check1 == true)" which will check ball[5] (out of bounds!!!!!!) when all 5 balls are spawned..

Try calling LoadContent() from your Initialize() and make it initialize the entire array, remove it from the Update() and in your Draw() you need to do a "for int i = 0; i < count; i++" loop and inside the loop you check for the "if (ball.Check1 == true)".

I'm not sure what this does in C# (I'm a C++ man myself), but it seems like you're overwriting your count variable with a new one???? -> "count.Draw(spriteBatch);" ... count is an int, so how can you call Draw() on it? Shouldn't it be the ball[] array?

.:vinterberg:.

Okay, now when I press X, first ball spawns, then after idk 250 miliseconds spawns 2nd one ( 90 pixels on the right, cause x += 90), and then after 250 ms spawns the 3rd one, again 180 pixels right, or maybe 270 (idk why, cause x += 90)), and then It crashes down again, even though it crashes, my wish is to first spawn 1 ball, and then if X is pressed again then spawn the 2nd, and so on


using System;
using System.Collections.Generic;
using System.Linq;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Audio;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.GamerServices;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.Media;

namespace First
{  

    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        Sprite backgnd;
        Item[] ball;
        int count = 0;
        int x = 80;
        int y = 80;
        KeyboardState oldState;

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

        protected override void Initialize()
        {

            ball = new Item[5];
            base.Initialize();
            oldState = Keyboard.GetState();
            LoadContent();
        }


        protected override void LoadContent()
        {

            spriteBatch = new SpriteBatch(GraphicsDevice);
            backgnd = new Background(Content.Load<Texture2D>("map"), new Rectangle(0, 0, GraphicsDevice.Viewport.Width, GraphicsDevice.Viewport.Height));
            
            if (count < 5)
            {
                ball[count] = new Item(Content.Load<Texture2D>("ball"), new Rectangle(x, y, 80, 80), new bool());
            }
        }

       
        protected override void UnloadContent()
        {
        }

        protected override void Update(GameTime gameTime)
        {
            KeyboardState newState = Keyboard.GetState();
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();
// ------------------------------------------------------------------------------------------------------------XXXXX
            if (newState.IsKeyDown(Keys.X))
            {
                if (!oldState.IsKeyDown(Keys.X))
                {
                    ball[count].Check1 = true;
                    count++;
                    LoadContent();
                }
            }

            ball[count].Update();
            base.Update(gameTime);
        }
        
  protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.CornflowerBlue);
           
            spriteBatch.Begin();
            backgnd.Draw(spriteBatch);
            for (int i = 0; i < count; i++)
            {
                if (ball[i].Check1 == true)
                {
                    ball[i].Draw(spriteBatch);
                    x += 90;
                }
           }
            spriteBatch.End();
            base.Draw(gameTime);
        }
    }
}

This topic is closed to new replies.

Advertisement