【发布时间】:2021-03-21 12:39:00
【问题描述】:
我正在制作一个在基本级别上运行良好的 2D 游戏引擎。现在我想对其进行微调并为引擎添加一些额外的(但必要的)功能。不幸的是,我坚持使用我的“层”系统。
您可以将其想象为 Unity 中的相同内容,或 Photoshop 中的图层...我想确定精灵(图像)的显示顺序。我发现的大多数“解决方案”都说“在另一个图像之前绘制一个图像,这样它就会显示在顶部......”是的,我知道这是如何工作的,但这不是最好的方式,因为游戏可以包含数千个精灵并且渲染顺序也可以由用户动态改变。所以我需要应用某种“图层”系统,用户可以在实例化 Sprite 类的对象期间设置顺序,或者稍后在需要时通过更改相关属性值来更改图层顺序(类似于“layerOrder = 2;” )。我想,我在说什么非常直截了当。
是否有任何合适且具有成本效益的方法来做到这一点?这应该具有成本效益,因为 Renderer() 函数在一秒钟内运行多次,同时将大量图像绘制到屏幕上。如果这个“函数”是 C# 本身的一部分,我会很高兴,但看起来不是!
这里是我简化的 Renderer() 方法:
private void Renderer(object sender, PaintEventArgs e)
{
Graphics g = e.Graphics;
g.Clear(BkgColor);
foreach (Sprite s in RegisterSprite.ToList())
{
g.DrawImage(s.SpriteBmp, s.Position.X, s.Position.Y, s.Size.X * s.Scale.X, s.Size.Y * s.Scale.Y;
}
}
我的 Sprite 类没有什么特别的......构造函数从给定目录加载图像并设置用户通过构造函数传递的属性,如位置、名称等......“RegisterSprite”只是一个包含所有内容的列表的精灵。当用户创建精灵的对象时,精灵就会被添加到列表中。(如墙壁或敌人......) Sprite 类会自动将新精灵注册到列表中,仅此而已!
请尝试提供一些可以集成到我的引擎中的想法或解决方案。或者让我知道是否有内置的方法可以做到这一点。很难想象没有任何方法可以决定哪个位图/图像绘制在其他图像之上...谢谢!
【问题讨论】:
-
如果您需要 z 顺序,则需要 z 顺序,这意味着您需要将其包含在系统中。然后其余的将通过简单地按顺序自行工作。唯一可能昂贵的操作是更改精灵的 z 值。一种选择是使用相对 z 值,另一种选择是将它们作为绝对值,如实际 z 坐标。后者需要处理碰撞,前者是重新排序,在您的示例中重新排序
RegisterSprite.. -
这听起来很有趣!很明显的方式,但由于我的引擎是纯 2D 的,这将很难实现一个新的维度。老实说,我不知道该怎么做,因为我从不编写任何 3D 代码(仅使用 Unity)。我也有 AABB 碰撞检测 - 正如你所提到的 - 我需要在其中实现新的 z 坐标,这听起来有问题。无论如何我会考虑如何做到这一切。目前我无法想象如何在 'DrawImage()' 方法中添加一个额外的轴,因为它只接受两个轴在 2D 屏幕上绘制。感谢您的想法!
-
好吧,我仍然会为所有其他帐户保留 2D,但如果您需要以某种顺序堆叠它们,则需要将订单信息存储在某个地方。 (或从列表中的顺序暗示,但这不适用于任何类型的更改,包括插入......)。给定 sprite 类中的 z 值,一个小的 LINQ 会即时重新排序列表,并且由于几乎所有项目都已经处于正确的顺序,因此重新排序应该非常快。 - 但是你需要在你的场景中决定一些“意义”。它是关于什么类型的场景?太空歌剧?
-
其实我的意思是“GameEngine”就像一个真正的通用游戏引擎,适用于所有类型的 2D 游戏......我有一个简单的自上而下的演示游戏,但没什么特别的......无论如何你的解决方案是这样做的方法!很简单,我向 Sprite.cs 添加了一个变量,例如“int layerOrder”,并在创建实例时设置它。然后,在渲染器开始运行之前,我根据变量对整个列表进行排序......所以我将得到一个有组织的列表,其中第一个元素是最低/最深的元素。这样,渲染器的 foreach 将首先绘制我想要的内容并自动存储“层”。谢谢!
-
如果您只想将您的想法作为评论,我将接受它作为解决方案!如果你不想要,我会根据你的想法回答我的问题,这样有类似问题的人就会看到如何去做。
标签: c# graphics bitmap overlay drawimage