如何处理2D游戏中的任意大图像?


13

当您拥有使用非常大图像(大于硬件可以支持的图像)的2D游戏时,该怎么办?也许对这个问题有一些有趣的解决方案,这在我之前从未发生过。

我基本上是在从事某种图形冒险游戏的制作。我的目标受众是几乎没有游戏开发(和编程)经验的人。如果您使用的是这样的应用程序,是不是更希望它在内部处理问题而不是告诉您“拆分图像”?

语境

众所周知,图形卡对其可使用的纹理大小施加了一组限制。例如,使用XNA时,取决于您选择的配置文件,最大纹理大小被限制为2048或4096像素。

通常,在2D游戏中这不会带来太大问题,因为大多数游戏都具有可以由较小的单个块(例如,图块或变形的精灵)构建的关卡。

但是,请考虑一些经典的点按式图形冒险游戏(例如Monkey Island)。图形冒险游戏中的房间通常是整体设计的,很少或没有可重复的部分,就像画家在风景上一样。或像《最终幻想7》这样的游戏使用了大型的预渲染背景。

这些房间中的一些可能会变得很大,经常跨越三个或更多屏幕宽度。现在,如果我们在现代高清游戏的背景下考虑这些背景,它们将很容易超过最大支持的纹理大小。

现在,解决此问题的明显方法是将背景分成适合需求的较小部分,并排绘制。但是,您(或您的艺术家)是否应该成为拆分所有纹理的人?

如果您使用的是高级API,它是否应该准备好应对这种情况并在内部进行纹理的拆分和组装(作为XNA的内容管道等预处理程序或在运行时进行)?

编辑

从XNA实现的角度来看,这就是我的想法。

我的2D引擎只需要Texture2D功能的很小一部分。我实际上可以将其简化为以下接口:

public interface ITexture
{
    int Height { get; }
    int Width { get; }
    void Draw(SpriteBatch spriteBatch, Vector2 position, Rectangle? source, Color  color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth);
}

我使用的唯一依赖Texture2D的外部方法是SpriteBatch.Draw(),因此我可以通过添加扩展方法在它们之间建立桥梁:

    public static void Draw(this SpriteBatch spriteBatch, ITexture texture, Vector2 position, Rectangle? sourceRectangle, Color color, float rotation, Vector2 origin, Vector2 scale, SpriteEffects effects, float layerDepth)
    {
        texture.Draw(spriteBatch, position, sourceRectangle, color, rotation, origin, scale, effects, layerDepth);
    }

每当我以前使用Texture2D时,这将允许我互换使用ITexture。

然后,我可以创建ITexture的两个不同实现,例如RegularTexture和LargeTexture,其中RegularTexture将仅包装常规的Texture2D。

另一方面,LargeTexture将保留一个Texture2D的列表,每个列表都对应于完整图像的一个分割片段。最重要的部分是,在LargeTexture上调用Draw()应该能够应用所有转换并绘制所有片段,就好像它们只是一个连续图像一样。

最后,为了使整个过程透明,我将创建一个统一的纹理加载器类,该类将充当Factory Method。它将纹理的路径作为参数,并返回一个ITexture,该ITexture可以是RegularTexture或LargeTexture,具体取决于图像大小是否超过限制。但是用户不需要知道它是哪一个。

有点过大或听起来还好吗?


1
好吧,如果您想分割图像,请扩展内容管道以编程方式进行。并非所有功能都能够涵盖每个场景,并且在某些时候您将不得不自己扩展它。个人分割声音就像最简单的解决方案一样,然后您就可以像平铺地图一样处理图像,上面有大量资源。
DMan 2011年

在内容管道上执行此操作是最明智的方法。但就我而言,我需要在运行时加载映像,并且已经设法提出了运行时解决方案(这就是为什么我昨天问了这个问题)。但是真正的美来自于拍摄这张“瓷砖贴图”,并使其表现得像普通纹理一样。也就是说,您仍然可以将其传递到spritebatch进行绘制,并且仍然可以指定位置,旋转,比例,src /目标矩形等。到现在为止,我就快到一半了:)
David Gouveia

但说实在的,我已经在想知道所有这些是否真的值得,还是我应该向用户显示警告,告诉他最大支持的图像大小为2048x2048,并加以处理。
David Gouveia

关于设计,这完全取决于您。如果您完成了项目并且无法在房间之间滚动,那么最好使用未完成的编辑器,该编辑器允许您滚动大纹理:D
Aleks

将其隐藏在API中听起来是一种使游戏作者的生活更轻松的好方法。我可能会在Polygon(sprite)和Texture类中实现它,而不是对较小的图像进行特殊处理,而只是使它们成为1x1的图块。因此,纹理类是一个纹理组,描述所有图块以及多少行/列。然后,Polygon类将查看此信息,以进行自我拆分,并使用适当的纹理绘制每个图块。这样,它同一类。如果您的Sprite类仅绘制可见的图块,并且纹理组直到需要时才加载纹理,则可获得加分。
uliwitness 2014年

Answers:


5

我认为您在正确的轨道上。您必须将图像分成较小的部分。自从您成为游戏制作人以来,您就无法使用XNA的内容管道。除非您的制造商更喜欢Engine,否则仍将要求开发人员使用Visual Studio。因此,您需要构建自己的例程来进行拆分。您甚至应该考虑在流式传输之前就对片段进行流式处理,以使您仍然不限制播放器应具有多少视频内存。

您可以针对冒险游戏做一些技巧。我想像所有经典的冒险游戏一样,您将具有几层这些纹理,以便...您的角色可以走在树或建筑物后面...

如果您想让这些图层具有降落效果,那么在拆分图块时,只需跳过所有半透明的图层。在这里,您需要考虑瓷砖的大小。较小的图块会增加管理开销和绘制调用,但数据量会减少,而较大的图块将对GPU更加友好,但将具有很多半透明性。

如果您没有降落伞效果,则可以只创建一个32位深度,而不是用2-4个具有32位深度的巨型图像覆盖整个场景。而且您可以拥有一个狭窄的或深度的图层,每个像素只有8位。

我知道这听起来非游戏开发商很难管理资产,但实际上并非必须如此。例如,如果您的街道上有3棵树,而玩家则走在2棵树的后面,在第3棵树的前面,而在背景的其余部分之前……只需在编辑器中按照所需的方式进行场景布局,然后在您可以从游戏制造商那里迈出一步,您可以烘烤这些巨大的图像(包括大图像的小方块)。

关于经典游戏的运作方式。我不确定他们可能会做类似的技巧,但您必须记住,在屏幕为320x240时,游戏具有16种颜色,当使用pa色纹理时,您可以将2个像素编码为一个字节。但这不是当前架构的工作方式:D

祝好运


谢谢,这里有很多非常有趣的想法!我实际上已经看过Adventure Game Studio之前使用的模板层技术。对于我的应用程序,我做的事情有所不同。房间不一定有一张背景图片。而是有一个用户导入的图像调色板以及一个背景/前景层。用户可以自由地将片段拖放到房间中进行创建。因此,如果他愿意,他也可以用较小的部分组成它,而不必非交互地创建游戏对象。但是没有视差,因为只有这两层。
David Gouveia

我已经查看了Monkey Island Special Edition(总部重制版)的数据文件。每个背景都会精确地分割为1024x1024个片段(即使大部分图像未被使用)。无论如何,请检查我的编辑内容,以使整个过程透明。
David Gouveia

我可能会选择更合理的东西,例如256x256。这样,我就不会浪费资源,如果以后决定实现流传输,它将加载更合理的块。也许我没有很好地解释它,但我建议您可以将所有这些小的静态游戏对象烘焙为大的纹理。如果背景纹理很大,您将保存的是顶部静态对象覆盖的所有像素。
亚历克斯(Aleks)

我知道了,因此将所有静态对象合并到背景中,然后拆分并创建纹理图集。我也可以按照这种思路将其他所有内容烘焙到纹理图集中。这也是一个好主意。但我将其留待以后使用,因为现在我没有任何“构建”步骤,即编辑器和游戏客户端都在相同的引擎和相同的数据格式上运行。
David Gouveia

我喜欢模具的方法,但是如果我要制作冒险游戏编辑器,我可能不会使用它……也许是因为,如果我要构建这样的工具,我将主要面向游戏开发人员。好吧,它有它的优点和缺点。例如,您可以使用其他图像,在这些图像上,位可以定义每个像素的触发器,或者,如果您有动画效果,则可以轻松地将其模版出来。注意:一种奇怪的不相关建议针对脚本编写的UML状态/活动图。
亚历克斯(Aleks)

2

切成小块,使它们不再像您说的那样大。没有魔术。那些旧的2D游戏要么这样做,要么用软件渲染,在这种情况下,除了RAM大小外,没有硬件限制。值得注意的是,许多2D游戏确实没有很大的背景,它们只是缓慢滚动,因此感觉很庞大。

您打算在图形冒险游戏制造商中进行的工作是在打包运行游戏之前,在某种“构建”或“集成”步骤中对这些大图像进行预处理。

如果您要使用现有的API和库而不是编写自己的API和库,建议您在“构建”期间将这些大图像转换为图块,并使用2D图块引擎,其中有很多。

如果您想使用自己的3D技术,则可能仍要拆分成图块,并使用众所周知的且设计良好的2D API为此编写自己的3D库,这样就可以确保至少从一个好的API设计,而您所需的设计却更少。


在构建时执行此操作将是理想的……但是我的编辑器也使用XNA进行渲染,而不仅仅是引擎。这意味着,一旦用户导入了图像并将其拖到房间中,XNA应该已经能够渲染它。因此,我的最大难题是加载内容时是在内存中拆分,还是导入内容时是在磁盘上拆分。同样,将图像物理上拆分为多个文件意味着我需要一种不同的方式来存储这些图像,而在运行时将其存储在内存中则不需要更改游戏的数据文件。
David Gouveia

1

如果您熟悉四叉树在视觉实践中的外观,我使用了一种将详细的大图像切割成较小图像的方法,该方法与四叉树的证明/可视化外观类似。但是我的方法是专门切割可以根据颜色进行不同编码或压缩的区域。您可以使用此方法并按照我的描述进行操作,因为它也很有用。

在运行时剪切它们会暂时需要更多内存,并导致加载时间变慢。我要说的是,这取决于您是否更关心物理存储或使用编辑器制作的用户游戏的加载时间。

加载/运行时间:我进行加载的方式只是将其切成比例大小的碎片。如果像素数是奇数,则占最右边的一个像素,没有人喜欢剪切图像,尤其是经验不足的用户,他们可能只是不知道这并不完全取决于他们。将它们的宽度减一半或将高度减一半(或3或4),而不是正方形或4个部分(2行2列)的原因是,这将使平铺内存变小,因为您不必担心x和y同时进行(并且取决于那么大的图像数量,这可能非常重要)

手动/自动之前:在这种情况下,我喜欢这样的想法:让用户选择将其存储在一个图像中或将其存储为单独的片段(默认为一个图像)。将图像存储为.gif效果很好。该图像将在一个文件中,而不是每个帧都是动画,它更像是所有相同图像的压缩存档(无论如何,本质上就是.gif)。这样可以简化物理文件的传输和加载的难度:

  1. 这是一个文件
  2. 所有文件的格式几乎相同
  3. 您可以轻松选择何时以及是否将其切成单独的纹理
  4. 如果单个图像已经位于单个已加载的.gif中,则访问单个图像可能会更容易,因为在内存中不需要那么多的图像文件

哦,如果您使用.gif方法,则应将文件扩展名更改为其他名称(.gif-> .kittens),以免当.gif动画像是损坏的文件时避免混淆。(不必担心合法性,.gif是一种开放格式)


您好,谢谢您的评论!抱歉,如果我误解了,但是您编写的内容不是主要与压缩和存储有关吗?在这种情况下,我真正担心的是我的应用程序的用户能够导入任何图像,并且引擎(在XNA中)能够在运行时加载和显示任何图像。我已经设法通过使用GDI将图像的不同部分读取到单独的XNA纹理中并将它们包装在一个行为类似于常规纹理的类中(即,整体上支持绘图和转换)来解决。
David Gouveia

但是出于好奇,您能否详细说明一下用来选择进入每个部分的图像区域的标准?
David Gouveia

如果您对图像处理的经验不足,则其中一些可能会让您头疼。但本质上,我是在描述将图像切成段。是的,.gif点既描述了存储又描述了加载,但这是作为一种方法来剪切图像,然后将其存储在计算机上。如果将其另存为gif,我是说您可以将其剪切为单个图像,然后将其另存为动画gif,并将图像的每个剪切均另存为单独的动画帧。它运作良好,我什至还添加了其他可能有用的功能。
Joshua Hedges

我所描述的四叉树系统完全是作为参考,因为这是我从中得到灵感的地方。尽管不要向可能有类似问题的读者挤一个可能有用的问题,但如果您想了解更多信息,我们应该使用私人消息传递。
Joshua Hedges

罗杰,我谈到了将GIF框架用作各种档案的内容。但是我也想知道,GIF是不是调色板数量有限的索引格式吗?我可以只在每帧中存储整个32bpp RGBA图像吗?而且我认为加载它的过程最终会变得更加复杂,因为XNA对此不提供任何支持。
David Gouveia

0

这听起来似乎很明显,但是为什么不将房间分成较小的部分呢?选择一个不会碰到任何图形卡的任意大小(例如1024x1024或更大),然后将房间分成多个部分。

我知道这可以避免问题,老实说,这是一个非常有趣的问题。无论如何,这是一个微不足道的解决方案,可能有时会为您服务。


我想我可能在该线程中的某处提到了原因,但是由于不确定,我会重复。基本上,因为它不是游戏而是公众游戏制造商(认为与RPG制造商在同一个范围内),因此与其在用户导入自己的资产时不强制纹理大小限制,不如处理它自动在幕后进行拆分和缝合,而无需担心纹理大小限制的技术细节。
David Gouveia

好的,那很有道理。抱歉,我想我错过了。
ashes999 2012年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.