在我的2D XNA游戏中绘制精灵的有效方法是什么?更具体地说,我将这个问题分为4个问题。
我曾经声明 Game1 的 spriteBatch是静态的,并在每个IDrawable.Draw
中调用SpriteBatch.Begin
和.Close
。这效果不佳。为每个可绘制对象提供自己的SpriteBatch也效果不佳。
Q1:我认为最好有一个 SpriteBatch 实例,并且只调用开始/关闭一次。这是对的吗?
目前,我的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:我认为应该有更好的方法来做到这一点。我正在考虑创建一个纹理字典,将其资产名称作为字符串。你有什么建议?
我曾经声明过 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,并在代码中根据需要调用它们。摆脱静态的东西并使用依赖注入 istead。
此外,每个组件都有自己的 IGameComponent.LoadContent 方法。我应该在那里加载我的内容吗?还是在父类(如 Game1.LoadContent)加载内容更好?
您应该在需要时加载资产,并且您对此负责。当用户刚刚开始游戏时,您不必加载所有 30 个关卡,是吗?例如,当游戏启动时,您会加载开始屏幕和主菜单所需的所有资产。如果您只加载所需的内容,则玩家很高兴游戏快速启动。然后玩家想要开始游戏。在这里,您可以在单独的线程上加载资产,以保持应用程序的响应。
我认为应该有更好的方法来做到这一点。我正在考虑创建一个纹理字典,将其资产名称作为字符串。你有什么建议?
Content.Load
已经缓存,因此您不必这样做。
从教程中可以收集到
的仅调用开始和结束一次是首选方法。
Q4:我认为应该有更好的方法来做到这一点。我正在考虑创建一个纹理字典,将其资产名称作为字符串。你有什么建议?
A4:我通常在TextureLib
类中创建一个Dictionary<string, Texture2D> NameTextureDic
(在运行时处理加载png图像),因此我可以获得如下所示的任何纹理:
var t2d = textureLib.NameTextureDic["tree-4"];