Как улучшить производительность процедурной генерации мира - PullRequest
1 голос
/ 06 мая 2020

Я создаю игру в стиле майнкрафт, которая загружается процедурно. Мир построен из столбцов блоков, которые представляют собой стеки по 16 блоков. Каждый кусок представляет собой куб, сделанный из блоков размером 16x16x16, которые, в свою очередь, состоят из четырехугольников (по соображениям производительности).

Когда мой игрок перемещается, я хочу, чтобы столбцы фрагментов в пределах определенного радиуса отображались. Каждый тик я проверяю, какие столбцы блоков находятся в радиусе от игрока, а затем визуализирую их. Когда это происходит, мир замирает на 1-2 секунды. Я изменил это так, чтобы каждый тик отображал только один фрагмент вместо целого столбца фрагмента. Игра зависает примерно на 0,5 - 1 секунду каждый раз.

Код, выполняющий рендеринг, находится здесь:

// Update is called once per frame
void Update()
{
    StartCoroutine("Render");
}

IEnumerator Render()
{
    int radius = 2;
    Vector3 currentPosition = Camera.main.transform.position;
    Vector2 currentChunkPosition = new Vector2((float) Math.Floor(currentPosition.x / Chunk.size), (float) Math.Floor(currentPosition.z / Chunk.size));
    float chunkColumnDistance;

    for (int x = 0; x < world.Size.x; x++)
    {
        for (int y = 0; y < world.Size.y; y++)
        {
            chunkColumnDistance = Mathf.Sqrt((float) Math.Pow(x - currentChunkPosition.x, 2) + (float)Math.Pow(y - currentChunkPosition.y, 2));

            if (chunkColumnDistance <= radius)
            {
                for (int i = ChunkColumn.chunksPerColumn - 1; i > -1; --i)
                {
                    if (world.chunkColumns[x, y].chunks[i].rendered)
                    {
                        continue;
                    }

                   world.chunkColumns[x, y].chunks[i].Render();
                   yield return null;
               }
           }
        }
    }
}

Я всегда ожидал бы небольшой задержки с каждым обновлением, но не до такой степени, чтобы это было заметно для игрока. В настоящее время я запускаю обновление рендеринга как сопрограмму, но я не уверен, где отсюда перейти к go. Может ли кто-нибудь предложить улучшения.

Для справки, проект находится здесь: https://github.com/JoshPJackson/BlockGame/blob/master/Assets/Scripts/Game.cs

EDIT:

I внес изменения, так что я визуализирую только фрагменты, которые находятся в определенном радиусе от игрока, а не каждый фрагмент в столбце фрагментов, который находится в пределах радиуса проигрывателя. Производительность лучше, но все еще не совсем так.

Обновленный код:

IEnumerator Render()
    {
        int radius = 2;
        Vector3 currentPosition = Camera.main.transform.position;
        float chunkDistance;

        for (int x = 0; x < world.Size.x; x++)
        {
            for (int y = 0; y < world.Size.y; y++)
            {
                for (int i = ChunkColumn.chunksPerColumn - 1; i > -1; --i)
                {
                    chunkDistance = Vector3.Distance(currentPosition, world.chunkColumns[x, y].chunks[i].globalPosition);

                    if (chunkDistance <= radius * Chunk.size)
                    {

                        if (world.chunkColumns[x, y].chunks[i].rendered)
                        {
                            continue;
                        }

                        world.chunkColumns[x, y].chunks[i].Render();
                        yield return null;
                    }
                }
            }
        }
    }

1 Ответ

1 голос
/ 07 мая 2020

Копаюсь в коде вашего проекта и похоже, что вы строите весь видимый мир при каждом обновлении. То есть вы создаете новые GameObject для всех видимых квадратов блоков каждого кадра , а затем отбрасываете их все (надеюсь, иначе у вас будет огромная утечка памяти), прежде чем начинать заново со следующего кадра.

Более эффективным подходом было бы создание экземпляров всех ваших GameObject один раз, после того как вы определите свой world.chunksColumns.chunks, а затем используете SetActive(true) или setActive(false) в вызове рендеринга классов блоков. Тогда приведенный выше код должен работать намного быстрее.

...