2024.12.19(목)
using System.Collections.Generic;
using UnityEngine;
public class UnitFormationManager
{
// 병력을 생성하고 배치하는 메서드
public void CreateAndArrangeUnits(GameObject soldierPrefab, Transform parentTransform, int soldierCount, Vector2Int gridDimensions, string formationType = "Rectangle")
{
if (soldierPrefab == null)
{
Debug.LogError("Soldier prefab is null!");
return;
}
if (parentTransform == null)
{
Debug.LogError("Parent transform is null!");
return;
}
if (gridDimensions.x <= 0 || gridDimensions.y <= 0)
{
Debug.LogError("Invalid grid dimensions! Both rows and columns must be greater than 0.");
return;
}
ClearExistingUnits(parentTransform);
switch (formationType.ToLower())
{
case "rectangle":
ArrangeRectangleFormation(soldierPrefab, parentTransform, soldierCount, gridDimensions);
break;
case "triangle":
ArrangeTriangleFormation(soldierPrefab, parentTransform, soldierCount);
break;
default:
Debug.LogError("Unsupported formation type: " + formationType);
break;
}
}
// 직사각형 형태로 배치
private void ArrangeRectangleFormation(GameObject soldierPrefab, Transform parentTransform, int soldierCount, Vector2Int initialGridDimensions)
{
Collider soldierCollider = soldierPrefab.GetComponent<CapsuleCollider>();
if (soldierCollider == null)
{
Debug.LogError("Soldier prefab does not have a CapsuleCollider component!");
return;
}
float spacingBuffer = 0.5f; // 최소 간격 버퍼
float xSpacing = 2 * ((CapsuleCollider)soldierCollider).radius + spacingBuffer; // 가로 간격
float zSpacing = ((CapsuleCollider)soldierCollider).height + spacingBuffer; // 세로 간격
// 비율에 따라 행과 열 계산
float aspectRatio = (float)initialGridDimensions.x / initialGridDimensions.y;
int targetColumns = Mathf.CeilToInt(Mathf.Sqrt(soldierCount * aspectRatio));
int targetRows = Mathf.CeilToInt((float)soldierCount / targetColumns);
int createdSoldiers = 0;
for (int i = 0; i < targetRows; i++)
{
for (int j = 0; j < targetColumns; j++)
{
if (createdSoldiers >= soldierCount)
{
return;
}
Vector3 position = parentTransform.position + new Vector3(j * xSpacing, 0, i * zSpacing);
position = CalculateNonOverlappingPosition(position, soldierPrefab, parentTransform);
GameObject soldier = Object.Instantiate(soldierPrefab, position, Quaternion.identity, parentTransform);
soldier.name = $"Soldier_{createdSoldiers + 1}";
createdSoldiers++;
}
}
}
// 삼각형 형태로 배치
private void ArrangeTriangleFormation(GameObject soldierPrefab, Transform parentTransform, int soldierCount)
{
float spacingBuffer = 0.5f; // 최소 간격 버퍼
Collider soldierCollider = soldierPrefab.GetComponent<Collider>();
if (soldierCollider == null)
{
Debug.LogError("Soldier prefab does not have a Collider component!");
return;
}
float xSpacing = soldierCollider.bounds.size.x + spacingBuffer;
float zSpacing = soldierCollider.bounds.size.z + spacingBuffer;
int createdSoldiers = 0;
int rowCount = 0;
while (createdSoldiers < soldierCount)
{
rowCount++;
int soldiersInRow = rowCount;
// Ensure at least one soldier in the last row
if (createdSoldiers + soldiersInRow > soldierCount)
{
soldiersInRow = soldierCount - createdSoldiers;
}
for (int j = 0; j < soldiersInRow; j++)
{
float offsetX = -(soldiersInRow - 1) * xSpacing / 2; // 중심 정렬
Vector3 position = CalculateNonOverlappingPosition(parentTransform.position + new Vector3(j * xSpacing + offsetX, 0, rowCount * zSpacing), soldierPrefab, parentTransform);
GameObject soldier = Object.Instantiate(soldierPrefab, position, Quaternion.identity, parentTransform);
soldier.name = $"Soldier_{createdSoldiers + 1}";
createdSoldiers++;
if (createdSoldiers >= soldierCount)
{
return;
}
}
}
}
// 콜라이더를 고려한 위치 계산
private Vector3 CalculateNonOverlappingPosition(Vector3 proposedPosition, GameObject soldierPrefab, Transform parentTransform)
{
Collider prefabCollider = soldierPrefab.GetComponent<CapsuleCollider>();
if (prefabCollider == null)
{
return proposedPosition;
}
Vector3 offset = Vector3.zero;
int maxAttempts = 10;
float minimumSpacing = ((CapsuleCollider)prefabCollider).radius * 2 + 0.5f; // 최소 간격
for (int attempt = 0; attempt < maxAttempts; attempt++)
{
bool isOverlapping = false;
foreach (Transform child in parentTransform)
{
Collider childCollider = child.GetComponent<CapsuleCollider>();
if (childCollider != null)
{
float distance = Vector3.Distance(
childCollider.ClosestPoint(proposedPosition + offset),
proposedPosition + offset
);
if (distance < minimumSpacing)
{
isOverlapping = true;
offset += new Vector3(0.1f, 0, 0.1f);
break;
}
}
}
if (!isOverlapping)
{
return proposedPosition + offset;
}
}
Debug.LogWarning("Could not find a non-overlapping position after max attempts.");
return proposedPosition + offset;
}
// 기존 병사들을 제거하는 메서드
private void ClearExistingUnits(Transform parentTransform)
{
foreach (Transform child in parentTransform)
{
Object.Destroy(child.gameObject);
}
}
// 병력 프리셋 클래스
public class FormationPreset
{
public string Name { get; private set; }
public Vector2Int GridDimensions { get; private set; }
public FormationPreset(string name, Vector2Int gridDimensions)
{
Name = name;
GridDimensions = gridDimensions;
}
}
// 프리셋 리스트를 제공하는 메서드
public List<FormationPreset> GetAvailablePresets()
{
return new List<FormationPreset>
{
new FormationPreset("Square Formation", new Vector2Int(5, 5)),
new FormationPreset("Line Formation", new Vector2Int(10, 1)),
new FormationPreset("Rectangle Formation", new Vector2Int(8, 3)),
new FormationPreset("Triangle Formation", new Vector2Int(0, 0)) // Triangle doesn't need grid dimensions
};
}
}
아... 코드 너무많이 봐서 현기증날거 같아요....