C#或C++游戏:许多16色图像加载到RAM中。高效解决方案是什么?

10

我正在规划一个格斗游戏,但不确定如何解决与内存有关的问题。

背景信息:
- 还在考虑是使用C#(XNA)还是C++。在探索如何在两个语言中解决这个问题之前,我们不想承诺使用哪种语言。
- 如果可能,最大使用256MB RAM会很好。
- 每次只能有两个角色出现,并且这些角色只能在战斗之间更换。在战斗之间有时间来加载/释放内存,但游戏在战斗过程中需要以恒定的60帧每秒运行。每一帧为16.67毫秒。
- 每个角色的图像总数不到一百个。每个图像大约为200x400像素。任何给定时刻只能显示每个角色的一个图像。

根据我的计算,每个未压缩的图像大约需要300kb;整个角色需要100MB以上。由于还需要内存用于其他资源,这太接近256MB的限制了。

由于每个图像可以用16种颜色表示。如果我能利用这一点,理论上应该能够使用1/8的空间。我找过一些资料,但没有找到本机支持调色板图像的消息。(使用较少的位存储每个像素,并将其映射到32位RGBa颜色)

我们尝试使用DXT压缩,但是压缩伪影很明显。

我考虑制作自己的文件格式,每个像素使用4位(以及一些额外的调色板信息),在战斗之前将所有这种新格式的图像加载到RAM中,然后在绘制任何特定图像时,仅对该图像进行解压缩,以便可以正确呈现。我不知道每帧执行如此多的赋值操作(每个角色大约为200x400 = 160k)是否现实。 对我来说听起来很恶心。

有人对我的解决方案是否合理有建议,并且是否存在更好的解决方案?

非常感谢!

我尝试使用只有一个通道的图片,然后使用着色器进行一系列if语句操作将各种值转换为其他颜色。不幸的是,这个着色器的代码行数太多了。而且这个方法非常不规范,不利于扩展。

C#(XNA)或C++;那应该是你的首选。 - Falmarri
1
Falmarri: 感谢您的快速响应。我应该在我的帖子中澄清以下内容。如果解决方案在一种语言中非常混乱,但在另一种语言中很清晰,则这将是我们选择使用哪种语言的决定性因素。因此,目前我们无法致力于一种语言,直到我们在两种语言中探索此问题。 - Codin' Wolf
忽略有关如何表示图像的问题,你打算如何确保数据实际上在内存中?操作系统可能会将数据分页到磁盘上!(Linux世界使用内存映射和页面固定;Windows应该有类似的东西。) - chrisaycock
@chrisaycock:256 MB 的限制强烈暗示着一个控制台(而 XNA 则暗示着 Xbox)。它们通常不会随机分页,因为一次只能运行一个游戏。 - MSalters
@MSalters 好的,那很有意义。我没有理解他的内存限制的重要性。 - chrisaycock
还有SlimDX + C#选项... - Agnius Vasiliauskas
5个回答

3
使用S3纹理压缩(又称DXTn)代替。S3TC可让您以每像素4位或8位的方式存储纹理,并且它是图形卡本地支持的。您不必担心即时解压缩,因为图形卡会处理。
DirectX在C++和C#中对S3TC有非常好的支持。

感谢您的回复。我忘了提到我已经尝试过DXT压缩,并已将其添加到主贴中。它可以工作,但是压缩伪影相当明显。特别是我们正在使用的卡通风格,其中有几个区域应该是纯色的。 - Codin' Wolf

2
如果您想针对XBox 360进行开发,但没有适当的(完整的)开发工具包,则C#是您唯一的选择。在开始时,XNA肯定会让您做事情变得更加容易,特别是如果您现在只是在做2D游戏(并且处理了许多其他您现在不需要担心的事情)。
至于内存限制问题,以下是降低内存使用的建议:
- 使用1555纹理格式将其减半(虽然您只有1位alpha通道) - 不同的图像是否有任何共同部分?您能否使用许多较小的瓷砖而不是一个大瓷砖来渲染角色(即2x4或更大的网格)。最有可能的是,您的角落中有很多空白空间,可以在大多数图像之间共享,并且这将节省大量空间(我刚刚看到有人通过精灵表已经提到了这一点-尽管这应该是一种无损选项以节省内存)。 - 您提到已经尝试伪造调色板纹理。除了IF语句之外,您还可以使用第二个纹理来包含调色板颜色,并使用从第一个纹理获得的值作为纹理坐标通过像素着色器查找第二个纹理(第二个纹理只是32位颜色值的1D纹理)。 - 鉴于现代处理器的强大性能以及您在同时进行的其他工作,您可能有足够的空闲资源来即时解压缩两个角色的帧以准备渲染纹理(特别是使用多核心)。但是,您至少需要双缓冲纹理以防止CPU等待GPU完成使用它们的上一帧。
您还可以结合其中一些选项以节省更多内存。

1

我认为将您的图像放入精灵表是最佳选择。这样可以在失去图像数据的同时,获得最佳的内存成本平衡。

我建议使用C#和XNA框架,因为它们具有出色的支持内置精灵处理器,并且内容管道可以在编译时自动将单个图像转换为完整的精灵表。微软提供了一个演示此功能的示例项目,链接在此:http://create.msdn.com/en-US/education/catalog/sample/sprite_sheet


1
你可以使用哈夫曼编码树将数据压缩后存储在内存中(因为它可以很好地进行压缩),然后实时提取/加载。还有其他的压缩数据结构可供使用。

0

你可能想看看xnaMUGEN。一个格斗游戏引擎在C#中很容易实现。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接