클라이언트에서 밝혀지지 않은 곳의 적이 보이는 문제 수정
This commit is contained in:
@@ -9,6 +9,12 @@ namespace Northbound
|
|||||||
[RequireComponent(typeof(Collider))]
|
[RequireComponent(typeof(Collider))]
|
||||||
public class EnemyUnit : NetworkBehaviour, IDamageable, ITeamMember, IHealthProvider
|
public class EnemyUnit : NetworkBehaviour, IDamageable, ITeamMember, IHealthProvider
|
||||||
{
|
{
|
||||||
|
[Header("Fog of War Visibility")]
|
||||||
|
[Tooltip("전장의 안개에 의한 가시성 제어 활성화")]
|
||||||
|
public bool enableFogVisibility = true;
|
||||||
|
|
||||||
|
[Tooltip("가시성 체크 주기 (초)")]
|
||||||
|
public float visibilityCheckInterval = 0.1f;
|
||||||
[Header("Team Settings")]
|
[Header("Team Settings")]
|
||||||
[Tooltip("이 유닛의 팀 (Hostile = 적대세력, Monster = 몬스터)")]
|
[Tooltip("이 유닛의 팀 (Hostile = 적대세력, Monster = 몬스터)")]
|
||||||
public TeamType enemyTeam = TeamType.Hostile;
|
public TeamType enemyTeam = TeamType.Hostile;
|
||||||
@@ -54,10 +60,20 @@ namespace Northbound
|
|||||||
|
|
||||||
private UnitHealthBar _healthBar;
|
private UnitHealthBar _healthBar;
|
||||||
|
|
||||||
|
// 전장의 안개 가시성
|
||||||
|
private Renderer[] _renderers;
|
||||||
|
private float _visibilityTimer;
|
||||||
|
private bool _lastVisibleState = true;
|
||||||
|
private bool _initializedVisibility = false;
|
||||||
|
private ulong _localPlayerId = ulong.MaxValue;
|
||||||
|
|
||||||
public override void OnNetworkSpawn()
|
public override void OnNetworkSpawn()
|
||||||
{
|
{
|
||||||
base.OnNetworkSpawn();
|
base.OnNetworkSpawn();
|
||||||
|
|
||||||
|
// 렌더러 캐시 (가시성 제어용)
|
||||||
|
_renderers = GetComponentsInChildren<Renderer>();
|
||||||
|
|
||||||
if (IsServer)
|
if (IsServer)
|
||||||
{
|
{
|
||||||
_currentHealth.Value = maxHealth;
|
_currentHealth.Value = maxHealth;
|
||||||
@@ -72,6 +88,12 @@ namespace Northbound
|
|||||||
{
|
{
|
||||||
CreateHealthBar();
|
CreateHealthBar();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 클라이언트에서는 기본적으로 렌더러 비활성화
|
||||||
|
if (enableFogVisibility && IsClient)
|
||||||
|
{
|
||||||
|
SetRenderersEnabled(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void OnNetworkDespawn()
|
public override void OnNetworkDespawn()
|
||||||
@@ -80,6 +102,137 @@ namespace Northbound
|
|||||||
base.OnNetworkDespawn();
|
base.OnNetworkDespawn();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void Update()
|
||||||
|
{
|
||||||
|
// 클라이언트에서만 가시성 체크 (호스트 포함)
|
||||||
|
if (enableFogVisibility && IsClient)
|
||||||
|
{
|
||||||
|
UpdateFogVisibility();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 전장의 안개에 따른 가시성 업데이트 (클라이언트 전용)
|
||||||
|
/// </summary>
|
||||||
|
private void UpdateFogVisibility()
|
||||||
|
{
|
||||||
|
_visibilityTimer += Time.deltaTime;
|
||||||
|
if (_visibilityTimer < visibilityCheckInterval) return;
|
||||||
|
_visibilityTimer = 0f;
|
||||||
|
|
||||||
|
// 로컬 플레이어 ID 캐시
|
||||||
|
if (_localPlayerId == ulong.MaxValue)
|
||||||
|
{
|
||||||
|
_localPlayerId = GetLocalPlayerId();
|
||||||
|
if (_localPlayerId == ulong.MaxValue)
|
||||||
|
{
|
||||||
|
// 로컬 플레이어를 찾지 못함 - 기본적으로 숨김
|
||||||
|
if (_initializedVisibility) return;
|
||||||
|
_initializedVisibility = true;
|
||||||
|
SetRenderersEnabled(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// FogOfWarSystem이 없으면 가시성 체크 안함
|
||||||
|
if (FogOfWarSystem.Instance == null)
|
||||||
|
{
|
||||||
|
if (_initializedVisibility) return;
|
||||||
|
_initializedVisibility = true;
|
||||||
|
SetRenderersEnabled(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 현재 위치의 가시성 확인
|
||||||
|
FogOfWarState state = FogOfWarSystem.Instance.GetVisibilityState(_localPlayerId, transform.position);
|
||||||
|
bool shouldBeVisible = (state == FogOfWarState.Visible);
|
||||||
|
|
||||||
|
// 초기화되지 않은 경우 강제로 설정
|
||||||
|
if (!_initializedVisibility)
|
||||||
|
{
|
||||||
|
_initializedVisibility = true;
|
||||||
|
_lastVisibleState = shouldBeVisible;
|
||||||
|
SetRenderersEnabled(shouldBeVisible);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 상태가 변경된 경우에만 렌더러 업데이트
|
||||||
|
if (shouldBeVisible != _lastVisibleState)
|
||||||
|
{
|
||||||
|
_lastVisibleState = shouldBeVisible;
|
||||||
|
SetRenderersEnabled(shouldBeVisible);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 로컬 플레이어의 실제 ID 가져오기
|
||||||
|
/// </summary>
|
||||||
|
private ulong GetLocalPlayerId()
|
||||||
|
{
|
||||||
|
if (NetworkManager.Singleton == null)
|
||||||
|
{
|
||||||
|
return ulong.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 방법 1: SpawnManager에서 찾기
|
||||||
|
var localPlayer = NetworkManager.Singleton.SpawnManager.GetLocalPlayerObject();
|
||||||
|
|
||||||
|
// 방법 2: LocalClient에서 찾기
|
||||||
|
if (localPlayer == null && NetworkManager.Singleton.LocalClient != null)
|
||||||
|
{
|
||||||
|
localPlayer = NetworkManager.Singleton.LocalClient.PlayerObject;
|
||||||
|
}
|
||||||
|
|
||||||
|
// 방법 3: 직접 검색 (IsLocalPlayer인 플레이어 찾기)
|
||||||
|
if (localPlayer == null)
|
||||||
|
{
|
||||||
|
var allPlayers = FindObjectsByType<NetworkPlayerController>(FindObjectsSortMode.None);
|
||||||
|
foreach (var player in allPlayers)
|
||||||
|
{
|
||||||
|
if (player.IsLocalPlayer)
|
||||||
|
{
|
||||||
|
localPlayer = player.GetComponent<NetworkObject>();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (localPlayer == null)
|
||||||
|
{
|
||||||
|
return ulong.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
var playerController = localPlayer.GetComponent<NetworkPlayerController>();
|
||||||
|
if (playerController == null)
|
||||||
|
{
|
||||||
|
return ulong.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return playerController.OwnerPlayerId;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 모든 렌더러 활성화/비활성화
|
||||||
|
/// </summary>
|
||||||
|
private void SetRenderersEnabled(bool enabled)
|
||||||
|
{
|
||||||
|
if (_renderers == null) return;
|
||||||
|
|
||||||
|
foreach (var renderer in _renderers)
|
||||||
|
{
|
||||||
|
if (renderer != null)
|
||||||
|
{
|
||||||
|
renderer.enabled = enabled;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 체력바도 함께 처리
|
||||||
|
if (_healthBar != null)
|
||||||
|
{
|
||||||
|
_healthBar.gameObject.SetActive(enabled);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private void OnHealthChanged(int previousValue, int newValue)
|
private void OnHealthChanged(int previousValue, int newValue)
|
||||||
{
|
{
|
||||||
if (_healthBar != null)
|
if (_healthBar != null)
|
||||||
|
|||||||
@@ -31,7 +31,7 @@ namespace Northbound
|
|||||||
private Color[] _colors;
|
private Color[] _colors;
|
||||||
private MeshRenderer _meshRenderer;
|
private MeshRenderer _meshRenderer;
|
||||||
private float _updateTimer;
|
private float _updateTimer;
|
||||||
private ulong _localClientId;
|
private ulong _localPlayerId;
|
||||||
private bool _isInitialized;
|
private bool _isInitialized;
|
||||||
|
|
||||||
private void Start()
|
private void Start()
|
||||||
@@ -49,14 +49,15 @@ namespace Northbound
|
|||||||
{
|
{
|
||||||
if (_isInitialized) return;
|
if (_isInitialized) return;
|
||||||
|
|
||||||
_localClientId = NetworkManager.Singleton.LocalClientId;
|
|
||||||
|
|
||||||
var fogSystem = FogOfWarSystem.Instance;
|
var fogSystem = FogOfWarSystem.Instance;
|
||||||
if (fogSystem == null)
|
if (fogSystem == null)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 로컬 플레이어의 실제 ID 가져오기 (없어도 텍스처는 생성)
|
||||||
|
_localPlayerId = GetLocalPlayerId();
|
||||||
|
|
||||||
// 텍스처 생성 (Bilinear filtering for smooth edges)
|
// 텍스처 생성 (Bilinear filtering for smooth edges)
|
||||||
_fogTexture = new Texture2D(fogSystem.gridWidth, fogSystem.gridHeight)
|
_fogTexture = new Texture2D(fogSystem.gridWidth, fogSystem.gridHeight)
|
||||||
{
|
{
|
||||||
@@ -105,11 +106,16 @@ namespace Northbound
|
|||||||
if (!_isInitialized && NetworkManager.Singleton != null && NetworkManager.Singleton.IsClient)
|
if (!_isInitialized && NetworkManager.Singleton != null && NetworkManager.Singleton.IsClient)
|
||||||
{
|
{
|
||||||
Initialize();
|
Initialize();
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!_isInitialized) return;
|
if (!_isInitialized) return;
|
||||||
|
|
||||||
|
// 로컬 플레이어 ID가 아직 없으면 다시 시도
|
||||||
|
if (_localPlayerId == ulong.MaxValue)
|
||||||
|
{
|
||||||
|
_localPlayerId = GetLocalPlayerId();
|
||||||
|
}
|
||||||
|
|
||||||
_updateTimer += Time.deltaTime;
|
_updateTimer += Time.deltaTime;
|
||||||
if (_updateTimer >= updateInterval)
|
if (_updateTimer >= updateInterval)
|
||||||
{
|
{
|
||||||
@@ -135,7 +141,12 @@ namespace Northbound
|
|||||||
if (_meshRenderer != null)
|
if (_meshRenderer != null)
|
||||||
_meshRenderer.enabled = true;
|
_meshRenderer.enabled = true;
|
||||||
|
|
||||||
var fogData = fogSystem.GetPlayerFogData(_localClientId);
|
var fogData = fogSystem.GetPlayerFogData(_localPlayerId);
|
||||||
|
if (fogData == null)
|
||||||
|
{
|
||||||
|
// fogData가 null이면 아직 서버에서 데이터를 받지 못함
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
for (int y = 0; y < fogSystem.gridHeight; y++)
|
for (int y = 0; y < fogSystem.gridHeight; y++)
|
||||||
{
|
{
|
||||||
@@ -164,6 +175,26 @@ namespace Northbound
|
|||||||
_fogTexture.Apply();
|
_fogTexture.Apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 로컬 플레이어의 실제 ID 가져오기
|
||||||
|
/// </summary>
|
||||||
|
private ulong GetLocalPlayerId()
|
||||||
|
{
|
||||||
|
if (NetworkManager.Singleton == null) return ulong.MaxValue;
|
||||||
|
|
||||||
|
var localPlayer = NetworkManager.Singleton.SpawnManager.GetLocalPlayerObject();
|
||||||
|
if (localPlayer != null)
|
||||||
|
{
|
||||||
|
var playerController = localPlayer.GetComponent<NetworkPlayerController>();
|
||||||
|
if (playerController != null)
|
||||||
|
{
|
||||||
|
return playerController.OwnerPlayerId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulong.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Apply box blur smoothing to create smooth circular vision edges
|
/// Apply box blur smoothing to create smooth circular vision edges
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|||||||
@@ -219,7 +219,7 @@ namespace Northbound
|
|||||||
|
|
||||||
[Header("Editor Settings")]
|
[Header("Editor Settings")]
|
||||||
[Tooltip("Disable fog of war in Unity Editor for easier development")]
|
[Tooltip("Disable fog of war in Unity Editor for easier development")]
|
||||||
public bool disableInEditor = true;
|
public bool disableInEditor = false;
|
||||||
|
|
||||||
// 서버: 각 플레이어별 가시성 맵
|
// 서버: 각 플레이어별 가시성 맵
|
||||||
private Dictionary<ulong, FogOfWarData> _serverFogData = new Dictionary<ulong, FogOfWarData>();
|
private Dictionary<ulong, FogOfWarData> _serverFogData = new Dictionary<ulong, FogOfWarData>();
|
||||||
@@ -250,11 +250,18 @@ namespace Northbound
|
|||||||
{
|
{
|
||||||
// Server: Register client connected callback to initialize fog data
|
// Server: Register client connected callback to initialize fog data
|
||||||
NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected;
|
NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected;
|
||||||
|
|
||||||
|
// 호스트 자신의 데이터도 초기화 (OnClientConnected가 호스트에게는 호출되지 않을 수 있음)
|
||||||
|
ulong hostClientId = NetworkManager.Singleton.LocalClientId;
|
||||||
|
if (!_serverFogData.ContainsKey(hostClientId))
|
||||||
|
{
|
||||||
|
_serverFogData[hostClientId] = new FogOfWarData(gridWidth, gridHeight);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (IsClient && !IsServer)
|
// 클라이언트는 로컬 데이터 초기화 (호스트 포함)
|
||||||
|
if (IsClient)
|
||||||
{
|
{
|
||||||
// 클라이언트는 로컬 데이터 초기화
|
|
||||||
_localFogData = new FogOfWarData(gridWidth, gridHeight);
|
_localFogData = new FogOfWarData(gridWidth, gridHeight);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -262,7 +269,7 @@ namespace Northbound
|
|||||||
private void OnClientConnected(ulong clientId)
|
private void OnClientConnected(ulong clientId)
|
||||||
{
|
{
|
||||||
if (!IsServer) return;
|
if (!IsServer) return;
|
||||||
|
|
||||||
// Ensure fog data exists for this client
|
// Ensure fog data exists for this client
|
||||||
if (!_serverFogData.ContainsKey(clientId))
|
if (!_serverFogData.ContainsKey(clientId))
|
||||||
{
|
{
|
||||||
@@ -317,13 +324,18 @@ namespace Northbound
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public FogOfWarData GetPlayerFogData(ulong clientId)
|
public FogOfWarData GetPlayerFogData(ulong clientId)
|
||||||
{
|
{
|
||||||
// 클라이언트는 자신의 로컬 데이터 반환
|
// 클라이언트(호스트 포함)는 자신의 로컬 데이터 반환
|
||||||
if (IsClient && !IsServer)
|
// 서버에서 계산된 시야 데이터는 ClientRpc로 동기화됨
|
||||||
|
if (IsClient)
|
||||||
{
|
{
|
||||||
|
if (_localFogData == null)
|
||||||
|
{
|
||||||
|
_localFogData = new FogOfWarData(gridWidth, gridHeight);
|
||||||
|
}
|
||||||
return _localFogData;
|
return _localFogData;
|
||||||
}
|
}
|
||||||
|
|
||||||
// 서버는 해당 클라이언트의 데이터 반환
|
// 순수 서버(전용 서버)의 경우 서버 데이터 반환
|
||||||
if (!_serverFogData.ContainsKey(clientId))
|
if (!_serverFogData.ContainsKey(clientId))
|
||||||
{
|
{
|
||||||
_serverFogData[clientId] = new FogOfWarData(gridWidth, gridHeight);
|
_serverFogData[clientId] = new FogOfWarData(gridWidth, gridHeight);
|
||||||
@@ -369,8 +381,11 @@ namespace Northbound
|
|||||||
FogOfWarData fogData = kvp.Value;
|
FogOfWarData fogData = kvp.Value;
|
||||||
|
|
||||||
// 해당 클라이언트가 여전히 연결되어 있는지 확인
|
// 해당 클라이언트가 여전히 연결되어 있는지 확인
|
||||||
if (NetworkManager.Singleton == null ||
|
// 호스트의 경우 ConnectedClients에 없을 수 있으므로 별도 체크
|
||||||
!NetworkManager.Singleton.ConnectedClients.ContainsKey(clientId))
|
bool isHost = (clientId == NetworkManager.Singleton.LocalClientId);
|
||||||
|
bool isConnected = NetworkManager.Singleton.ConnectedClients.ContainsKey(clientId);
|
||||||
|
|
||||||
|
if (!isHost && !isConnected)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -39,7 +39,7 @@ namespace Northbound
|
|||||||
private Material[] _originalMaterials;
|
private Material[] _originalMaterials;
|
||||||
private bool _isVisible = false;
|
private bool _isVisible = false;
|
||||||
private float _updateTimer;
|
private float _updateTimer;
|
||||||
private ulong _localClientId;
|
private ulong _localPlayerId;
|
||||||
private bool _isInitialized = false;
|
private bool _isInitialized = false;
|
||||||
private float _objectHeight = 0f;
|
private float _objectHeight = 0f;
|
||||||
|
|
||||||
@@ -130,7 +130,13 @@ namespace Northbound
|
|||||||
{
|
{
|
||||||
if (NetworkManager.Singleton != null && NetworkManager.Singleton.IsClient)
|
if (NetworkManager.Singleton != null && NetworkManager.Singleton.IsClient)
|
||||||
{
|
{
|
||||||
_localClientId = NetworkManager.Singleton.LocalClientId;
|
_localPlayerId = GetLocalPlayerId();
|
||||||
|
if (_localPlayerId == ulong.MaxValue)
|
||||||
|
{
|
||||||
|
// Local player not found yet - stay hidden
|
||||||
|
SetVisible(false);
|
||||||
|
return;
|
||||||
|
}
|
||||||
_isInitialized = true;
|
_isInitialized = true;
|
||||||
|
|
||||||
// Force immediate visibility update on initialization
|
// Force immediate visibility update on initialization
|
||||||
@@ -152,6 +158,26 @@ namespace Northbound
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 로컬 플레이어의 실제 ID 가져오기
|
||||||
|
/// </summary>
|
||||||
|
private ulong GetLocalPlayerId()
|
||||||
|
{
|
||||||
|
if (NetworkManager.Singleton == null) return ulong.MaxValue;
|
||||||
|
|
||||||
|
var localPlayer = NetworkManager.Singleton.SpawnManager.GetLocalPlayerObject();
|
||||||
|
if (localPlayer != null)
|
||||||
|
{
|
||||||
|
var playerController = localPlayer.GetComponent<NetworkPlayerController>();
|
||||||
|
if (playerController != null)
|
||||||
|
{
|
||||||
|
return playerController.OwnerPlayerId;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return ulong.MaxValue;
|
||||||
|
}
|
||||||
|
|
||||||
private void UpdateVisibility()
|
private void UpdateVisibility()
|
||||||
{
|
{
|
||||||
var fogSystem = FogOfWarSystem.Instance;
|
var fogSystem = FogOfWarSystem.Instance;
|
||||||
@@ -163,7 +189,7 @@ namespace Northbound
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Wait for fog data to be initialized
|
// Wait for fog data to be initialized
|
||||||
var fogData = fogSystem.GetPlayerFogData(_localClientId);
|
var fogData = fogSystem.GetPlayerFogData(_localPlayerId);
|
||||||
if (fogData == null)
|
if (fogData == null)
|
||||||
{
|
{
|
||||||
// Fog data not ready yet - stay hidden
|
// Fog data not ready yet - stay hidden
|
||||||
@@ -171,7 +197,7 @@ namespace Northbound
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
FogOfWarState fogState = fogSystem.GetVisibilityState(_localClientId, transform.position);
|
FogOfWarState fogState = fogSystem.GetVisibilityState(_localPlayerId, transform.position);
|
||||||
|
|
||||||
// Check for distant visibility based on height
|
// Check for distant visibility based on height
|
||||||
bool isDistantVisible = false;
|
bool isDistantVisible = false;
|
||||||
|
|||||||
Reference in New Issue
Block a user