C# 最佳实践:在XNA中高效绘制精灵
在我的2D XNA游戏中绘制精灵的有效方法是什么?更具体地说,我把这个问题分成4个问题C# 最佳实践:在XNA中高效绘制精灵,c#,xna,drawing,2d,sprite,C#,Xna,Drawing,2d,Sprite,在我的2D XNA游戏中绘制精灵的有效方法是什么?更具体地说,我把这个问题分成4个问题 我曾经声明Game1的spriteBatch静态,并在每个IDrawable.Draw中调用spriteBatch.Begin和.Close。那没用。给每一个drawable它自己的SpriteBatch也没有很好地工作 Q1:我认为最好有一个SpriteBatch实例,并且只调用begin/close一次。这是正确的吗 目前,我的Game1.Draw看起来像这样: spriteBatch.Begin()
我曾经声明Game1的spriteBatch静态,并在每个
IDrawable.Draw中调用spriteBatch.Begin
和.Close
。那没用。给每一个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
,并给了它们两个构造函数:
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;
}
}
静态纹理2d默认纹理;
公共纹理2d我的纹理;
公敌()
:此(默认纹理){}
公敌(纹理2D纹理)
{
MyTexture=纹理;
}
受保护的覆盖void LoadContent()
{
如果(MyTexture==null)
{
如果(defaultTexture==null)
{
defaultTexture=Content.Load(“敌人”);
}
MyTexture=defaultTexture;
}
}
这样,类的默认纹理仅在第一次对该类调用LoadContent
时加载。但是,当在构造函数中指定参数texture
时,我必须事先加载该纹理
Q4:我认为应该有更好的方法来做到这一点。我正在考虑创建一个纹理字典,将它们的资产名称作为字符串。你有什么建议?尽可能从
只调用一次begin和end是首选方法
我曾经声明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发生冲突
是否将元素添加到组件的全局集合?将drawable添加到此集合中不是一个好主意。您无法控制绘图顺序,组件是全局的
在组件IUpdatable和IDrawable中实现,并在需要时在代码中调用它们。去掉静态内容,使用istead
此外,每个组件都有自己的IGameComponent.LoadContent方法。我应该在那里加载我的内容吗?还是最好在父类加载内容,例如Game1.LoadContent
您应该在需要并负责的时候加载资产。当用户刚开始游戏时,您不必加载所有30个关卡,是吗?例如,当游戏开始时,加载开始屏幕和主菜单所需的所有资源。如果你加载了你需要的东西,玩家会很高兴游戏开始得很快。然后玩家想要开始游戏。在这里,您可以在单独的线程上加载资源,以保持应用程序的响应性
我认为应该有更好的方法来做到这一点。我正在考虑创建一个纹理字典,将它们的资产名称作为字符串。你有什么建议
Content.Load
已被缓存,因此您不必这样做 Q4:我认为应该有更好的方法来做到这一点。我正在考虑创建一个纹理字典,将它们的资产名称作为字符串。你有什么建议
A4:我通常在TextureLib
类中创建一个字典名TextureDic
(该类在运行时处理加载png图像),因此我可以获得如下任何纹理:
var t2d = textureLib.NameTextureDic["tree-4"];
我也是这样做的。如果我没有理由使用多重精灵批处理(例如,对于分割屏幕、不同效果等),我只在游戏的主类中调用一次开始和结束,并在此开始和结束之间绘制所有内容。您似乎在手动对敌人调用绘制。在我的游戏中,我已经将所有可绘制的东西(如墙和敌人)添加到Game1。组件
列表,因此在调用基类时调用Draw
。+1指出Content.Load
本身处理冗余调用。然而,使用全局集合有那么糟糕吗?我不必控制绘图顺序。而且,我明白我不应该加载所有级别。但是,举个例子,我应该在玩家射击时加载bullet.png,在它离开时卸载吗?或者我应该在级别的开始加载图像?默认情况下,您不应该关心卸载<代码>内容
将管理缓存。游戏组件是一个设计缺陷。请参见,但是,我应该在init级别加载所需的精灵,还是在它们第一次出现时加载?:)