【问题标题】:Difficulty loading a texture and passing it to a class in XNA 4.0难以加载纹理并将其传递给 XNA 4.0 中的类
【发布时间】:2014-09-03 21:55:39
【问题描述】:

这是一个 c#/XNA 4.0 类的作业,不,我不是 HWgrade-zombie。我会让你知道我问这个问题的情况,我做了多少“研究”,我希望学习而不是获得分数,但它会被认为是无用的并被删除。

无论如何,我遇到的问题是我试图加载到 Game1.cs 中的“textureImage”中的内容(精灵表),然后将其传递给“Sprite.cs”进行绘制,通过“userControlledSprite.cs”,当我编译我的程序时没有被绘制。作为 c# 和 XNA 的新手,我理解这个问题(内容加载,但没有正确传递),但我不知道如何解决它。

以下是我的程序包含的全部三个类:

Game1.cs -- 调用 userControlledSprite。

    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 Proj06
    {
        public class Game1 : Microsoft.Xna.Framework.Game
        {
           GraphicsDeviceManager graphics;
           SpriteBatch spriteBatch;

            static Texture2D textureImage;
            static Point frameSize = new Point(52,50);
            static Point currentFrame = new Point(0, 0);
            static Point sheetSize = new Point(4, 1);
            static Vector2 position = Vector2.Zero;
            static int collisionOffset = 1;
            static Vector2 speed;

           userControlledSprite UserControlledSprite1;


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

        protected override void Initialize()
        {
           base.Initialize();
        }

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            textureImage = Content.Load<Texture2D>(@"images/Picture");
            UserControlledSprite1 = new userControlledSprite(textureImage, position, frameSize, collisionOffset, currentFrame, sheetSize, speed);
        }

        protected override void UnloadContent()
        {
          /// Ignore this void
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                this.Exit();

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.White);
            UserControlledSprite1.Draw(gameTime, spriteBatch);
            base.Draw(gameTime);
        }
    }
}

Sprite.cs -- 绘制精灵并为其设置动画,以及检查碰撞。

    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 Proj06
    {
       abstract class Sprite
        {
            Texture2D textureImage;
            protected Point frameSize;
            Point currentFrame;
            Point sheetSize;
            int collisionOffset;
            int timeSinceLastFrame = 0;
            int millisecondsPerFrame;
            const int defaultMillisecondsPerFrame = 16;
            protected Vector2 speed;
            protected Vector2 position;

            public Sprite(Texture2D textureImage, Vector2 position, Point frameSize,
                int collisionOffset, Point currentFrame, Point sheetSize, Vector2 speed)
                : this(textureImage, position, frameSize, collisionOffset, currentFrame,
                sheetSize, speed, defaultMillisecondsPerFrame)
            {
            }

            public Sprite(Texture2D textureImage, Vector2 position, Point frameSize,
                int collisionOffset, Point currentFrame, Point sheetSize, Vector2 speed,
                int millisecondsPerFrame)
            {
                this.textureImage = textureImage;
                this.position = position;
                this.frameSize = frameSize;
                this.collisionOffset = collisionOffset;
                this.currentFrame = currentFrame;
                this.sheetSize = sheetSize;
                this.speed = speed;
                this.millisecondsPerFrame = millisecondsPerFrame;
            }

            public virtual void Update(GameTime gameTime, Rectangle clientBounds)
            {
                timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
                if (timeSinceLastFrame > millisecondsPerFrame)
                {
                    timeSinceLastFrame = 0;
                    ++currentFrame.X;
                    if (currentFrame.X >= sheetSize.X)
                    {
                        currentFrame.X = 0;
                        ++currentFrame.Y;
                        if (currentFrame.Y >= sheetSize.Y)
                        {
                            currentFrame.Y = 0;
                        }
                    }
                }
            }

            public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch)
            {
                spriteBatch.Begin();

                spriteBatch.Draw(textureImage,
                    position,
                    new Rectangle(currentFrame.X * frameSize.X,
                        currentFrame.Y * frameSize.Y,
                        frameSize.X, frameSize.Y),
                        Color.White, 0, Vector2.Zero,
                        1f, SpriteEffects.None, 0);

                spriteBatch.End();
            }

            public abstract Vector2 direction
            {
                get;
            }

            public Rectangle collisionRect
            {
                get
                {
                    return new Rectangle(
                        (int)position.X + collisionOffset,
                        (int)position.Y + collisionOffset,
                        frameSize.X - (collisionOffset * 2),
                        frameSize.Y - (collisionOffset * 2));
                }
            }
        }
    }

and userControlledSprite.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.Input;


    namespace Proj06
    {
        class userControlledSprite : Sprite
        {
            public userControlledSprite(Texture2D textureImage, Vector2 position,
                Point frameSize, int collisionOffset, Point currentFrame, Point sheetSize,
                Vector2 speed)
                : base(textureImage, position, frameSize, collisionOffset, currentFrame,
                sheetSize, speed)
            {
            }

            public userControlledSprite(Texture2D textureImage, Vector2 position,
                Point frameSize, int collisionOffset, Point currentFrame, Point sheetSize,
                Vector2 speed, int millisecondsPerFrame)
                : base(textureImage, position, frameSize, collisionOffset, currentFrame,
                sheetSize, speed, millisecondsPerFrame)
            {
            }

            public override Vector2 direction
            {
                get
                {
                    Vector2 inputDirection = Vector2.Zero;

                    if (Keyboard.GetState().IsKeyDown(Keys.Left))
                        inputDirection.X -= 1;
                    if (Keyboard.GetState().IsKeyDown(Keys.Right))
                        inputDirection.X += 1;
                    if (Keyboard.GetState().IsKeyDown(Keys.Up))
                        inputDirection.Y -= 1;
                    if (Keyboard.GetState().IsKeyDown(Keys.Down))
                        inputDirection.Y += 1;

                    return inputDirection * speed;
                }
            }

            public override void Update(GameTime gameTime, Rectangle clientBounds)
            {
                position += direction;

                if (position.X < 0)
                    position.X = 0;
                if (position.Y < 0)
                    position.Y = 0;
                if (position.X > clientBounds.Width - frameSize.X)
                    position.X = clientBounds.Width - frameSize.X;
                if (position.Y > clientBounds.Height - frameSize.Y)
                    position.X = clientBounds.Height - frameSize.Y;

                base.Update(gameTime, clientBounds);
            }
        }
    }

我将继续在线搜索任何有用的资源,如果我发现任何内容,我会发布编辑。感谢您的宝贵时间。

【问题讨论】:

  • 您没有从 Game1 类调用 draw 方法,并且 Sprite 也没有扩展 DrawableGameComponent(然后添加到 Game.Components)来注册您覆盖的绘制方法。你至少需要做其中一件事。看起来您还缺少 spriteBatch.Begin 和 spriteBatch.End 调用。在您的 Draw/Update 方法中设置断点以查看它们是否被调用。

标签: c# xna argument-passing


【解决方案1】:

将 UserControlledSprite1 的字段定义保留在原处,但不要在那里对其进行初始化:

public class Game1 : Microsoft.Xna.Framework.Game
{
    userControlledSprite UserControlledSprite1;
}

然后在加载纹理后立即在LoadContent()方法中初始化它:

protected override void LoadContent()
{
    spriteBatch = new SpriteBatch(GraphicsDevice);

    textureImage = Content.Load<Texture2D>(@"images/Picture");
    UserControlledSprite1 = new userControlledSprite(textureImage, position, frameSize, collisionOffset, currentFrame, sheetSize, speed);
}

另外,请确保您在 Game1.Draw() 中调用 UserControlledSprite1.Draw() 方法。

【讨论】:

  • 我按照您的建议编辑了我的代码,并将 gameTime 和 spriteBatch 作为 UserControlledSprite1.Draw() 方法的参数,并收到以下错误:Field 'Proj06.Game1.UserControlledSprite1 ' 永远不会分配给,并且将始终具有其默认值 null
  • @Newprgm 确保将我在上面添加的最后一行添加到您的 LoadContent() 方法中。
  • @Newprgm 你仍然需要在Game1.Draw() 中调用UserControlledSprite1.Draw(gameTime, spriteBatch) 就在GraphicsDevice.Clear(Color.White); 之后
  • 问题仍然是最新的(只是忘记在编辑帖子时添加该部分)。
【解决方案2】:

这里很简单,你的 DrawUpdate 方法永远不会被调用。

如果您希望它们被 XNA 自动调用,您的 Sprite 类需要扩展 DrawableGameComponent 并在 Game1 中注册。为此,您需要将Game 作为参数传递。您将覆盖的Draw 方法也需要SpriteBatch,因此也将它传递给构造函数。这不是一种真正干净的方法,但它会起作用。然后在您拥有的每个 DrawableGameComponent 上调用 Components.Add

完成后,只需在 Game1 中调用 spriteBatch.Begin() 和 spriteBatch.End()(对 Begin 和 End 只调用一次),然后每个 Sprite 将自行绘制。

我还冒昧地删除了无用的 usings 并修复了你的类名以适应 C# 约定 (PascalCase)。

改变的重要部分是:

  • userControlledSprite 现在接收 spriteBatch 和 Game 类
  • userControlledSprite 注册为组件
  • Sprite 现在扩展了 DrawableGameComponent
  • 现在调用 spriteBatch.Begin 和 End
  • Sprite 现在会覆盖正确的 Draw 方法。

请注意,我没有更改您的 Update 方法。除非您将其更改为 public override void Update(GameTime gameTime),否则它不会被调用。

如果你在 Draw 中设置断点,它应该被 XNA 调用。

Game1.cs

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

namespace Proj06
{
    public class Game1 : Game
    {
        GraphicsDeviceManager graphics;
        SpriteBatch spriteBatch;

        private Texture2D textureImage;
        private Point frameSize = new Point(52, 50);
        private Point currentFrame = new Point(0, 0);
        private Point sheetSize = new Point(4, 1);
        private Vector2 position = Vector2.Zero;
        private int collisionOffset = 1;
        private Vector2 speed;

        private UserControlledSprite userControlledSprite1;


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

        protected override void LoadContent()
        {
            spriteBatch = new SpriteBatch(GraphicsDevice);

            textureImage = Content.Load<Texture2D>(@"images/Picture");
            userControlledSprite1 = new UserControlledSprite(this, spriteBatch, textureImage, position, frameSize, collisionOffset, currentFrame, sheetSize, speed);
            Components.Add(userControlledSprite1);
        }

        protected override void Update(GameTime gameTime)
        {
            if (GamePad.GetState(PlayerIndex.One).Buttons.Back == ButtonState.Pressed)
                Exit();

            base.Update(gameTime);
        }

        protected override void Draw(GameTime gameTime)
        {
            GraphicsDevice.Clear(Color.White);

            spriteBatch.Begin();
            base.Draw(gameTime);
            spriteBatch.End();
        }
    }
}

UserControlledSprite.cs

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


namespace Proj06
{
    class UserControlledSprite : Sprite
    {
        public UserControlledSprite(Game game, SpriteBatch sb, Texture2D textureImage, Vector2 position,
            Point frameSize, int collisionOffset, Point currentFrame, Point sheetSize,
            Vector2 speed)
            : base(game, sb, textureImage, position, frameSize, collisionOffset, currentFrame,
            sheetSize, speed)
        {
        }

        public UserControlledSprite(Game game, SpriteBatch sb, Texture2D textureImage, Vector2 position,
            Point frameSize, int collisionOffset, Point currentFrame, Point sheetSize,
            Vector2 speed, int millisecondsPerFrame)
            : base(game, sb, textureImage, position, frameSize, collisionOffset, currentFrame,
            sheetSize, speed, millisecondsPerFrame)
        {
        }

        public override Vector2 direction
        {
            get
            {
                Vector2 inputDirection = Vector2.Zero;

                if (Keyboard.GetState().IsKeyDown(Keys.Left))
                    inputDirection.X -= 1;
                if (Keyboard.GetState().IsKeyDown(Keys.Right))
                    inputDirection.X += 1;
                if (Keyboard.GetState().IsKeyDown(Keys.Up))
                    inputDirection.Y -= 1;
                if (Keyboard.GetState().IsKeyDown(Keys.Down))
                    inputDirection.Y += 1;

                return inputDirection * speed;
            }
        }

        public override void Update(GameTime gameTime, Rectangle clientBounds)
        {
            position += direction;

            if (position.X < 0)
                position.X = 0;
            if (position.Y < 0)
                position.Y = 0;
            if (position.X > clientBounds.Width - frameSize.X)
                position.X = clientBounds.Width - frameSize.X;
            if (position.Y > clientBounds.Height - frameSize.Y)
                position.X = clientBounds.Height - frameSize.Y;

            base.Update(gameTime, clientBounds);
        }
    }
}

Sprite.cs

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

namespace Proj06
{
    abstract class Sprite : DrawableGameComponent
    {
        Texture2D textureImage;
        protected Point frameSize;
        Point currentFrame;
        Point sheetSize;
        int collisionOffset;
        int timeSinceLastFrame = 0;
        int millisecondsPerFrame;
        const int defaultMillisecondsPerFrame = 16;
        protected Vector2 speed;
        protected Vector2 position;
        private SpriteBatch spriteBatch;

        public Sprite(Game game, SpriteBatch sb, Texture2D textureImage, Vector2 position, Point frameSize,
            int collisionOffset, Point currentFrame, Point sheetSize, Vector2 speed)
            : this(game, sb, textureImage, position, frameSize, collisionOffset, currentFrame,
            sheetSize, speed, defaultMillisecondsPerFrame)
        {
        }

        public Sprite(Game game, SpriteBatch sb, Texture2D textureImage, Vector2 position, Point frameSize,
            int collisionOffset, Point currentFrame, Point sheetSize, Vector2 speed,
            int millisecondsPerFrame) : base(game)
        {
            this.textureImage = textureImage;
            this.position = position;
            this.frameSize = frameSize;
            this.collisionOffset = collisionOffset;
            this.currentFrame = currentFrame;
            this.sheetSize = sheetSize;
            this.speed = speed;
            this.millisecondsPerFrame = millisecondsPerFrame;
            spriteBatch = sb;
        }

        public virtual void Update(GameTime gameTime, Rectangle clientBounds)
        {
            timeSinceLastFrame += gameTime.ElapsedGameTime.Milliseconds;
            if (timeSinceLastFrame > millisecondsPerFrame)
            {
                timeSinceLastFrame = 0;
                ++currentFrame.X;
                if (currentFrame.X >= sheetSize.X)
                {
                    currentFrame.X = 0;
                    ++currentFrame.Y;
                    if (currentFrame.Y >= sheetSize.Y)
                    {
                        currentFrame.Y = 0;
                    }
                }
            }
        }

        public override void Draw(GameTime gameTime)
        {
            spriteBatch.Draw(textureImage,
                position,
                new Rectangle(currentFrame.X * frameSize.X,
                    currentFrame.Y * frameSize.Y,
                    frameSize.X, frameSize.Y),
                    Color.White, 0, Vector2.Zero,
                    1f, SpriteEffects.None, 0);

            base.Draw(gameTime);
        }

        public abstract Vector2 direction
        {
            get;
        }

        public Rectangle collisionRect
        {
            get
            {
                return new Rectangle(
                    (int)position.X + collisionOffset,
                    (int)position.Y + collisionOffset,
                    frameSize.X - (collisionOffset * 2),
                    frameSize.Y - (collisionOffset * 2));
            }
        }
    }
}

作为附录,我强烈建议您转用 MonoGame。 XNA 不再受支持(很久以前它被微软杀死了),MonoGame 是开源实现。变化不大,但您仍需要使用 XNA 的内容管道(.XNB 文件)。

如果您想坚持使用 XNA,请使用 Platformer Starter Kit 开始项目。你会更好地了解 XNA 是如何工作的,因为你的架构很奇怪。

【讨论】:

  • 我可能误解了您更改更新方法的意思,但我尝试将更新方法更改为“公共覆盖无效更新(GameTime gameTime)”而不是“受保护的覆盖无效更新( GameTime gameTime”并得到“在覆盖'受保护'继承的成员时无法更改访问修饰符”。感谢您的建议。我正在上这门课,看看我是否想进入视频游戏编程,但它没有那么富有成效正如我所希望的那样(在实践知识的意义上)。
  • @Newprgm 更新方法的问题在于您使用的 Rectangle 参数。 XNA 的默认更新方法不使用它,因此它与UserControlledSprite 更新之间存在冲突。有关游戏编程的更多信息,总是有GameDev StackExchange 网站。但取决于您将在哪里工作,您不会像 XNA 那样总是从头开始。通常,这些公司使用自制引擎,或者他们为一个引擎购买许可证(例如:Unity 或 CryEngine)。然而,遗憾的是,大多数游戏开发工作场所都具有“大量工作时间”和“低薪”的特点。
猜你喜欢
  • 1970-01-01
  • 2014-08-31
  • 1970-01-01
  • 1970-01-01
  • 2012-01-24
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多