Files
ProjectMD/Assets/Scripts/GameBase/UndergroundGenerator.cs
2026-01-22 18:13:20 +09:00

119 lines
4.2 KiB
C#

using UnityEngine;
using Unity.Netcode;
public class UndergroundGenerator : NetworkBehaviour
{
[Header("Generation Range")]
[SerializeField] private Vector3Int generationRange = new Vector3Int(20, 30, 10);
[SerializeField] private float noiseScale = 0.12f;
[Header("Thresholds (0 to 1)")]
[SerializeField, Range(0, 1)] private float hollowThreshold = 0.35f;
[SerializeField, Range(0, 1)] private float baseResourceThreshold = 0.8f;
[Header("Depth Settings")]
[SerializeField] private float depthFactor = 0.005f; // 깊어질수록 임계값 감소 (자원 증가)
[Header("Prefabs")]
[SerializeField] private GameObject normalBlockPrefab;
[SerializeField] private GameObject resourceBlockPrefab;
[Header("Organization")]
[SerializeField] private string containerName = "UndergroundBlocks";
private Transform _blockContainer; // 블록들을 담을 부모 오브젝트
private float _seedX, _seedY, _seedZ;
private void Awake()
{
_seedX = Random.Range(0f, 99999f);
_seedY = Random.Range(0f, 99999f);
_seedZ = Random.Range(0f, 99999f);
// Hierarchy 정리를 위한 컨테이너 생성
_blockContainer = new GameObject(containerName).transform;
}
public override void OnNetworkSpawn()
{
if (IsServer) GenerateFromGeneratorPivot();
}
private void GenerateFromGeneratorPivot()
{
Vector3Int originGrid = BuildManager.Instance.WorldToGrid3D(transform.position);
for (int x = 0; x < generationRange.x; x++)
{
for (int y = 0; y > -generationRange.y; y--)
{
for (int z = 0; z < generationRange.z; z++)
{
Vector3Int targetGridPos = originGrid + new Vector3Int(x, y, z);
float noise = Get3DNoise(targetGridPos.x, targetGridPos.y, targetGridPos.z);
if (noise < hollowThreshold) continue;
float currentThreshold = baseResourceThreshold + (y * depthFactor);
GameObject prefab = (noise > currentThreshold) ? resourceBlockPrefab : normalBlockPrefab;
SpawnBlock(prefab, targetGridPos);
}
}
}
}
private void SpawnBlock(GameObject prefab, Vector3Int gridPos)
{
if (prefab == null) return;
Vector3 worldPos = BuildManager.Instance.GridToWorld(gridPos);
// 1. 생성 시 부모(Container)를 지정하여 Hierarchy 정리
GameObject block = Instantiate(prefab, worldPos, Quaternion.identity);
// 2. 네트워크 스폰 (Netcode for GameObjects)
block.GetComponent<NetworkObject>().Spawn();
}
private float Get3DNoise(int x, int y, int z)
{
// 대칭 방지를 위한 10000 오프셋 및 시드 적용
float xCoord = (x + _seedX + 10000f) * noiseScale;
float yCoord = (y + _seedY + 10000f) * noiseScale;
float zCoord = (z + _seedZ + 10000f) * noiseScale;
float ab = Mathf.PerlinNoise(xCoord, yCoord);
float bc = Mathf.PerlinNoise(yCoord, zCoord);
float ac = Mathf.PerlinNoise(xCoord, zCoord);
return (ab + bc + ac) / 3f;
}
private void OnDrawGizmosSelected()
{
BuildManager bm = BuildManager.Instance;
if (bm == null) bm = FindFirstObjectByType<BuildManager>(); // 에러 방지 안전장치
if (bm == null) return;
Vector3Int originGrid = bm.WorldToGrid3D(transform.position);
for (int x = 0; x < generationRange.x; x += 2)
{
for (int y = -generationRange.y; y < 0; y += 2)
{
for (int z = 0; z < generationRange.z; z += 2)
{
Vector3Int targetGridPos = originGrid + new Vector3Int(x, y, z);
float noise = Get3DNoise(targetGridPos.x, targetGridPos.y, targetGridPos.z);
if (noise < hollowThreshold) continue;
Gizmos.color = (noise > baseResourceThreshold) ? Color.yellow : new Color(0.5f, 0.5f, 0.5f, 0.2f);
Vector3 pos = bm.GridToWorld(targetGridPos);
Gizmos.DrawSphere(pos, 0.2f);
}
}
}
}
}