XNA — исключение Null Reference при создании текстуры

Мне нужно, чтобы мой спрайт стрелял каждый раз, когда я нажимаю пробел. Я почти уверен, что создал текстуру и нарисовал ее (внутри своего класса проигрывателя), но каждый раз, когда она считывает bulletTexture.width, она всегда возвращает ноль. Я надеюсь, что Some1 может мне помочь.

Вот полное изложение моего кода:

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
    }
}

Унаследован от SpriteManager (для его анимации), вот класс SpriteManager:

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
    }
}

Я «рисую» свою текстуру пули каждый раз, когда она вызывается в player.cs в функции Attack(). Вот мой класс пули:

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
    }
}

Ошибка вылетает каждый раз на player.cs, на cb.pos = new Vector2(this.pos.X - cb.bulletTexture.Width / 2, this.pos.Y + 15);. Из отладчика я почти уверен, что cb.bulletTexture НЕ равен нулю, но его ширина возвращает значение null.

Я надеюсь, что кто-то может помочь мне здесь, спасибо.


person user2002495    schedule 11.07.2013    source источник


Ответы (1)


Вы инициализируете новый CommonBullet в каждом Attack(), однако вы не вызываете метод LoadContent() для загрузки изображения.

Это можно легко исправить, добавив вызов LoadContent

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

Тем не менее, как правило, не рекомендуется постоянно загружать новое изображение, особенно если это изображение игры, в этом нет смысла.

Вы должны сделать переменную static в CommonBullet

статическая Texture2D BulletTexture;

Вы также должны сделать свой метод LoadContent static, и вместо способа, описанного выше (называя его каждой атакой), вы должны зайти в свой основной файл Game, найти его метод LoadContent и добавить эту строку:

CommonBullet.LoadContent(this.ContentManager);

Или вы могли бы просто сделать CommonBullet.BulletTexture = Content.Load<Texture2D>("Blah");

person Cyral    schedule 11.07.2013
comment
Как можно использовать/получить доступ к статической переменной в основном файле игры? Edit Более конкретно, поскольку мне нужно знать ширину и высоту текстуры пули в классе игрока (см. player.cs), как Могу ли я узнать это, если он статичен? Пожалуйста, не поймите меня неправильно, я очень ценю помощь. Редактировать В настоящее время я заставляю его работать, если я изменю ширину и высоту текстуры пули на 8 пикселей (размер изображения ), но я чувствую, что это не совсем решение (поскольку изображение пули может измениться в будущем) - person user2002495; 11.07.2013
comment
Что ж, статическая текстура означает, что к ней можно получить доступ из любого класса с помощью CommonBullet.BulletTexture, чтобы получить размеры, то же самое, CommonBullet.BulletTexture.Width - person Cyral; 11.07.2013