Я выпускаю сценарий оптимизации для моего учебного проекта, в котором я работаю. пытаюсь создать базовую функциональность Minecraft.
Я создал два метода для граничных кубов в кусках, которые гарантируют, что граничные кубы, покрытые с каждого направления другими кубами, не будут создавать экземпляры или, если они уже созданы, они будут деактивированы.
Проблема в том, что эти два метода < strong>содержат избыточный код, от которого я хочу избавиться, чтобы сделать этот скрипт чище.
private void BorderCubesOptimizationsOfNewChunk(CubeData newCubeData, Dictionary newChunkFieldData, Vector3 centerOfNeigbourChunk, Vector3 neighbourCubePosition, Border border, Corner corner)
{
Dictionary neighbourChunk = mapGenerator.dictionaryOfCentersWithItsChunkField[centerOfNeigbourChunk];
// WIP
if (corner != Corner.Null)
{
if (corner == Corner.XNegative_ZNegative)
{
}
else if (corner == Corner.XNegative_ZPositive)
{
}
else if (corner == Corner.XPositive_ZNegative)
{
}
else if (corner == Corner.XPositive_ZPositive)
{
}
return;
}
// If there is a Cube in New Chunk bellow New Cube, then return
if (!newChunkFieldData.ContainsKey(newCubeData.position - Vector3.up))
{
return;
}
// If there is a Cube in New Chunk above New Cube, then return
if (!newChunkFieldData.ContainsKey(newCubeData.position + Vector3.up))
{
return;
}
if (border != Border.XNegative)
{
// If there is a Cube in New Chunk at decremented X position, then return
if (!newChunkFieldData.ContainsKey(newCubeData.position - Vector3.right))
{
return;
}
}
else
{
// If there is a Cube in Neighbour Chunk at decremented X position, then return
if (!neighbourChunk.ContainsKey(neighbourCubePosition))
{
return;
}
}
if (border != Border.XPositive)
{
// If there is a Cube in New Chunk at incremented X position, then return
if (!newChunkFieldData.ContainsKey(newCubeData.position + Vector3.right))
{
return;
}
}
else
{
// If there is a Cube in Neighbour Chunk at incremented X position, then return
if (!neighbourChunk.ContainsKey(neighbourCubePosition))
{
return;
}
}
if (border != Border.ZNegative)
{
// If there is a Cube in New Chunk at decremented Z position, then return
if (!newChunkFieldData.ContainsKey(newCubeData.position - Vector3.forward))
{
return;
}
}
else
{
// If there is a Cube in Neighbour Chunk at decremented Z position, then return
if (!neighbourChunk.ContainsKey(neighbourCubePosition))
{
return;
}
}
if (border != Border.ZPositive)
{
// If there is a Cube in New Chunk at incremented Z position, then return
if (!newChunkFieldData.ContainsKey(newCubeData.position + Vector3.forward))
{
return;
}
}
else
{
// If there is a Cube in Neighbout Chunk at incremented Z position, then return
if (!neighbourChunk.ContainsKey(neighbourCubePosition))
{
return;
}
}
newCubeData.isCubeDataSurrounded = true;
}
Тогда у меня есть очень похожий метод, который гарантирует, что если Соседний куб в Соседний блок окружен с каждой стороны, то он деактивируется. этот куб. Но это не единственное отличие: чтобы все заработало, мне пришлось поменять местами операторы для граничных условий.
private void BorderCubesOptimizationsOfNeighbourChunk(Dictionary newChunkFieldData, CubeData newCubeData, Vector3 centerOfNeigbourChunk, Vector3 neighbourCubePosition, Border border, Corner corner)
{
Dictionary neighbourChunk = mapGenerator.dictionaryOfCentersWithItsChunkField[centerOfNeigbourChunk];
// WIP
if (corner != Corner.Null)
{
if (true)
{
}
else if (true)
{
}
else if (true)
{
}
else if (true)
{
}
return;
}
// If there is a Cube in Neighbour Chunk bellow Neighbour Cube, then return
if (!neighbourChunk.ContainsKey(neighbourCubePosition - Vector3.up))
{
return;
}
// If there is a Cube in Neighbour Chunk bellow Neighbour Cube, then return
if (!neighbourChunk.ContainsKey(neighbourCubePosition + Vector3.up))
{
return;
}
if (border != Border.XNegative)
{
// If there is Cube in Neighbour Chunk at incremented X position, then return
if (!neighbourChunk.ContainsKey(neighbourCubePosition + Vector3.right))
{
return;
}
}
else
{
// If there is Cube in New Chunk at incremented X position, then return
if (!newChunkFieldData.ContainsKey(newCubeData.position))
{
return;
}
}
if (border != Border.XPositive)
{
// If there is Cube in Neighbour Chunk at decremented X position, then return
if (!neighbourChunk.ContainsKey(neighbourCubePosition - Vector3.right))
{
return;
}
}
else
{
// If there is Cube in New Chunk at decremented X position, then return
if (!newChunkFieldData.ContainsKey(newCubeData.position))
{
return;
}
}
if (border != Border.ZNegative)
{
// If there is Cube in Neighbour Chunk at incremented Z position, then return
if (!neighbourChunk.ContainsKey(neighbourCubePosition + Vector3.forward))
{
return;
}
}
else
{
// If there is Cube in New Chunk at incremented Z position, then return
if (!newChunkFieldData.ContainsKey(newCubeData.position))
{
return;
}
}
if (border != Border.ZPositive)
{
// If there is cube in Neighbour Chunk at decremented Z position, then return
if (!neighbourChunk.ContainsKey(neighbourCubePosition - Vector3.forward))
{
return;
}
}
else
{
// If there is cube in New Chunk at decremented Z position, then return
if (!newChunkFieldData.ContainsKey(newCubeData.position))
{
return;
}
}
neighbourChunk[neighbourCubePosition].cubeInstance.gameObject.SetActive(false);
И здесь я скорее предоставляю метод, использующий оба метода, которые я предоставил выше. Этот метод тоже можно оптимизировать, чтобы избавиться от лишнего кода, но я буду работать над этим в будущем.
private void OptimizeDataOfNewChunk(CubeData newCubeData, Vector3 centerOfUpcomingChunk, Dictionary newChunkFieldData)
{
Border border = Border.Null;
Corner corner = Corner.Null;
// Negative X border of actual chunk
// If actual cube postion is on border of actual chunk and if border chunk exist, optimalize borders of these two chunks
if ((newCubeData.position.x - (mapGenerator.gridSize.x / 2)) % mapGenerator.gridSize.x == 0)
{
if (mapGenerator.dictionaryOfCentersWithItsChunkField.ContainsKey(centerOfXPositiveNeighbourChunk))
{
border = Border.XPositive;
// WIP: X positive - Z positive corner
if (newCubeData.position.z == centerOfUpcomingChunk.z + Mathf.Ceil((float)mapGenerator.gridSize.x / 2.0f) - 1.0f)
{
}
// WIP: X positive - Z negative corner
else if (newCubeData.position.z == centerOfUpcomingChunk.z - Mathf.Ceil((float)mapGenerator.gridSize.x / 2.0f) + 1.0f)
{
}
BorderCubesOptimizationsOfNewChunk(newCubeData, newChunkFieldData, centerOfXPositiveNeighbourChunk, newCubeData.position + Vector3.right, border, Corner.Null);
BorderCubesOptimizationsOfNeighbourChunk(newChunkFieldData, newCubeData, centerOfXPositiveNeighbourChunk, newCubeData.position + Vector3.right, border, Corner.Null);
return;
}
}
// Positive X border of actual chunk
// If actual cube postion is on border of actual chunk and if border chunk exist, optimalize borders of these two chunks
else if ((newCubeData.position.x + (mapGenerator.gridSize.x / 2)) % mapGenerator.gridSize.x == 0)
{
if (mapGenerator.dictionaryOfCentersWithItsChunkField.ContainsKey(centerOfXNegativeNeighbourChunk))
{
border = Border.XNegative;
// WIP: X negative - Z positive corner
if (newCubeData.position.z == centerOfUpcomingChunk.z + Mathf.Ceil((float)mapGenerator.gridSize.z / 2.0f) - 1.0f)
{
}
// WIP: X negative - Z negative corner
else if (newCubeData.position.z == centerOfUpcomingChunk.z - Mathf.Ceil((float)mapGenerator.gridSize.z / 2.0f) + 1.0f)
{
}
BorderCubesOptimizationsOfNewChunk(newCubeData, newChunkFieldData, centerOfXNegativeNeighbourChunk, newCubeData.position + Vector3.left, border, Corner.Null);
BorderCubesOptimizationsOfNeighbourChunk(newChunkFieldData, newCubeData, centerOfXNegativeNeighbourChunk, newCubeData.position + Vector3.left, border, Corner.Null);
return;
}
}
// Negative Z border of actual chunk
// If actual cube postion is on border of actual chunk and if border chunk exist, optimalize borders of these two chunks
else if ((newCubeData.position.z - (mapGenerator.gridSize.x / 2)) % mapGenerator.gridSize.x == 0)
{
if (mapGenerator.dictionaryOfCentersWithItsChunkField.ContainsKey(centerOfZPositiveNeighbourChunk))
{
border = Border.ZPositive;
// Z positive - X positive corner
if (newCubeData.position.x == centerOfUpcomingChunk.x + Mathf.Ceil((float)mapGenerator.gridSize.x / 2.0f) - 1.0f)
{
}
// Z negative - X negative corner
else if (newCubeData.position.x == centerOfUpcomingChunk.x - Mathf.Ceil((float)mapGenerator.gridSize.x / 2.0f) + 1.0f)
{
}
BorderCubesOptimizationsOfNewChunk(newCubeData, newChunkFieldData, centerOfZPositiveNeighbourChunk, newCubeData.position + Vector3.forward, border, Corner.Null);
BorderCubesOptimizationsOfNeighbourChunk(newChunkFieldData, newCubeData, centerOfZPositiveNeighbourChunk, newCubeData.position + Vector3.forward, border, Corner.Null);
return;
}
}
// Postive Z border of actual chunk
// If actual cube postion is on border of actual chunk and if border chunk exist, optimalize borders of these two chunks
else if ((newCubeData.position.z + (mapGenerator.gridSize.x / 2)) % mapGenerator.gridSize.x == 0)
{
if (mapGenerator.dictionaryOfCentersWithItsChunkField.ContainsKey(centerOfZNegativeNeighbourChunk))
{
border = Border.ZNegative;
// Z negative - X positive corner
if (newCubeData.position.x == centerOfUpcomingChunk.x + Mathf.Ceil((float)mapGenerator.gridSize.x / 2.0f) - 1.0f)
{
}
// Z negative - X negative corner
else if (newCubeData.position.x == centerOfUpcomingChunk.x - Mathf.Ceil((float)mapGenerator.gridSize.x / 2.0f) + 1.0f)
{
}
BorderCubesOptimizationsOfNewChunk(newCubeData, newChunkFieldData, centerOfZNegativeNeighbourChunk, newCubeData.position + Vector3.back, border, Corner.Null);
BorderCubesOptimizationsOfNeighbourChunk(newChunkFieldData, newCubeData, centerOfZNegativeNeighbourChunk, newCubeData.position + Vector3.back, border, Corner.Null);
return;
}
}
DeactiavateSurroundedCubeData(newCubeData, newChunkFieldData);
}
Я думаю, что можно поместить все условия из методов BorderCubesOptimizationsOfNewChunk и BorderCubesOptimizationsOfNeighbourChunk в один метод, используя универсальные шаблоны.
Я знаю, что такое дженерики, и спокойно знаю, как использовать их на очень низком уровне, но раньше я не использовал их в более сложном коде. Я пытался найти документацию и видео, чтобы научиться использовать дженерики, но это не помогло мне даже убедиться, что я на правильном пути.
Также я попросил ChatGPT разделить эти два метода на один, используя дженерики, и ни один из его ответов ни на шаг не приблизил меня к решению этой головоломки. Я попробовал одну реализацию, которую она мне предоставила, но она дала мне внеочередной ответ, который делает дженерики метода OptimizeDataOfNewChunk, но я даже не использовал ее.
Однако, даже если я попытаюсь использовать дженерики для обобщения словарей, которые я использую как фрагменты, я не знаю, как обеспечить это для Соседних кубов или Новых кубов , будут оцененные операторы с соответствующими условиями.
Буду очень благодарен за советы по дизайну или ссылки на обучение материал, который предоставит мне эффективный способ решить эту проблему.
Тема решена. Мой новый код выглядит так.
private void BorderCubeOptimizationSequence(Dictionary newChunkFieldData, CubeData newCubeData, Border newChunkBorder, Dictionary neighbourChunkField, Vector3 neighbourCubePosition, Border neighbourChynkBorder)
{
// Return if New Cube in New Chunk isn't surrounded with cubes from each sides
if (!IsBorderCubeSurrounded(newChunkFieldData, newCubeData.position, neighbourChunkField, neighbourCubePosition, newChunkBorder))
{
return;
}
newCubeData.isCubeDataSurrounded = true;
// Return if Neighbor Cube in Neighbor Chunk isn't surrounded with cubes from each sides
if (!IsBorderCubeSurrounded(neighbourChunkField, neighbourCubePosition, newChunkFieldData, newCubeData.position, neighbourChynkBorder))
{
return;
}
neighbourChunkField[neighbourCubePosition].cubeInstance.gameObject.SetActive(false);
}
private bool IsBorderCubeSurrounded(Dictionary firstChunkFieldData, Vector3 firstCubePosition, Dictionary secondChunkFieldData, Vector3 secondCubePosition, Border border)
{
foreach (Border actaualBorder in borders)
{
foreach (Vector3 actualDirection in directions)
{
// Continue to the next foreach interation if Actual Direction is the same as Current Border
if (isDirectionSameAsBorder(actualDirection, border))
{
continue;
}
if (actaualBorder != border)
{
if (!firstChunkFieldData.ContainsKey(firstCubePosition + actualDirection))
{
return false;
}
}
else
{
if (!secondChunkFieldData.ContainsKey(secondCubePosition))
{
return false;
}
}
}
}
return true;
}
private bool isDirectionSameAsBorder(Vector3 actualDirection, Border border)
{
if (actualDirection == Vector3.right && border == Border.XPositive)
{
return true;
}
if (actualDirection == -(Vector3.right) && border == Border.XNegative)
{
return true;
}
if (actualDirection == Vector3.forward && border == Border.ZPositive)
{
return true;
}
if (actualDirection == -(Vector3.forward) && border == Border.ZNegative)
{
return true;
}
return false;
}
Подробнее здесь: https://stackoverflow.com/questions/789 ... rp-project