Search code examples
xnanullreferenceexceptiontexture2d

XNA - Null Reference Exception When Creating Texture


I need to make my sprite shoot each time i presses space. I'm pretty sure I've created the texture and draw it (inside my player class), but every time it was reading bulletTexture.width it always returns null. I hope some1 can help me.

Here's a complete rundown of my code:

Player.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Input;

namespace SpaceShooter_Beta.Animation.PlayerCollection
{
    public class Player : SpriteManager
    {
        #region Field Region

        public bool isAnimating = false, isDirectional = false;
        private float loadTime = 0.05f, shootDelay, bulletDelay, timeElapsed;
        public float speed;
        public List<CommonBullet> commonBulletList;
        public int bulletCap = 20;

        KeyboardState kbs;

        #endregion

        #region Property Region

        public int fps
        {
            set { loadTime = (1f / value); }
        }

        #endregion

        #region Constructor Region

        public Player(Texture2D texture, int frame, int animations) :
            base(texture, frame, animations)
        {
            speed = 2f;
            shootDelay = 5f;

            this.AddAnimation("down", 1);
            this.AddAnimation("up", 2);
            this.AddAnimation("right", 3);
            this.AddAnimation("left", 4);
            this.AddAnimation("upright", 5);
            this.AddAnimation("upleft", 6);
            this.AddAnimation("downright", 7);
            this.AddAnimation("downleft", 8);

            commonBulletList = new List<CommonBullet>();
            bulletDelay = 5f;
        }

        public void Update(GameTime gt)
        {
            timeElapsed += (float)gt.ElapsedGameTime.TotalSeconds;

            if (!this.isAnimating)
            {
                if (timeElapsed > loadTime)
                {
                    timeElapsed -= loadTime;
                    if (frameIndex == rects.Length - 1) this.isAnimating = false;
                    else frameIndex++;
                }
            }

            kbs = Keyboard.GetState();
            GetMovement();
            if (kbs.IsKeyDown(Keys.Space)) Attack();
            UpdateBullet();
        }

        #endregion

        #region Method Region

        private void GetMovement()
        {
            if (kbs.IsKeyDown(Keys.W))
            {
                this.pos.Y -= speed;
                this.animation = "up";

                if (kbs.IsKeyDown(Keys.D))
                {
                    if (!isDirectional)
                    {
                        frameIndex = 0;
                        isDirectional = true;
                    }
                    this.pos.X += speed;
                    this.animation = "upright";
                }
                else if (kbs.IsKeyDown(Keys.A))
                {
                    if (!isDirectional)
                    {
                        frameIndex = 0;
                        isDirectional = true;
                    }
                    this.pos.X -= speed;
                    this.animation = "upleft";
                }

                if (!this.isAnimating) this.isAnimating = true;
                else this.isAnimating = false;
            }
            else if (kbs.IsKeyDown(Keys.S))
            {
                this.pos.Y += speed;
                this.animation = "down";

                if (kbs.IsKeyDown(Keys.D))
                {
                    if (!isDirectional)
                    {
                        frameIndex = 0;
                        isDirectional = true;
                    }
                    this.pos.X += speed;
                    this.animation = "downright";
                }
                else if (kbs.IsKeyDown(Keys.A))
                {
                    if (!isDirectional)
                    {
                        frameIndex = 0;
                        isDirectional = true;
                    }
                    this.pos.X -= speed;
                    this.animation = "downleft";
                }

                if (!this.isAnimating) this.isAnimating = true;
                else this.isAnimating = false;
            }
            else if (kbs.IsKeyDown(Keys.A))
            {
                this.pos.X -= speed;
                this.animation = "left";
                if (!this.isAnimating) this.isAnimating = true;
                else this.isAnimating = false;
            }
            else if (kbs.IsKeyDown(Keys.D))
            {
                this.pos.X += speed;
                this.animation = "right";
                if (!this.isAnimating) this.isAnimating = true;
                else this.isAnimating = false;
            }
            else
            {
                this.isAnimating = false;
                this.isDirectional = false;
                frameIndex = 0;
            }

            if (this.pos.X <= 0) this.pos.X = 0;
            if (this.pos.X >= (800 - this.width)) this.pos.X = 800 - this.width;
            if (this.pos.Y <= 0) this.pos.Y = 0;
            if (this.pos.Y >= (600 - this.height)) this.pos.Y = 600 - this.height;
        }
        private void Attack()
        {
            if (bulletDelay > 0) bulletDelay--;
            if (bulletDelay <= 0)
            {
                CommonBullet cb = new CommonBullet();
                if(cb.bulletTexture.Width > 0)
                {
                    Console.WriteLine("this");
                    return;
                }
                cb.pos = new Vector2(this.pos.X - cb.bulletTexture.Width / 2, this.pos.Y + 15);
                cb.hasFired = true;
                if (commonBulletList.Count < bulletCap) commonBulletList.Add(cb);
                bulletDelay = 0;
            }
            if (bulletDelay == 0) bulletDelay = shootDelay;
        }
        private void UpdateBullet()
        {
            foreach (CommonBullet cb in commonBulletList)
            {
                cb.box = new Rectangle((int)cb.pos.X, (int)cb.pos.Y, cb.bulletTexture.Width, cb.bulletTexture.Height);
                cb.pos.Y -= cb.bulletSpeed;
                if (cb.pos.Y < 0) cb.hasFired = false;
            }

            for (int i = 0; i < commonBulletList.Count; i++)
            {
                if (!commonBulletList[i].hasFired)
                {
                    commonBulletList.RemoveAt(i);
                    i--;
                }
            }
        }

        public void Draw(SpriteBatch sb)
        {
            sb.Draw(texture, pos, animations[animation][frameIndex], Color.White, rot, ori, s, se, 0f);
            foreach (CommonBullet cb in commonBulletList)
            {
                cb.Draw(sb);
            }
        }
        #endregion
    }
}

Inherits from SpriteManager(for its animation), here is SpriteManager class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace SpaceShooter_Beta
{
    public class SpriteManager
    {
        #region Field Region

        protected Texture2D texture;
        protected Rectangle[] rects;
        protected int frameIndex = 0, frames;
        protected Dictionary<string, Rectangle[]> animations = new Dictionary<string, Rectangle[]>();

        public Vector2 pos, ori;
        public float rot = 0f, s= 1f;
        public SpriteEffects se;
        public string animation;
        public int width, height;

        #endregion

        #region Property Region
        #endregion

        #region Constructor Region

        public SpriteManager(Texture2D texture, int frame, int animation)
        {
            this.texture = texture;
            this.frames = frame;

            rects = new Rectangle[frame];
            for (int i = 0; i < frame; i++)
            {
                rects[i] = new Rectangle(i * width, 0, width, texture.Height);
            }

            width = texture.Width / frame;
            height = texture.Height / animation;
        }

        #endregion

        #region Method Region

        public void AddAnimation(string name, int row)
        {
            Rectangle[] rects = new Rectangle[frames];
            for (int i = 0; i < frames; i++)
            {
                rects[i] = new Rectangle(i * width, (row - 1) * height, width, height);
            }
            animations.Add(name, rects);
        }

        #endregion
    }
}

I "draw" my bullet texture every time its called in player.cs in Attack() function. Here is my bullet class:

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;
using Microsoft.Xna.Framework.Content;

namespace SpaceShooter_Beta.Animation.PlayerCollection
{
    public class CommonBullet
    {
        #region Field Region

        public float bulletSpeed = 5f;
        public double bulletDamage;
        public Texture2D bulletTexture;
        public Vector2 pos, ori;
        public bool hasFired;
        public Rectangle box;

        #endregion

        #region Property Region
        #endregion

        #region Constructor Region

        public CommonBullet()
        {
            hasFired = false;
        }

        #endregion

        #region Method Region

        public void Draw(SpriteBatch sb)
        {
            sb.Draw(bulletTexture, pos, Color.White);
        }

        public void LoadContent(ContentManager Content)
        {
            bulletTexture = Content.Load<Texture2D>(@"playerbullet");
        }

        #endregion
    }
}

The error throws everytime at player.cs, at cb.pos = new Vector2(this.pos.X - cb.bulletTexture.Width / 2, this.pos.Y + 15);. From the debugger, I'm pretty sure cb.bulletTexture is NOT null, but it's width returns null.

I hope someone can help me here, thanks.


Solution

  • You are initializing a new CommonBullet in every Attack() however, you are not calling the LoadContent() method to load the image.

    This could easily be fixed by adding the LoadContent call

    CommonBullet cb = new CommonBullet();
    cb.LoadContent(your content manager)
    

    However, it is generally not a good idea to load a new image all the time, especially if it is the game image, there is no point.

    You should make a static variable in CommonBullet

    static Texture2D BulletTexture;

    You should also make your LoadContent method static, and instead of the way above (calling it each attack) you should go into your main Game file, and find it's LoadContent method, and add this line:

    CommonBullet.LoadContent(this.ContentManager);
    

    Or you could just do CommonBullet.BulletTexture = Content.Load<Texture2D>("Blah");