最佳实践:XNA中的高效精灵绘图

时间:2012-12-20 11:02:43

标签: c# xna drawing 2d sprite

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


我过去常常声明Game1的spriteBatch 静态,并在每个SpriteBatch.Begin中调用.CloseIDrawable.Draw。这不太好用。给每个drawable它自己的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


我意识到我永远不应该加载相同的内容两次,所以我给了我的可绘制组件静态和非静态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 :我认为应该有更好的方法来做到这一点。我正在考虑创建一个纹理字典,其资产名称为字符串。你会建议什么?

3 个答案:

答案 0 :(得分:3)

  

我曾经宣布过Game1的spriteBatch static

您不必将其静态化。只做一个单身人士。内部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发生冲突。

您是否将元素添加到全局组件集合中?将drawable添加到此集合中是一个坏主意。您无法控制绘图的顺序,组件是全局的。 See this answer

在您的组件中实现IUpdatable和IDrawable,并在您需要的代码中调用它们。摆脱静态的东西,并使用Dependency Injection istead。

  

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

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

  

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

Content.Load已缓存,因此您无需执行此操作。

答案 1 :(得分:1)

可以从tutorials around

收集

只调用一次开始和结束是首选方法。

答案 2 :(得分:0)

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


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

var t2d = textureLib.NameTextureDic["tree-4"];