如何以给定的叠加顺序绘制图片? 层数...

问题描述

我正在制作一个在基本层面上运行良好的 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'只是一个包含所有内容的列表的精灵。当用户创建精灵的对象时,精灵会添加到列表中..(如墙壁或敌人...)精灵类会自动将新精灵注册到列表中,仅此而已!

请尝试提供一些我可以集成到我的引擎中的想法或解决方案。或者让我知道是否有内置的方法来做到这一点。很难想象没有任何方法可以决定哪个位图/图像绘制在其他位图/图像之上...谢谢!

解决方法

好的.. TaW 在问题的评论部分发布了我的问题的解决方案,但我会在这里自我回答,因为 TaW 看起来不再写答案了。

创建“图层系统”更简单,就像我写问题时所想的那样。我在 Sprite 类中添加了一个整数变量 (layerOrder),因此我可以设置每个精灵(图像)所需的顺序。正如我提到的,我有一个列表 (RegisterSprite),我在创建它们时存储每个精灵(实例化对象)。然后我写了一个小方法,可以按精灵的 layerOrder 值对列表进行排序。这样,列表中的第一个精灵将是最低值,最后一个是最高值。我使用 foreach 循环将列表中的每个图像绘制到屏幕上——当然——这将从第一个元素开始。因此,具有较低 layerOrder 的精灵将首先被绘制,在具有较高值的​​精灵之下。在渲染器(使用 foreach)部分之前调用排序方法很重要。

如果需要在“运行时”更改精灵 layerOrder,只需在更改值后调用排序算法或创建一个更改 layerOrder 的方法,该方法也会自动重新排序列表。如果需要,优化算法(堆优化?)或编写另一个更新列表(更改相关元素)的算法,以便快速重新排序...

这是我的排序方法和渲染器的简化版本:

    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;
    }
}