158 lines
11 KiB
C#
158 lines
11 KiB
C#
using UnityEngine; // 유니티 엔진의 기본 기능을 불러올거에요 -> UnityEngine을
|
|
using System.Collections.Generic; // 리스트 기능을 사용할거에요 -> System.Collections.Generic을
|
|
|
|
namespace GameSystems.Optimization // 최적화 네임스페이스를 정의할거에요 -> GameSystems.Optimization으로
|
|
{
|
|
[DisallowMultipleComponent] // 기능을 제한할거에요 -> 중복 부착을 방지하도록
|
|
[AddComponentMenu("Game Systems/Optimization/Player Range Manager")] // 메뉴를 추가할거에요 -> 컴포넌트 추가 경로에
|
|
public sealed class PlayerRangeManager : MonoBehaviour // 클래스를 선언할거에요 -> 최적화 관리자인 PlayerRangeManager를
|
|
{
|
|
#region Serialized Fields
|
|
|
|
[Header("=== 필수 설정 ===")] // 제목을 표시할거에요 -> === 필수 설정 === 을
|
|
[SerializeField, Tooltip("최적화 설정 에셋")] // 필드를 직렬화할거에요 -> 인스펙터 노출을 위해
|
|
private RenderOptimizationConfig _config; // 변수를 선언할거에요 -> 설정 에셋을 담을 _config를
|
|
|
|
[SerializeField, Tooltip("환경 오브젝트들이 들어있는 부모 폴더 리스트")] // 툴팁을 추가할거에요 -> 설명 문구를
|
|
private List<Transform> _environmentParents = new List<Transform>(); // 리스트를 생성할거에요 -> 부모 폴더들을 관리할 목록을
|
|
|
|
#endregion
|
|
|
|
#region Private Fields
|
|
|
|
private Transform _playerTransform; // 변수를 선언할거에요 -> 플레이어의 위치 정보를 저장할 변수를
|
|
private readonly List<RenderGroup> _renderGroups = new List<RenderGroup>(512); // 리스트를 생성할거에요 -> 렌더 그룹들을 담을 목록을
|
|
|
|
private bool _isInitialized; // 변수를 선언할거에요 -> 초기화 완료 여부를
|
|
private bool _isPaused; // 변수를 선언할거에요 -> 시스템 일시정지 여부를
|
|
|
|
private int _totalObjectCount; // 변수를 선언할거에요 -> 관리 대상 총 개수를
|
|
private int _visibleObjectCount; // 변수를 선언할거에요 -> 화면에 표시 중인 개수를
|
|
private int _lastFrameChangedCount; // 변수를 선언할거에요 -> 지난 프레임의 상태 변화 수를
|
|
private float _nextCheckTime; // 변수를 선언할거에요 -> 다음 검사 시간을
|
|
|
|
#endregion
|
|
|
|
#region Public Properties
|
|
|
|
public bool IsInitialized => _isInitialized; // 값을 반환할거에요 -> 초기화 완료 여부 상태를
|
|
public bool IsPaused => _isPaused; // 값을 반환할거에요 -> 일시정지 여부 상태를
|
|
public int TotalObjectCount => _totalObjectCount; // 값을 반환할거에요 -> 총 관리 개수 수치를
|
|
public int VisibleObjectCount => _visibleObjectCount; // 값을 반환할거에요 -> 현재 표시 개수 수치를
|
|
public float CullingEfficiency => _totalObjectCount > 0 ? 1f - ((float)_visibleObjectCount / _totalObjectCount) : 0f; // 값을 계산해서 반환할거에요 -> 컬링 효율 비율을
|
|
|
|
#endregion
|
|
|
|
private void Awake() { ValidateConfiguration(); } // 함수를 실행할거에요 -> 시작 시 설정을 검증하는 Awake를
|
|
private void Start() { InitializeSystem(); } // 함수를 실행할거에요 -> 시스템을 초기화하는 Start를
|
|
|
|
private void Update() // 함수를 실행할거에요 -> 매 프레임 업데이트 로직인 Update를
|
|
{
|
|
if (!_isInitialized || _isPaused || _playerTransform == null) return; // 조건이 맞으면 중단할거에요 -> 동작 불가능한 상태라면
|
|
|
|
if (Time.time >= _nextCheckTime) // 조건이 맞으면 실행할거에요 -> 다음 검사 시간이 되었다면
|
|
{
|
|
UpdateCulling(); // 함수를 실행할거에요 -> 컬링 업데이트 기능을
|
|
_nextCheckTime = Time.time + GetCheckInterval(); // 값을 갱신할거에요 -> 다음 검사 예정 시간을
|
|
}
|
|
}
|
|
|
|
private void ValidateConfiguration() // 함수를 선언할거에요 -> 설정 누락 여부를 확인하는 ValidateConfiguration을
|
|
{
|
|
if (_config == null) // 조건이 맞으면 실행할거에요 -> 설정 에셋이 비어있다면
|
|
{
|
|
Debug.LogWarning("[PlayerRangeManager] Config가 없습니다! 기본값을 생성합니다."); // 경고를 출력할거에요 -> 자동 생성 메시지를
|
|
_config = RenderOptimizationConfig.CreateDefault(); // 값을 설정할거에요 -> 기본값으로 생성된 에셋을
|
|
}
|
|
}
|
|
|
|
private void InitializeSystem() // 함수를 선언할거에요 -> 전체 시스템을 초기화하는 InitializeSystem을
|
|
{
|
|
FindPlayer(); // 함수를 실행할거에요 -> 플레이어를 찾는 기능을
|
|
ScanEnvironmentObjects(); // 함수를 실행할거에요 -> 주변 오브젝트를 스캔하는 기능을
|
|
|
|
_isInitialized = true; // 상태를 바꿀거에요 -> 초기화 완료인 참(true)으로
|
|
if (ShouldLog()) Debug.Log($"[PlayerRangeManager] 초기화 완료. 대상 그룹: {_totalObjectCount}"); // 조건이 맞으면 로그를 출력할거에요 -> 결과 보고 메시지를
|
|
}
|
|
|
|
private void FindPlayer() // 함수를 선언할거에요 -> 플레이어를 탐색하는 FindPlayer를
|
|
{
|
|
GameObject player = GameObject.FindGameObjectWithTag(GetPlayerTag()); // 오브젝트를 찾을거에요 -> 지정된 태그를 가진 플레이어를
|
|
if (player != null) // 조건이 맞으면 실행할거에요 -> 플레이어를 찾았다면
|
|
{
|
|
_playerTransform = player.transform; // 값을 저장할거에요 -> 플레이어의 Transform 정보를
|
|
}
|
|
else // 조건이 틀리면 실행할거에요 -> 플레이어를 못 찾았다면
|
|
{
|
|
Debug.LogError($"[PlayerRangeManager] '{GetPlayerTag()}' 태그의 플레이어를 찾을 수 없습니다!"); // 에러를 출력할거에요 -> 태그 불일치 메시지를
|
|
}
|
|
}
|
|
|
|
private void ScanEnvironmentObjects() // 함수를 선언할거에요 -> 환경 오브젝트들을 스캔하는 ScanEnvironmentObjects를
|
|
{
|
|
_renderGroups.Clear(); // 리스트를 비울거에요 -> 기존에 있던 렌더 그룹들을
|
|
|
|
foreach (var parent in _environmentParents) // 반복할거에요 -> 등록된 모든 부모 폴더에 대해
|
|
{
|
|
if (parent == null) continue; // 조건이 맞으면 건너뛸거에요 -> 부모가 비어있다면
|
|
|
|
foreach (Transform child in parent) // 반복할거에요 -> 부모 폴더의 모든 자식 오브젝트에 대해
|
|
{
|
|
Renderer[] renderers = child.GetComponentsInChildren<Renderer>(true); // 배열을 가져올거에요 -> 자식 내부의 모든 렌더러들을
|
|
if (renderers.Length > 0) // 조건이 맞으면 실행할거에요 -> 렌더러가 존재한다면
|
|
{
|
|
_renderGroups.Add(new RenderGroup(renderers)); // 리스트에 추가할거에요 -> 새로운 렌더 그룹을 생성해서
|
|
}
|
|
}
|
|
}
|
|
|
|
_totalObjectCount = _renderGroups.Count; // 값을 저장할거에요 -> 총 관리 대상 개수를
|
|
}
|
|
|
|
private void UpdateCulling() // 함수를 선언할거에요 -> 컬링을 업데이트하는 UpdateCulling을
|
|
{
|
|
Vector3 playerPos = _playerTransform.position; // 값을 가져올거에요 -> 현재 플레이어의 위치를
|
|
float range = GetRenderRange(); // 값을 가져올거에요 -> 설정된 렌더링 거리 수치를
|
|
|
|
int changedCount = 0; // 변수를 초기화할거에요 -> 변경 개수를 0으로
|
|
int visibleCount = 0; // 변수를 초기화할거에요 -> 표시 중인 개수를 0으로
|
|
|
|
for (int i = 0; i < _renderGroups.Count; i++) // 반복할거에요 -> 모든 렌더 그룹에 대해
|
|
{
|
|
if (_renderGroups[i].UpdateVisibility(playerPos, range)) changedCount++; // 조건이 맞으면 증가시킬거에요 -> 상태가 바뀌었다면 변경 수를
|
|
if (_renderGroups[i].IsVisible) visibleCount++; // 조건이 맞으면 증가시킬거에요 -> 현재 보이고 있다면 표시 수를
|
|
}
|
|
|
|
_visibleObjectCount = visibleCount; // 값을 저장할거에요 -> 이번 검사 결과의 총 표시 개수를
|
|
_lastFrameChangedCount = changedCount; // 값을 저장할거에요 -> 변화가 발생한 그룹 수를
|
|
}
|
|
|
|
public void RefreshObjectList() { ScanEnvironmentObjects(); } // 함수를 실행할거에요 -> 목록을 새로 스캔하는 기능을
|
|
public void ShowAllObjects() { foreach (var g in _renderGroups) g.ForceShow(); _visibleObjectCount = _totalObjectCount; } // 함수를 실행할거에요 -> 모든 대상을 켜는 기능을
|
|
public void HideAllObjects() { foreach (var g in _renderGroups) g.ForceHide(); _visibleObjectCount = 0; } // 함수를 실행할거에요 -> 모든 대상을 끄는 기능을
|
|
public void SetPaused(bool paused) => _isPaused = paused; // 값을 바꿀거에요 -> 일시정지 여부를 전달받은 인자대로
|
|
|
|
private float GetRenderRange() => _config.RenderRange; // 값을 가져올거에요 -> 설정 파일의 렌더링 사거리 수치를
|
|
private float GetCheckInterval() => _config.CheckInterval; // 값을 가져올거에요 -> 설정 파일의 검사 간격 수치를
|
|
private string GetPlayerTag() => _config.PlayerTag; // 값을 가져올거에요 -> 설정 파일의 플레이어 태그를
|
|
private bool ShouldShowGizmos() => _config.ShowGizmos; // 값을 가져올거에요 -> 설정 파일의 기즈모 표시 여부를
|
|
private bool ShouldLog() => _config.EnableVerboseLogging; // 값을 가져올거에요 -> 설정 파일의 로그 활성화 여부를
|
|
|
|
private void OnDrawGizmos() // 함수를 실행할거에요 -> 기즈모를 그리는 OnDrawGizmos를
|
|
{
|
|
if (!ShouldShowGizmos() || _playerTransform == null) return; // 조건이 맞으면 중단할거에요 -> 표시 설정이 꺼졌거나 플레이어가 없다면
|
|
Gizmos.color = new Color(1f, 0f, 0f, 0.3f); // 색상을 설정할거에요 -> 빨간색 반투명으로
|
|
Gizmos.DrawWireSphere(_playerTransform.position, GetRenderRange()); // 그림을 그릴거에요 -> 플레이어 중심의 사거리 구체를
|
|
}
|
|
|
|
private void OnDrawGizmosSelected() // 함수를 실행할거에요 -> 선택 시 기즈모를 그리는 OnDrawGizmosSelected를
|
|
{
|
|
if (!ShouldShowGizmos() || !_isInitialized) return; // 조건이 맞으면 중단할거에요 -> 표시 설정이 꺼졌거나 초기화 전이라면
|
|
foreach (var group in _renderGroups) // 반복할거에요 -> 모든 렌더 그룹에 대해
|
|
{
|
|
Gizmos.color = group.IsVisible ? new Color(0f, 1f, 0f, 0.5f) : new Color(0.5f, 0.5f, 0.5f, 0.2f); // 색상을 결정할거에요 -> 상태에 따라 초록 혹은 회색으로
|
|
Gizmos.DrawWireSphere(group.ActualCenter, group.BoundingRadius); // 그림을 그릴거에요 -> 각 그룹의 경계면 구체를
|
|
}
|
|
}
|
|
}
|
|
} |