我正在为使用XNA的2D游戏编写地图编辑程序。为地图所需的所有图块创建Texture2D需要太长时间。
是否有使用纹理进行XNA绘图的替代方法?
我试图为每个瓷砖集创建一个纹理,而不是为瓷砖集中的每个瓷砖创建一个纹理,但是纹理的大小有限,我无法将瓷砖集的所有瓷砖都放到一个纹理中
目前程序包含内存中所有可能的纹理作为Bitmap对象。有没有办法简单地在XNA中将Bitmap对象绘制到屏幕上?我搜索过但我找不到任何相关信息。这种方法可以避免必须完全创建纹理,但是我必须直接对位图进行任何着色或效果。
答案 0 :(得分:2)
有没有理由你没有考虑加载图像一次然后将x和y偏移坐标传递给像素着色器?
你基本上会像这样设置C#:
myGraphicsDevice.Textures[0] = whateverYourGiantMapTextureIs;
foreach(MapChunk chunk in mapChunks) {
myShader.Effect.Parameters["xOffset"] = chunk.XOffset;
myShader.Effect.Parameters["yOffset"] = chunk.YOffset;
myGraphicsDevice.DrawIndexedPrimitives( your chunk drawing code here );
}
然后着色器代码如下:
float4x4 World;
float4x4 View;
float4x4 Projection;
float xOffset;
float yOffset;
sampler TextureSampler;
struct VS_INPUT {
float4 Position : POSITION0;
float4 Color : COLOR0;
};
VS_INPUT Transform(VS_INPUT Input) {
VS_INPUT Output;
float4 worldPosition = mul(Input.Position, World);
float4 viewPosition = mul(worldPosition, View);
Output.Position = mul(viewPosition, Projection);
Output.Color = Input.Color;
return Output;
}
float4 ColorTexture(VS_INPUT Input) : COLOR0{
return Input.Color.rgba * tex2D(TextureSampler, float2(xOffset, yOffset));
}
technique TransformColorTexture {
pass P0 {
VertexShader = compile vs_2_0 Transform();
PixelShader = compile ps_2_0 ColorTexture();
}
}
着色器代码可能需要适合您现有的代码,否则它应该可以解决问题。
答案 1 :(得分:2)
每个图块使用一个纹理效率不高。特别是因为这意味着你不能进行批处理(在任何真正意义上)。
如果你因为某些原因需要在内容项目中将它们作为单独的纹理(更容易编辑一个图块等),你可以在加载后很容易地将它们编译成tilemaps。 你如何做到这一点基本上是:
1:加载一些瓷砖(现在说40个32 * 32瓷砖)
2:为tilemap找出一个漂亮的纹理大小: 40的平方根是6.something,所以我们舍入到7. 7 * 32是224,这很好,但256更好,所以让纹理256x256。 (你可以制作能够动态识别出来的代码)
3:创建一个所需大小的Rendertarget2D。
4:激活rendertarget。
5:在rendertarget上渲染切片:
int x, y = 0;
foreach (var tile in allTiles)
{
RenderTile(tile, x*32, y*32);
x++;
if (x >= 8)
{
x = 0;
y++;
}
}
要进行渲染渲染,您将拥有一个顶点缓冲区,其顶点为4 * 40。每组4都有一个值,表示它所属的四元组的索引(0,1,2等等)。在着色器中,您有一组矩阵[40]用于平铺的位置,以及一个tileIndex(int [40])数组,用于了解要从平铺贴图中渲染的平铺。
对不起,我现在没有时间编写所有着色器代码:s
我在游戏中使用的另一个技巧是将级别预渲染到大型磁贴(640x360)上,这大大减少了绘制调用的次数,尤其是在处理来自不同tileset的5层以上的tile时。唯一的问题是它不适用于动态图块(动画图块等),但如果您愿意,可以标记它们并正常呈现它们。
答案 2 :(得分:1)
由于您需要使用自定义图像格式,如果您需要(为了速度),您可以尝试为XNA(http://msdn.microsoft.com/en-us/library/bb447754.aspx)编写自定义内容管道导入程序和处理器,但这可能对您所需要的内容有些过高要做。
我认为您希望尽可能轻松地设计GUI,即使这些问题迫使您使用C ++之类的语言,因此您可以使用DirectX。在Visual C ++中,如果使用Visual Studio,则仍应能够利用visual Windows Forms layout。
答案 3 :(得分:0)
假设地图需要现有图像的所有图块只是放在屏幕上以布置图块地图?或者你是在这个地图编辑器中制作图像并想要保存它们吗?
我读过这篇文章,还有你关于纹理的其他文章 - 如果它们都是你想要在你的游戏中使用的定义好的图像,那么你只能将它们包含在内容文件夹中并在那里引用它们吗?这允许XNA以xnb格式编译纹理,您不应该遇到要解释的问题。
然而,如果我们说的是完全动态的 - 或者你正在从瓷砖的布局中制作一个大图像(而不是像瓷砖地图那样做),那么我不确定如何处理这个问题。
答案 4 :(得分:0)
如果多个图块使用相同的纹理,只需加载一次即可。
如果用户包含某种文件格式的纹理,您可以自动将其转换为纹理/图像格式,以便更快地满足您的需求。
答案 5 :(得分:0)
不幸的是,据我所知,没有办法直接在XNA中将位图绘制到屏幕上;它要求所有内容都映射到Texture对象,默认情况下缓冲到图形卡。听起来好像你在谈论很多瓷砖,如果它们都不适合最大允许纹理(我不记得那是1024或4096平方......) - 你试过有一个无缓冲纹理用于速度目的?另一个替代方案是将您的tileset延迟加载到纹理中,这样用户就不必等待它们全部加载 - 对于编辑器,在加载时通常可以使用亮粉色后备颜色。
此外,在XNA中编写工具是否有任何必要条件?因为它听起来你是在与游戏引擎本身分开编写工具,所以你可能会在WPF中找到一些非常可接受的解决方案,包括直接从BitmapSources和UI的一些实用程序中绘制。
答案 6 :(得分:0)
您是否尝试使用单个执行线程绘制所有内容?
尝试多线程游戏。 C#中的线程非常简单,XNA支持。
不要将整个屏幕视为一个整体,而是尝试将其分成两个(或更多)部分。你可能需要重新编写你用来绘制的函数(我当然希望你不要直接在Draw()方法中抛出所有东西!!)来获取坐标设置绘制区域的边界。