feat: 멀티플레이어 네트워크 동기화 구현
- 로비 씬 추가 및 LobbyManager/LobbyUI/LobbySceneBuilder 구현 - NetworkPrefabsList로 플레이어 프리팹 등록 (PlayerPrefab 자동스폰 비활성화) - PlayerMovement 서버 권한 이동 아키텍처로 전환 - NetworkVariable<Vector2>로 클라이언트 입력 → 서버 전달 - 점프 JumpRequestRpc로 서버 검증 후 실행 - 보스 프리팹에 NetworkTransform/NetworkAnimator 추가 (서버 권한) - SkillController를 NetworkBehaviour로 전환 - PlaySkillClipClientRpc로 클립 override + 재생 원자적 동기화 - OnEffect/OnSkillEnd 클라이언트 실행 차단 - WeaponEquipment 클라이언트 무기 시각화 동기화 수정 - registeredWeapons 인덱스 기반 NetworkVariable 동기화 - SpawnWeaponVisualsLocal로 클라이언트 무기 생성 - 중복 Instantiate 버그 수정 Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -27,6 +27,10 @@ namespace Colosseum
|
||||
/// </summary>
|
||||
public class GameManager : NetworkBehaviour
|
||||
{
|
||||
[Header("Player")]
|
||||
[Tooltip("플레이어 프리팹 (NetworkObject 포함)")]
|
||||
[SerializeField] private GameObject playerPrefab;
|
||||
|
||||
[Header("UI Prefabs")]
|
||||
[Tooltip("게임 오버 UI 프리팹")]
|
||||
[SerializeField] private GameObject gameOverUIPrefab;
|
||||
@@ -107,33 +111,62 @@ namespace Colosseum
|
||||
if (loadSceneMode == LoadSceneMode.Single)
|
||||
{
|
||||
if (debugMode)
|
||||
{
|
||||
Debug.Log($"[GameManager] Scene loaded: {sceneName}");
|
||||
}
|
||||
|
||||
// 씬 로드 완료 시 플레이어 리스폰
|
||||
if (IsServer)
|
||||
StartCoroutine(SpawnPlayersAndRespawn(clientsCompleted));
|
||||
}
|
||||
}
|
||||
|
||||
private IEnumerator SpawnPlayersAndRespawn(List<ulong> clientsCompleted)
|
||||
{
|
||||
if (playerPrefab == null)
|
||||
{
|
||||
Debug.LogWarning("[GameManager] playerPrefab이 설정되지 않았습니다. 인스펙터에서 할당하세요.");
|
||||
RespawnAllPlayersClientRpc();
|
||||
yield break;
|
||||
}
|
||||
|
||||
Debug.Log($"[GameManager] SpawnPlayersAndRespawn: clientsCompleted=[{string.Join(",", clientsCompleted)}]");
|
||||
|
||||
// 씬 로드를 완료한 클라이언트마다 플레이어 스폰
|
||||
foreach (ulong clientId in clientsCompleted)
|
||||
{
|
||||
var go = Instantiate(playerPrefab);
|
||||
var no = go.GetComponent<NetworkObject>();
|
||||
if (no != null)
|
||||
{
|
||||
RespawnAllPlayersClientRpc();
|
||||
no.SpawnAsPlayerObject(clientId, true);
|
||||
Debug.Log($"[GameManager] Spawned player for clientId={clientId}");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.LogError($"[GameManager] playerPrefab에 NetworkObject가 없습니다!");
|
||||
Destroy(go);
|
||||
}
|
||||
}
|
||||
|
||||
// 클라이언트가 스폰된 오브젝트를 받을 시간 여유
|
||||
yield return new WaitForSeconds(0.5f);
|
||||
RespawnAllPlayersClientRpc();
|
||||
}
|
||||
|
||||
[Rpc(SendTo.ClientsAndHost)]
|
||||
private void RespawnAllPlayersClientRpc()
|
||||
{
|
||||
// 모든 플레이어 리스폰
|
||||
// 서버: 모든 플레이어 체력/상태 리셋
|
||||
var players = FindObjectsByType<PlayerNetworkController>(FindObjectsSortMode.None);
|
||||
foreach (var player in players)
|
||||
{
|
||||
player.Respawn();
|
||||
}
|
||||
|
||||
// 카메라 재설정
|
||||
var playerMovement = FindObjectsByType<PlayerMovement>(FindObjectsSortMode.None);
|
||||
foreach (var movement in playerMovement)
|
||||
// 카메라 재설정 — 자신이 소유한 플레이어만
|
||||
var playerMovements = FindObjectsByType<PlayerMovement>(FindObjectsSortMode.None);
|
||||
foreach (var movement in playerMovements)
|
||||
{
|
||||
movement.RefreshCamera();
|
||||
if (movement.IsOwner)
|
||||
movement.RefreshCamera();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user