Загрузка чанков вокруг игрока

Я делаю Voxel Engine на Java. У меня работает система чанков, но я обеспокоен тем, что загружаю чанки не самым эффективным способом.

Мои фрагменты хранятся внутри хэш-карты, например:

Map<Vector2f, Chunk> chunkList = new HashMap<Vector2f, Chunk>(); // Create an array for the chunks

Таким образом, у меня есть 2D-массив фрагментов, и я могу получить к ним доступ следующим образом:

chunkList.get(new Vector2f(0, 0));

Вот как я загружаю все куски вокруг игрока:

public void updateChunks( Vector3f cameraPosition ) { // Update all the chunks

    Thread chunkThread = new Thread() {

        public void run() {

            int playerChunkX = (int) Math.floor(cameraPosition.x / ( Chunk.CHUNK_SIZE * BlockVertices.BLOCK_SIZE )); // Get the current chunk that the player is in on the X - Axis
            int playerChunkZ = (int) Math.floor(cameraPosition.z / ( Chunk.CHUNK_SIZE * BlockVertices.BLOCK_SIZE )); // Get the current chunk that the player is in on the Z - Axis

            System.out.println( playerChunkX + ", " + playerChunkZ );

            for (int i = 0; i < Camera.view_distance; i++) { // X - Axis iteration
                for (int j = 0; j < Camera.view_distance; j++) { // Z - Axis iteration
                    if( !(chunkList.containsKey( new Vector2f( playerChunkX + i, playerChunkZ ) ) )) { // If the chunk manager doesn't have a chunk at the specified location

                        chunkList.put(new Vector2f(playerChunkX + i, playerChunkZ), new Chunk(perlin, playerChunkX + i, playerChunkZ)); // Create a new chunk
                        chunkList.get(new Vector2f(playerChunkX + i, playerChunkZ)).load(); // Load the new chunk

                    }

                    if (!(chunkList.containsKey(new Vector2f(playerChunkX + i, playerChunkZ + j)))) { // If the chunk manager doesn't have a chunk at the specified location

                        chunkList.put(new Vector2f(playerChunkX + i, playerChunkZ + j), new Chunk(perlin, playerChunkX + i, playerChunkZ + j)); // Create a new chunk
                        chunkList.get(new Vector2f(playerChunkX + i, playerChunkZ + j)).load(); // Load the new chunk

                    }

                    if (!(chunkList.containsKey(new Vector2f(playerChunkX + i, playerChunkZ - j)))) { // If the chunk manager doesn't have a chunk at the specified location

                        chunkList.put(new Vector2f(playerChunkX + i, playerChunkZ - j), new Chunk(perlin, playerChunkX + i, playerChunkZ - j)); // Create a new chunk
                        chunkList.get(new Vector2f(playerChunkX + i, playerChunkZ - j)).load(); // Load the new chunk

                    }

                    if (!(chunkList.containsKey(new Vector2f(playerChunkX - i, playerChunkZ - j)))) { // If the chunk manager doesn't have a chunk at the specified location

                        chunkList.put(new Vector2f(playerChunkX - i, playerChunkZ - j), new Chunk(perlin, playerChunkX - i, playerChunkZ - j)); // Create a new chunk
                        chunkList.get(new Vector2f(playerChunkX - i, playerChunkZ - j)).load(); // Load the new chunk

                    }

                    if (!(chunkList.containsKey(new Vector2f(playerChunkX - i, playerChunkZ + j)))) { // If the chunk manager doesn't have a chunk at the specified location

                        chunkList.put(new Vector2f(playerChunkX - i, playerChunkZ + j), new Chunk(perlin, playerChunkX - i, playerChunkZ + j)); // Create a new chunk
                        chunkList.get(new Vector2f(playerChunkX - i, playerChunkZ + j)).load(); // Load the new chunk

                    }

                }
            }

        }

    };
    chunkThread.run();

}

Как видите, я использую для этого отдельный поток для лучшей производительности. Есть ли лучший способ сделать это? Если да, то как наиболее эффективно загружать фрагменты вокруг проигрывателя?


person Grim Reaper    schedule 03.10.2017    source источник
comment
Лучший способ основан на мнении. Остальная часть вашего вопроса относится к просмотру кода, для которого существует другой сайт. У вас есть конкретный вопрос по программированию, который будет актуален для SO? Кроме того, не применяйте преждевременную оптимизацию. Вы измерили фактическое влияние использования отдельных потоков? Я бы, вероятно, использовал только один фоновый поток загрузки и поставил бы его в очередь последовательно.   -  person Polygnome    schedule 03.10.2017
comment
Под лучшим я имел в виду наиболее эффективный. Ошибка с моей стороны, я отредактирую вопрос. В настоящее время дополнительный поток действительно увеличивает FPS в игре на 10-20%, но это должно быть более значительным, когда я добавлю больше вещей в куски. Тем не менее, я никогда не хотел, чтобы это было обзором кода. Я опубликовал свое решение этой проблемы, но я не думаю, что это самый эффективный способ сделать это, поэтому этот пост.   -  person Grim Reaper    schedule 03.10.2017
comment
Не существует единого лучшего решения. Это слишком сильно зависит от специфики вашей игры, например. как часто игрок перемещается туда-сюда между границами чанка. Кроме того, программирование заключается не в поиске наилучшего решения, а в поиске решений, которые *работают достаточно хорошо*+. если вы всегда пытаетесь найти лучшее решение (по какой бы метрике это ни было, попробуйте сначала придумать объективную метрику для хороших решений, это сложно), вы никогда ничего не добьетесь.   -  person Polygnome    schedule 03.10.2017
comment
Я не могу не согласиться с этим. Вы совершенно правы. Я просто буду работать с тем, что работает, пока не найду лучшее решение. Ваше здоровье   -  person Grim Reaper    schedule 03.10.2017


Ответы (1)


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

Я не знаю, возможно ли это для вас, но я бы предложил переключить управление на само движение, таким образом вы можете избежать этого потока в цикле while (true). Итак, пунктуально выполняя расчет для загрузки чанков.

person Gaetano Piazzolla    schedule 03.10.2017
comment
Я не совсем уверен, что понял вас полностью. Вы предлагаете, чтобы я вызывал это только тогда, когда игрок двигается? - person Grim Reaper; 03.10.2017
comment
Ага. Вы можете это сделать? - person Gaetano Piazzolla; 03.10.2017
comment
Да, я могу. Я не думал об этом раньше. Это улучшает некоторые вещи. Как вы думаете, будет ли этот код эффективным? Включено много проверок и циклов for, что вызывает опасения по поводу фактической эффективности загрузки фрагментов таким образом. - person Grim Reaper; 03.10.2017
comment
Вы должны смотреть на положение камеры и пересчитывать фрагменты только тогда, когда оно превышает определенный порог от последней позиции, где вы пересчитывали. Вы также можете рассмотреть возможность использования подхода октодерева, чтобы быстро сократить пространство поиска, а не перебирать каждый возможный фрагмент. - person Tim B; 03.10.2017
comment
Я люблю это. Я буду обновлять чанки только после того, как игрок переместится на указанное количество :) Что касается октодеревьев, я кое-что читал и не думаю, что они будут хороши для моего воксельного движка. Изменение вокселя потребовало бы много работы и было бы медленнее, чем обычный массив блоков. Если бы я использовал октодерево для фрагментов, я не уверен, насколько хорошо это сработает, поскольку я постоянно загружаю новые фрагменты, а это означает, что мне пришлось бы добавлять много точек в дерево. Поскольку эта тема для меня новая, я могу ошибаться в этом, поэтому, пожалуйста, поправьте меня, если я ошибаюсь :) - person Grim Reaper; 03.10.2017