네트워크 멀티플레이 대응
This commit is contained in:
@@ -27,231 +27,170 @@ namespace Northbound
|
||||
|
||||
[Header("Debug")]
|
||||
public bool showDebugRay = true;
|
||||
|
||||
|
||||
private PlayerInputActions _inputActions;
|
||||
private IInteractable _currentInteractable;
|
||||
private Camera _mainCamera;
|
||||
private Animator _animator;
|
||||
private EquipmentSocket _equipmentSocket;
|
||||
|
||||
private EquipmentData _pendingEquipmentData;
|
||||
private string _currentEquipmentSocket;
|
||||
private bool _isInteracting = false;
|
||||
private bool _isInteracting;
|
||||
private float _interactionStartTime;
|
||||
private const float INTERACTION_TIMEOUT = 3f;
|
||||
|
||||
// 다른 컴포넌트가 이동 차단 여부를 확인할 수 있도록 public 프로퍼티 제공
|
||||
public bool IsInteracting => _isInteracting;
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
if (!IsOwner) return;
|
||||
|
||||
_mainCamera = Camera.main;
|
||||
_animator = GetComponent<Animator>();
|
||||
_equipmentSocket = GetComponent<EquipmentSocket>();
|
||||
}
|
||||
|
||||
public override void OnNetworkSpawn()
|
||||
{
|
||||
base.OnNetworkSpawn();
|
||||
|
||||
if (rayOrigin == null)
|
||||
rayOrigin = transform;
|
||||
|
||||
|
||||
_inputActions = new PlayerInputActions();
|
||||
_inputActions.Player.Interact.performed += OnInteract;
|
||||
_inputActions.Enable();
|
||||
}
|
||||
|
||||
|
||||
public override void OnNetworkDespawn()
|
||||
{
|
||||
if (IsOwner && _inputActions != null)
|
||||
if (_inputActions != null)
|
||||
{
|
||||
_inputActions.Player.Interact.performed -= OnInteract;
|
||||
_inputActions.Disable();
|
||||
_inputActions.Dispose();
|
||||
}
|
||||
|
||||
base.OnNetworkDespawn();
|
||||
}
|
||||
|
||||
|
||||
private void Update()
|
||||
{
|
||||
if (!IsOwner) return;
|
||||
|
||||
if (_isInteracting && Time.time - _interactionStartTime > INTERACTION_TIMEOUT)
|
||||
{
|
||||
_isInteracting = false;
|
||||
}
|
||||
|
||||
DetectInteractable();
|
||||
}
|
||||
|
||||
|
||||
private void DetectInteractable()
|
||||
{
|
||||
Vector3 origin = rayOrigin.position;
|
||||
Vector3 direction = useForwardDirection ? transform.forward : _mainCamera.transform.forward;
|
||||
|
||||
Ray ray = new Ray(origin, direction);
|
||||
|
||||
|
||||
if (showDebugRay)
|
||||
{
|
||||
Debug.DrawRay(ray.origin, ray.direction * interactionRange,
|
||||
_currentInteractable != null ? Color.green : Color.yellow);
|
||||
}
|
||||
|
||||
|
||||
if (Physics.Raycast(ray, out RaycastHit hit, interactionRange, interactableLayer))
|
||||
{
|
||||
IInteractable interactable = hit.collider.GetComponent<IInteractable>();
|
||||
|
||||
if (interactable == null)
|
||||
{
|
||||
interactable = hit.collider.GetComponentInParent<IInteractable>();
|
||||
|
||||
}
|
||||
|
||||
if (interactable != null && interactable.CanInteract(OwnerClientId))
|
||||
{
|
||||
_currentInteractable = interactable;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
_currentInteractable = null;
|
||||
}
|
||||
|
||||
|
||||
private void OnInteract(InputAction.CallbackContext context)
|
||||
{
|
||||
if (blockDuringAnimation && _isInteracting)
|
||||
if (blockDuringAnimation && IsInteracting)
|
||||
return;
|
||||
|
||||
if (_currentInteractable == null)
|
||||
return;
|
||||
|
||||
if (_currentInteractable != null)
|
||||
var equipmentData = _currentInteractable.GetEquipmentData();
|
||||
string animTrigger = _currentInteractable.GetInteractionAnimation();
|
||||
bool hasAnimation = !string.IsNullOrEmpty(animTrigger);
|
||||
|
||||
if (playAnimations && _animator != null && hasAnimation)
|
||||
{
|
||||
_isInteracting = true;
|
||||
_pendingEquipmentData = _currentInteractable.GetEquipmentData();
|
||||
_interactionStartTime = Time.time;
|
||||
|
||||
string animTrigger = _currentInteractable.GetInteractionAnimation();
|
||||
bool hasAnimation = !string.IsNullOrEmpty(animTrigger);
|
||||
|
||||
// 장비 장착 (애니메이션 이벤트 사용 안 할 경우)
|
||||
if (!useAnimationEvents && useEquipment && _equipmentSocket != null && _pendingEquipmentData != null)
|
||||
{
|
||||
if (_pendingEquipmentData.attachOnStart && _pendingEquipmentData.equipmentPrefab != null)
|
||||
{
|
||||
AttachEquipment();
|
||||
|
||||
if (_pendingEquipmentData.detachOnEnd)
|
||||
{
|
||||
StartCoroutine(DetachEquipmentAfterDelay(2f));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 애니메이션 재생
|
||||
if (playAnimations && _animator != null && hasAnimation)
|
||||
if (useAnimationEvents)
|
||||
{
|
||||
_animator.SetTrigger(animTrigger);
|
||||
}
|
||||
else
|
||||
{
|
||||
// 애니메이션이 없으면 즉시 상호작용 완료
|
||||
_animator.SetTrigger(animTrigger);
|
||||
_currentInteractable.Interact(OwnerClientId);
|
||||
_isInteracting = false;
|
||||
}
|
||||
|
||||
// 상호작용 실행 (서버에서 처리)
|
||||
}
|
||||
else
|
||||
{
|
||||
_currentInteractable.Interact(OwnerClientId);
|
||||
}
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// Animation Event 함수들
|
||||
// ========================================
|
||||
|
||||
public void OnEquipTool()
|
||||
|
||||
public void AttachEquipment()
|
||||
{
|
||||
if (!useAnimationEvents || !useEquipment) return;
|
||||
AttachEquipment();
|
||||
}
|
||||
if (!IsOwner) return;
|
||||
if (_currentInteractable == null || !useEquipment) return;
|
||||
|
||||
public void OnEquipTool(string socketName)
|
||||
var equipmentData = _currentInteractable.GetEquipmentData();
|
||||
if (equipmentData == null || !equipmentData.attachOnStart) return;
|
||||
|
||||
if (_equipmentSocket == null)
|
||||
{
|
||||
Debug.LogWarning("[PlayerInteraction] EquipmentSocket component not found on player");
|
||||
return;
|
||||
}
|
||||
|
||||
if (equipmentData.equipmentPrefab == null)
|
||||
{
|
||||
Debug.LogWarning("[PlayerInteraction] Equipment prefab is null. Assign a prefab in the Resource's EquipmentData in Inspector");
|
||||
return;
|
||||
}
|
||||
|
||||
_equipmentSocket.AttachToSocket(equipmentData.socketName, equipmentData.equipmentPrefab);
|
||||
}
|
||||
|
||||
public void DetachEquipment()
|
||||
{
|
||||
if (!useAnimationEvents || !useEquipment) return;
|
||||
AttachEquipment(socketName);
|
||||
}
|
||||
if (!IsOwner) return;
|
||||
if (_currentInteractable == null || !useEquipment) return;
|
||||
|
||||
public void OnUnequipTool()
|
||||
{
|
||||
if (!useAnimationEvents || !useEquipment) return;
|
||||
DetachEquipment();
|
||||
}
|
||||
var equipmentData = _currentInteractable.GetEquipmentData();
|
||||
if (equipmentData == null || !equipmentData.detachOnEnd) return;
|
||||
|
||||
public void OnUnequipTool(string socketName)
|
||||
{
|
||||
if (!useAnimationEvents || !useEquipment) return;
|
||||
DetachEquipment(socketName);
|
||||
}
|
||||
if (_equipmentSocket == null) return;
|
||||
|
||||
_equipmentSocket.DetachFromSocket(equipmentData.socketName);
|
||||
}
|
||||
|
||||
public void OnInteractionComplete()
|
||||
{
|
||||
_isInteracting = false;
|
||||
Debug.Log("[PlayerInteraction] 상호작용 완료");
|
||||
}
|
||||
|
||||
// ========================================
|
||||
// 내부 헬퍼 함수들
|
||||
// ========================================
|
||||
|
||||
private void AttachEquipment(string socketName = null)
|
||||
{
|
||||
if (_equipmentSocket == null || _pendingEquipmentData == null)
|
||||
return;
|
||||
|
||||
if (_pendingEquipmentData.equipmentPrefab == null)
|
||||
return;
|
||||
|
||||
string socket = socketName ?? _pendingEquipmentData.socketName;
|
||||
_equipmentSocket.AttachToSocket(socket, _pendingEquipmentData.equipmentPrefab);
|
||||
_currentEquipmentSocket = socket;
|
||||
}
|
||||
|
||||
private void DetachEquipment(string socketName = null)
|
||||
{
|
||||
if (_equipmentSocket == null)
|
||||
return;
|
||||
|
||||
string socket = socketName ?? _currentEquipmentSocket;
|
||||
|
||||
if (!string.IsNullOrEmpty(socket))
|
||||
if (_currentInteractable != null)
|
||||
{
|
||||
_equipmentSocket.DetachFromSocket(socket);
|
||||
|
||||
if (socket == _currentEquipmentSocket)
|
||||
_currentEquipmentSocket = null;
|
||||
}
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator DetachEquipmentAfterDelay(float delay)
|
||||
{
|
||||
yield return new WaitForSeconds(delay);
|
||||
DetachEquipment();
|
||||
|
||||
if (!useAnimationEvents)
|
||||
{
|
||||
_isInteracting = false;
|
||||
}
|
||||
}
|
||||
|
||||
private void OnGUI()
|
||||
{
|
||||
if (!IsOwner || _currentInteractable == null) return;
|
||||
|
||||
GUIStyle style = new GUIStyle(GUI.skin.label)
|
||||
{
|
||||
fontSize = 24,
|
||||
alignment = TextAnchor.MiddleCenter
|
||||
};
|
||||
style.normal.textColor = Color.white;
|
||||
|
||||
string prompt = _currentInteractable.GetInteractionPrompt();
|
||||
|
||||
if (_isInteracting)
|
||||
{
|
||||
prompt += " (진행 중...)";
|
||||
style.normal.textColor = Color.yellow;
|
||||
}
|
||||
|
||||
GUI.Label(new Rect(Screen.width / 2 - 200, Screen.height - 100, 400, 50), prompt, style);
|
||||
}
|
||||
|
||||
public override void OnDestroy()
|
||||
{
|
||||
if (_inputActions != null)
|
||||
{
|
||||
_inputActions.Dispose();
|
||||
_currentInteractable.Interact(OwnerClientId);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user