如何按照给定的叠加顺序绘制图片? (层...)
How to draw pictures in the given overlay order? (layers...)
我正在制作一个 2D 游戏引擎,它在基本级别上运行良好。现在我想微调它并为引擎添加一些额外的(但必要的)功能。不幸的是,我坚持使用我的“层”系统。
你可以想象这就像 Unity 中的一样,或者像 Photoshop 中的层......我想确定精灵(图像)的显示顺序。我发现的大多数“解决方案”都说“在另一张图片之前绘制一张图片,这样它就会显示在顶部......”是的,我知道这是如何工作的,但这不是最好的方法,因为游戏可以包含数千个精灵并且渲染顺序也可以由用户动态更改。所以我需要应用某种 'layer' 系统,用户可以在实例化 Sprite 对象时设置顺序 class 或者稍后在需要时通过更改相关 属性 来更改图层顺序值(类似于“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 class 没有什么特别的...构造函数从给定目录加载图像并设置用户通过构造函数传递的属性,如位置、名称等... 'RegisterSprite' 只有一个包含所有精灵的列表。当用户创建精灵的对象时,精灵会添加到列表中。(如墙或敌人......)精灵 class 自动将新精灵注册到列表中,仅此而已!
请尝试提供一些我可以集成到我的引擎中的想法或解决方案。或者让我知道是否有内置方法可以做到这一点。很难想象没有任何方法可以决定哪个 bitmap/image 比其他人高...谢谢!
好的.. TaW 在问题的评论部分发布了我的问题的解决方案,但我会在这里自行回答,因为 TaW 看起来不写任何答案更长。
创建一个'layer system'和我当时写题时想的一样简单。我向 Sprite class 添加了一个整数变量 (layerOrder),因此我可以为每个 Sprite(图像)设置我需要的顺序。正如我提到的,我有一个列表 (RegisterSprite),当我创建它们(实例化对象)时,我在其中存储每个精灵。然后我写了一个小方法,可以根据精灵的 layerOrder 值对列表进行排序。这样,列表中的第一个精灵将是最低值,最后一个是最高值。我使用 foreach 循环将列表中的每个图像绘制到屏幕上,当然,这将从第一个元素开始。因此,具有较低 layerOrder 的精灵将首先绘制,在具有较高值的精灵之下。在渲染器(使用 foreach)部分之前调用排序方法很重要。
如果需要在 'runtime' 更改精灵图层顺序,只需在更改值后调用排序算法或创建一个方法来更改图层顺序,该方法也会自动重新排序列表。如果需要优化算法(堆优化?)或编写另一个更新列表的算法(更改相关元素)以便快速重新排序...
这是我的排序方法和渲染器的简化版本:
public List<Sprite> SortSpriteList(List<Sprite> list)
{
for (int i = 0; i < list.Count - 1; i++)
{
int lowest = i;
int j = i + 1;
for (; j < list.Count; j++)
{
if (list[j].Layer < list[lowest].Layer)
{
lowest = j;
}
}
if (lowest != i)
{
Sprite copy = list[i];
list[i] = list[lowest];
list[lowest] = copy;
}
}
return list;
}
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;
}
}
我正在制作一个 2D 游戏引擎,它在基本级别上运行良好。现在我想微调它并为引擎添加一些额外的(但必要的)功能。不幸的是,我坚持使用我的“层”系统。
你可以想象这就像 Unity 中的一样,或者像 Photoshop 中的层......我想确定精灵(图像)的显示顺序。我发现的大多数“解决方案”都说“在另一张图片之前绘制一张图片,这样它就会显示在顶部......”是的,我知道这是如何工作的,但这不是最好的方法,因为游戏可以包含数千个精灵并且渲染顺序也可以由用户动态更改。所以我需要应用某种 'layer' 系统,用户可以在实例化 Sprite 对象时设置顺序 class 或者稍后在需要时通过更改相关 属性 来更改图层顺序值(类似于“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 class 没有什么特别的...构造函数从给定目录加载图像并设置用户通过构造函数传递的属性,如位置、名称等... 'RegisterSprite' 只有一个包含所有精灵的列表。当用户创建精灵的对象时,精灵会添加到列表中。(如墙或敌人......)精灵 class 自动将新精灵注册到列表中,仅此而已!
请尝试提供一些我可以集成到我的引擎中的想法或解决方案。或者让我知道是否有内置方法可以做到这一点。很难想象没有任何方法可以决定哪个 bitmap/image 比其他人高...谢谢!
好的.. TaW 在问题的评论部分发布了我的问题的解决方案,但我会在这里自行回答,因为 TaW 看起来不写任何答案更长。
创建一个'layer system'和我当时写题时想的一样简单。我向 Sprite class 添加了一个整数变量 (layerOrder),因此我可以为每个 Sprite(图像)设置我需要的顺序。正如我提到的,我有一个列表 (RegisterSprite),当我创建它们(实例化对象)时,我在其中存储每个精灵。然后我写了一个小方法,可以根据精灵的 layerOrder 值对列表进行排序。这样,列表中的第一个精灵将是最低值,最后一个是最高值。我使用 foreach 循环将列表中的每个图像绘制到屏幕上,当然,这将从第一个元素开始。因此,具有较低 layerOrder 的精灵将首先绘制,在具有较高值的精灵之下。在渲染器(使用 foreach)部分之前调用排序方法很重要。
如果需要在 'runtime' 更改精灵图层顺序,只需在更改值后调用排序算法或创建一个方法来更改图层顺序,该方法也会自动重新排序列表。如果需要优化算法(堆优化?)或编写另一个更新列表的算法(更改相关元素)以便快速重新排序...
这是我的排序方法和渲染器的简化版本:
public List<Sprite> SortSpriteList(List<Sprite> list)
{
for (int i = 0; i < list.Count - 1; i++)
{
int lowest = i;
int j = i + 1;
for (; j < list.Count; j++)
{
if (list[j].Layer < list[lowest].Layer)
{
lowest = j;
}
}
if (lowest != i)
{
Sprite copy = list[i];
list[i] = list[lowest];
list[lowest] = copy;
}
}
return list;
}
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;
}
}