13

在我的 2D XNA 游戏中绘制精灵的有效方法是什么?更具体地说,我将这个问题分为 4 个问题。


我曾经将 Game1 的 spriteBatch 声明为staticSpriteBatch.Begin.Close在每个IDrawable.Draw. 那效果不好。为每个可绘制对象提供自己的 SpriteBatch 也效果不佳。

Q1:我认为最好有一个SpriteBatch 实例,并且只调用一次begin/close 。它是否正确?


目前,我Game1.Draw看起来像这样:

spriteBatch.Begin();

base.Draw(gameTime); // draws elements of Game.Components

// ...

spriteBatch.End();

Q2:这种方式,Begin只调用一次。这是要走的路吗?你们是怎么解决这个问题的?


Q3:另外,每个组件都有自己的IGameComponent.LoadContent方法。我应该在那里加载我的内容吗?还是在父类中加载内容更好,例如Game1.LoadContent


我意识到我不应该两次加载相同的内容,所以我给了我的可绘制组件一个 static 和一个 non-static Texture2D,并给了它们 2 个构造函数:

static Texture2D defaultTexture;
public Texture2D MyTexture;

public Enemy()
    : this(defaultTexture) { }

public Enemy(Texture2D texture)
{
    MyTexture = texture;
}

protected override void LoadContent()
{
    if (MyTexture == null)
    {
        if (defaultTexture == null)
        {
            defaultTexture = Content.Load<Texture2D>("enemy");
        }

        MyTexture = defaultTexture;
    }
}

这样,类的默认纹理仅在该类第一次LoadContent调用时加载。但是,当texture在构造函数中指定参数时,我必须事先加载该纹理。

Q4:我认为应该有更好的方法来做到这一点。我正在考虑创建一个纹理字典,其资产名称为字符串。你有什么建议?

4

3 回答 3

3

我曾经将 Game1 的 spriteBatch 声明为静态

你不必让它是静态的。只做一个单例。内部Draw方法

SpriteBatch spriteBatch = ScreenManager.SpriteBatch; // singletion SpriteBatch
spriteBatch.Begin();
// Draw the background
spriteBatch.Draw(background, ...
foreach (var enemy in enemys)
{
     enemy.Draw(gameTime);
}
// etc.
spriteBatch.End(); // call here end 
base.Draw(gameTime); // and then call the base class

我认为最好有一个 SpriteBatch 实例,并且只调用一次开始/关闭。它是否正确?

我建议您打开并结束SpriteBatch一种方法。它将帮助您避免与SpriteBatch已开始绘制但未完成的冲突。

您是否将元素添加到全局组件集合中?将可绘制对象添加到此集合是一个坏主意。您无法控制绘图的顺序,组件是全局的。看到这个答案

在您的组件中实现 IUpdatable 和 IDrawable 并在您需要的代码中调用它们。摆脱静态的东西并使用依赖注入

此外,每个组件都有自己的 IGameComponent.LoadContent 方法。我应该在那里加载我的内容吗?还是在父类中加载内容更好,例如 Game1.LoadContent?

您应该在需要时加载资产并且您对此负责。当用户刚开始游戏时,您不必加载所有 30 个关卡,是吗?例如,当您的游戏开始时,您会加载开始屏幕和主菜单所需的所有资源。如果你只加载你需要的东西,玩家就会很高兴游戏开始得很快。然后玩家想要开始游戏。在这里,您可以在单独的线程上加载资产以保持应用程序响应。

我认为应该有更好的方法来做到这一点。我正在考虑创建一个纹理字典,其资产名称为字符串。你有什么建议?

Content.Load已经缓存了,所以你不必这样做。

于 2012-12-20T11:15:30.510 回答
1

可以从周围的教程中收集到

只调用一次 begin 和 end 是首选方法。

于 2012-12-20T11:12:33.673 回答
0

Q4:我认为应该有更好的方法来做到这一点。我正在考虑创建一个纹理字典,其资产名称为字符串。你有什么建议?


A4Dictionary<string, Texture2D> NameTextureDic :我通常在我的类中创建一个TextureLib(在运行时处理加载 png 图像),所以我可以得到任何这样的纹理:

var t2d = textureLib.NameTextureDic["tree-4"];
于 2012-12-21T09:45:41.153 回答