Встроенные циклы For для карты осадков с шумом Perlin в игровом движке Unity3d - PullRequest
0 голосов
/ 08 февраля 2020

Я делаю карту осадков для эксперимента с шумом Перлина, где я также создаю биомы.

Я использую температуру и количество осадков для определения биома определенного пикселя, у меня есть программа для осадков, но кратное значение For loops в программе делает Unity3d перестать отвечать на запросы в течение длительного периода времени.

Кто-нибудь знает, как сделать это быстрее? Я посмотрел на inte rnet, но не смог найти ответ

Вот мой код:

public float[,] PrecipMap (float[,] noise,int mapWidth,int mapHeight)
{
    float[,] precipMap = new float[mapWidth, mapHeight];//array that it to be used for precipitation
    float[,] waterTiles = WaterTiles(mapHeight, mapWidth, noise);//array with all values that are water
    for (int y = 0; y < mapHeight; y++)
    {
        for(int x = 0; x < mapWidth; x++)
        {

        float[] distance = new float[count];//distance between pixel and water tile
        for(int wy = 0; wy < mapHeight; wy++)
        {
            for(int wx = 0; wx < mapWidth; wx++)
            {
                if (waterTiles[x, y] == 1) { // if the selected tile in water tiles has water
                    for(int i = 0; i < count; i++)// distance makes an array of all possible distances. 
                        {
                            distance[i] = Mathf.Sqrt(((x + -wx) * (x + -wx)) + ((y +-wy) * (y +-wy)));// finds distance between pixel and water tile 
                        } 

                    }
                }
                Array.Sort(distance); /// sorts distance from least to greatest
                precipMap[x, y] = distance[count-1];//enters in distance

            }
        }
    }

    return precipMap;
}

Если кто-нибудь может помочь, я был бы благодарен. Я очень благодарен за любую помощь / критику.

1 Ответ

0 голосов
/ 08 февраля 2020

Как уже отмечалось, ваши циклы запускаются довольно часто, и по умолчанию все в единице выполняется в основном потоке. Поэтому, прежде чем Unity сможет отрендерить следующий кадр, ваш метод должен завершить sh.

Кроме того, вы запускаете Array.Sort, что довольно дорого, и выделяете новые массивы для каждой итерации, что также делает ваш G C занятым !

Тогда я не вижу, для чего хорош ваш массив distance. Переменная i - это Neve, используемая в подсчете yoir, поэтому вы просто заполняете все 1500 записей одним и тем же значением, сортируете его и считываете последнее ... Они все равно будут равны, так что это полностью избыточно!

Также вы проверяете избыточно

if (waterTiles[x, y] == 1)

, что будет достаточно для проверки один раз , как только у вас есть x и y, и это будет необязательно выполнено ниже в рамках вложенных циклов. - циклы, которые вы могли бы полностью пропустить, если условие в любом случае ложно.

Вы могли бы фактически переместить весь ваш метод в поток и ждать результата, используя asyn c await (также см. Использование asyn c -aaait в Unity3D ). К сожалению, я не эксперт по async-await, но это должно сделать

public async void CalculatePrecipMap(float[,] noise, int mapWidth, int mapHeight, Action<float[,]> callback)
{
    var result = await PrecipMap(noise, mapWidth, mapHeight);

    callback?.Invoke(result);
}

private async Task<float[,]> PrecipMap (float[,] noise,int mapWidth,int mapHeight)
{
    //array that it to be used for precipitation
    float[,] precipMap = new float[mapWidth, mapHeight];
    //array with all values that are water
    float[,] waterTiles = WaterTiles(mapHeight, mapWidth, noise);

    for (var y = 0; y < mapHeight; y++)
    {
        for(var x = 0; x < mapWidth; x++)
        {   
            // Skip as soon as possible
            // Completely unnecessary to run your loop at all if this is already false
            if (waterTiles[x, y] != 1) continue; 

            // if the selected tile in water tiles has water

            for(var wy = 0; wy < mapHeight; wy++)
            {
                for(var wx = 0; wx < mapWidth; wx++)
                {
                    // i is nowhere used in below calculation!
                    // I don't see any reason to use an distance array here at all !!!                      
                    precipMap[x, y] = Mathf.Sqrt(((x + -wx) * (x + -wx)) + ((y +-wy) * (y +-wy)));
                }
            }
        }
    }

    return precipMap;
}

Затем вы можете использовать его с использованием лямбда-выражения, например

CalculatePrecipMap(someNoise, someWidth, someHeight, result =>
{
    // Do something with the result
}

, или с помощью метода, подобного

CalculatePrecipMap(someNoise, someWidth, someHeight, OnResultReady);

private void OnResultReady (float[,] result)
{
    // Do something with the result
}

Примечание: напечатано на смартфоне, но я надеюсь, что идея проясняется

...