코어, 자원, 벽, 플레이어 시작 위치 설정

Flatkit 기능 일부 활용 테스트
This commit is contained in:
2026-01-26 01:33:26 +09:00
parent cf16910a32
commit 33bd90658a
24 changed files with 1756 additions and 360 deletions

View File

@@ -0,0 +1,121 @@
using System.Collections.Generic;
using System.Linq;
using Unity.Netcode;
using UnityEngine;
namespace Northbound
{
/// <summary>
/// 네트워크 연결 및 스폰 관리
/// </summary>
public class NetworkConnectionHandler : MonoBehaviour
{
[Header("Spawn Settings")]
public List<Transform> spawnPoints = new List<Transform>();
public bool useRandomSpawn = false;
public bool findSpawnPointsAutomatically = true;
private Dictionary<ulong, int> _clientSpawnIndices = new Dictionary<ulong, int>();
private int _nextSpawnIndex = 0;
private void Start()
{
if (findSpawnPointsAutomatically)
{
FindSpawnPoints();
}
if (NetworkManager.Singleton != null)
{
NetworkManager.Singleton.ConnectionApprovalCallback = ApprovalCheck;
NetworkManager.Singleton.OnServerStarted += OnServerStarted;
}
}
private void FindSpawnPoints()
{
PlayerSpawnPoint[] points = FindObjectsByType<PlayerSpawnPoint>(FindObjectsSortMode.None);
// spawnIndex로 정렬
var sortedPoints = points.OrderBy(p => p.spawnIndex == -1 ? int.MaxValue : p.spawnIndex);
spawnPoints.Clear();
foreach (var point in sortedPoints)
{
if (point.isAvailable)
{
spawnPoints.Add(point.transform);
}
}
Debug.Log($"<color=cyan>[Connection] {spawnPoints.Count}개의 스폰 포인트를 찾았습니다.</color>");
}
private void OnServerStarted()
{
Debug.Log("<color=green>[Connection] 서버 시작됨</color>");
}
private void ApprovalCheck(
NetworkManager.ConnectionApprovalRequest request,
NetworkManager.ConnectionApprovalResponse response)
{
response.Approved = true;
response.CreatePlayerObject = true;
// 스폰 위치 설정
response.Position = GetSpawnPosition(request.ClientNetworkId);
response.Rotation = GetSpawnRotation(request.ClientNetworkId);
Debug.Log($"<color=cyan>[Connection] 클라이언트 {request.ClientNetworkId} 승인됨. 스폰 위치: {response.Position}</color>");
}
private Vector3 GetSpawnPosition(ulong clientId)
{
if (spawnPoints.Count == 0)
{
Debug.LogWarning("[Connection] 스폰 포인트가 없습니다. 기본 위치 반환.");
return Vector3.zero;
}
int spawnIndex;
if (useRandomSpawn)
{
spawnIndex = Random.Range(0, spawnPoints.Count);
}
else
{
if (!_clientSpawnIndices.ContainsKey(clientId))
{
_clientSpawnIndices[clientId] = _nextSpawnIndex;
_nextSpawnIndex = (_nextSpawnIndex + 1) % spawnPoints.Count;
}
spawnIndex = _clientSpawnIndices[clientId];
}
return spawnPoints[spawnIndex].position;
}
private Quaternion GetSpawnRotation(ulong clientId)
{
if (spawnPoints.Count == 0)
return Quaternion.identity;
int spawnIndex = _clientSpawnIndices.ContainsKey(clientId)
? _clientSpawnIndices[clientId]
: 0;
return spawnPoints[spawnIndex].rotation;
}
private void OnDestroy()
{
if (NetworkManager.Singleton != null)
{
NetworkManager.Singleton.ConnectionApprovalCallback = null;
NetworkManager.Singleton.OnServerStarted -= OnServerStarted;
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: f77688301e4c5684bae207ce2a93706c

View File

@@ -0,0 +1,132 @@
using System.Collections.Generic;
using System.Linq;
using Unity.Netcode;
using UnityEngine;
namespace Northbound
{
/// <summary>
/// 네트워크 플레이어의 스폰 위치를 관리
/// </summary>
public class NetworkSpawnManager : NetworkBehaviour
{
public static NetworkSpawnManager Instance { get; private set; }
[Header("Spawn Settings")]
public List<Transform> spawnPoints = new List<Transform>();
public bool useRandomSpawn = false;
public bool findSpawnPointsAutomatically = true;
private Dictionary<ulong, int> _clientSpawnIndices = new Dictionary<ulong, int>();
private int _nextSpawnIndex = 0;
private void Awake()
{
if (Instance != null && Instance != this)
{
Destroy(gameObject);
return;
}
Instance = this;
}
private void Start()
{
if (findSpawnPointsAutomatically)
{
FindSpawnPoints();
}
if (NetworkManager.Singleton != null)
{
NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected;
}
}
private void FindSpawnPoints()
{
PlayerSpawnPoint[] points = FindObjectsByType<PlayerSpawnPoint>(FindObjectsSortMode.None);
// spawnIndex로 정렬
var sortedPoints = points.OrderBy(p => p.spawnIndex == -1 ? int.MaxValue : p.spawnIndex);
spawnPoints.Clear();
foreach (var point in sortedPoints)
{
if (point.isAvailable)
{
spawnPoints.Add(point.transform);
}
}
Debug.Log($"<color=cyan>[SpawnManager] {spawnPoints.Count}개의 스폰 포인트를 찾았습니다.</color>");
}
private void OnClientConnected(ulong clientId)
{
if (!IsServer) return;
// 플레이어가 스폰되었을 때 위치 설정
if (NetworkManager.Singleton.ConnectedClients.TryGetValue(clientId, out var client))
{
if (client.PlayerObject != null)
{
Vector3 spawnPosition = GetSpawnPosition(clientId);
Quaternion spawnRotation = GetSpawnRotation(clientId);
client.PlayerObject.transform.position = spawnPosition;
client.PlayerObject.transform.rotation = spawnRotation;
Debug.Log($"<color=green>[SpawnManager] 클라이언트 {clientId} 스폰 위치 설정: {spawnPosition}</color>");
}
}
}
public Vector3 GetSpawnPosition(ulong clientId)
{
if (spawnPoints.Count == 0)
{
Debug.LogWarning("[SpawnManager] 스폰 포인트가 없습니다. 기본 위치 반환.");
return Vector3.zero;
}
int spawnIndex;
if (useRandomSpawn)
{
spawnIndex = Random.Range(0, spawnPoints.Count);
}
else
{
if (!_clientSpawnIndices.ContainsKey(clientId))
{
_clientSpawnIndices[clientId] = _nextSpawnIndex;
_nextSpawnIndex = (_nextSpawnIndex + 1) % spawnPoints.Count;
}
spawnIndex = _clientSpawnIndices[clientId];
}
return spawnPoints[spawnIndex].position;
}
public Quaternion GetSpawnRotation(ulong clientId)
{
if (spawnPoints.Count == 0)
return Quaternion.identity;
int spawnIndex = _clientSpawnIndices.ContainsKey(clientId)
? _clientSpawnIndices[clientId]
: 0;
return spawnPoints[spawnIndex].rotation;
}
private void OnDestroy()
{
if (NetworkManager.Singleton != null)
{
NetworkManager.Singleton.OnClientConnectedCallback -= OnClientConnected;
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 287898125f34d1448a03db6b98a9c420

View File

@@ -0,0 +1,25 @@
using UnityEngine;
namespace Northbound
{
/// <summary>
/// 플레이어 스폰 위치를 표시하는 마커
/// </summary>
public class PlayerSpawnPoint : MonoBehaviour
{
[Header("Spawn Settings")]
public int spawnIndex = -1; // -1 = 순서대로 할당
public bool isAvailable = true;
[Header("Debug")]
public Color gizmoColor = Color.green;
public float gizmoRadius = 0.5f;
private void OnDrawGizmos()
{
Gizmos.color = isAvailable ? gizmoColor : Color.red;
Gizmos.DrawWireSphere(transform.position, gizmoRadius);
Gizmos.DrawLine(transform.position, transform.position + transform.forward * 2f);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 41a3c6ef0dc9b4d4c9db4ec668a78fb3