문제

Hey guys I really need some help here my spriteBatch keeps returning a NullReference Exception and I don't know what I am doing wrong!? (I am making a brickbreaker game) and whenever my bricks are created inside Game1.cs it works fine but when I move it to Wall.cs (which is where I want to display a pattern of bricks) the game just crashes and gives a NullReference exception. Heres my code:

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 BrickBreaker
{
    /// <summary>
    /// This is the main type for your game
    /// </summary>
    public class Game1 : Microsoft.Xna.Framework.Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;
        private Paddle paddle;
        private Ball ball;
        private Texture2D background;
        private static int screenWidth = 750;
        private static int screenHeight = 600;
        private int leftBorder = 20;
        private int rightBorder = 28;
        private int topBorder = 20;
        private readonly int normalBrickResist = 2;
        private readonly int normalBrickPoints = 10;
        private Wall wall;

        //DELETE this shit
        private Brick brick;

        /// <summary>
        /// Contructor for the Game1 class.
        /// </summary>
        public Game1()
        {
            graphics = new GraphicsDeviceManager(this);
            Content.RootDirectory = "Content";
        }


        /// <summary>
        /// Read only property for the screen height.
        /// </summary>
        public static int ScreenHeight
        {
            get { return screenHeight; }
        }

        /// <summary>
        /// Read only property for the screen width.
        /// </summary>
        public static int ScreenWidth
        {
            get { return screenWidth; }
        }

        /// <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()
        {
            graphics.PreferredBackBufferHeight = screenHeight;
            graphics.PreferredBackBufferWidth = screenWidth;
            graphics.ApplyChanges();

            paddle = new Paddle(this);
            Components.Add(paddle);

            wall = new Wall(this);
            Components.Add(wall);

            ball = new Ball(this, paddle, leftBorder, rightBorder, topBorder, brick);
            Components.Add(ball);

            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()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            background = Content.Load<Texture2D>("background");
        }

        /// <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();

            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();
            Vector2 position = new Vector2(0, 0);
            spriteBatch.Draw(background, position, Color.White);
            spriteBatch.End();

            base.Draw(gameTime);
        }

        public void RemoveComponent(IGameComponent obj)
        {
            this.Components.Remove(obj);
        }
    }
}

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 BrickBreaker
{

    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class Wall : Microsoft.Xna.Framework.DrawableGameComponent
    {
        private Brick brick;
        private Brick[,] brickLayout = new Brick[5, 8];
        private Game game;
        SpriteBatch spriteBatch;
        private Texture2D brickImg;

        public Wall(Game game)
            : base(game)
        {
            this.game = game;
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Draw(GameTime gameTime)
        {
            foreach (var item in brickLayout)
            {
                if (item != null)
                {
                    item.Draw(gameTime);
                }

            }

            base.Draw(gameTime);
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            foreach (Brick item in brickLayout)
            {
                item.Update(gameTime);
            }

            base.Update(gameTime);
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here
            foreach (var item in brickLayout)
            {
                if (item != null)
                {
                    item.Initialize();
                }
            }
            base.Initialize();
        }

        protected override void LoadContent()
        {

            int x = 0;
            int y = 0;
            Vector2 startPosition;
            for (int i = 0; i < brickLayout.GetLength(0); i++)
            {
                for (int j = 0; j < brickLayout.GetLength(1); j++)
                {
                    startPosition = new Vector2(x, y);
                    brickLayout[i, j] = new Brick(game, 20, 1, startPosition);
                    x += 20;
                }
                y += 20;
            }

            base.LoadContent();
        }
    }
}

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 BrickBreaker
{
    /// <summary>
    /// This is a game component that implements IUpdateable.
    /// </summary>
    public class Brick : Microsoft.Xna.Framework.DrawableGameComponent
    {
        enum brickType
        {
            Regular1,
            Regular2,
            Regular3,
            Regular4,
            Regular5,
            PowerUp,
            Unbreakable
        }

        private Texture2D brick;
        private SpriteBatch spriteBatch;
        private Game game;
        private int brickValue;
        private Vector2 startPosition, position;
        private Rectangle collisionBox;
        private int brickWidth;
        private bool isBroken = false;
        private int resistance;

        public Brick(Game game, int brickValue, int resistance, Vector2 startPosition)
            : base(game)
        {
            this.brickValue = brickValue;
            this.game = game;
            this.resistance = resistance;
            this.startPosition = startPosition;
        }

        public Boolean IsBroken
        {
            get
            {
                return this.isBroken;
            }
            set
            {
                this.isBroken = value;
            }
        }

        /// <summary>
        /// Property for the paddle collision box.
        /// </summary>
        public Rectangle CollisionBox
        {
            get { return collisionBox; }
        }


        /// <summary>
        /// Read only property for the paddle width.
        /// </summary>
        public int BrickWidth
        {
            get { return brickWidth; }
        }

        /// <summary>
        /// Allows the game component to perform any initialization it needs to before starting
        /// to run.  This is where it can query for any required services and load content.
        /// </summary>
        public override void Initialize()
        {
            // TODO: Add your initialization code here

            base.Initialize();
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Update(GameTime gameTime)
        {
            // TODO: Add your update code here

            base.Update(gameTime);
        }

        /// <summary>
        /// Allows the game component to update itself.
        /// </summary>
        /// <param name="gameTime">Provides a snapshot of timing values.</param>
        public override void Draw(GameTime gameTime)
        {

            if (isBroken == false)
            {
                spriteBatch.Begin();
                spriteBatch.Draw(brick, this.position, Color.White);
                spriteBatch.End();
            }


            base.Draw(gameTime);
        }

        /// <summary>
        /// Comment
        /// </summary>
        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);
            brick = game.Content.Load<Texture2D>("brick");

            collisionBox = new Rectangle(0, 0, brick.Width, brick.Height);

            position = startPosition;
            collisionBox.X = (int)position.X;
            collisionBox.Y = (int)position.Y;

            base.LoadContent();
        }

        public void TakeHit()
        {
            resistance--;

            if (resistance == 0)
                IsBroken = true;

        }

    }
}

Edit: Fixed the old problem by adding this in wall.cs

   for (int i = 0; i < brickLayout.GetLength(0); i++)
    {
        for (int j = 0; j < brickLayout.GetLength(1); j++)
        {
            startPosition = new Vector2(x, y);
            brickLayout[i, j] = new Brick(game, 20, 1, startPosition);
            //Added this line:
            brickLayout[i, j].Initialize();
            x += 45;
        }
        x = 150;
        y += 25;
    }

BUT now the collision box isn't working at all.

도움이 되었습니까?

해결책 2

It's giving NullReferenceException in the Brick class at the SpriteBatch.Begin() line in the Draw method.

다른 팁

Look closer at your Brick class. In your wall class you're not initializing spriteBatch, and you're not calling Begin and End

Your LoadContent method needs this:

spriteBatch = new SpriteBatch(GraphicsDevice);

And you need to be sure to call this is your Draw method:

spriteBatch.Begin();

and

spriteBatch.End();

EDIT: You're never calling LoadContent on your brick class which is why spriteBatch never gets initialized. Try:

    protected override void LoadContent()
    {

        int x = 0;
        int y = 0;
        Vector2 startPosition;
        for (int i = 0; i < brickLayout.GetLength(0); i++)
        {
            for (int j = 0; j < brickLayout.GetLength(1); j++)
            {
                startPosition = new Vector2(x, y);
                brickLayout[i, j] = new Brick(game, 20, 1, startPosition);
                // This new line...
                brickLayout[i, j].LoadContent();
                x += 20;
            }
            y += 20;
        }

        base.LoadContent();
    }
라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top