using System.Collections.Generic;
using UnityEngine;
public class SpectatorMode : MonoBehaviour
{
private List<GameObject> RemainingPlayers = new List<GameObject>(); // 남아있는 플레이어
public GameObject SpectatingTarget; // 내가 관전 중인 플레이어
private bool isSpectating = false;
public void StartSpectating()
{
Debug.Log("Start Spectating");
isSpectating = true;
RemainingPlayers = new List<GameObject>();
RemainingPlayers.AddRange(GameObject.FindGameObjectsWithTag("Player"));
Player p = NetworkManager.Instance.myPlayer; // 자기가 조종하고 있는 플레이어
RemainingPlayers.Remove(p.gameObject);
transform.SetParent(null);
gameObject.AddComponent<SpectatorCamera>(); // 쫓아다니기 시작
gameObject.AddComponent<CharacterController>(); // 마우스 이동 추가
UpdateSpectatingPlayer();
}
public void UpdateSpectatingPlayer()
{
// 어떤 플레이어가 죽었을 때마다 호출됨
// 남아있는 플레이어 중에서 다음 플레이어로 변경
if (RemainingPlayers.Count == 0)
{
Debug.Log("No players to spectate");
return;
}
// 다음 플레이어로 변경
SpectatingTarget = RemainingPlayers[0];
GetComponent<SpectatorCamera>().SetSpectatingTarget(SpectatingTarget);
Debug.Log("Remaining Players: " + SpectatingTarget.name);
}
public void RemoveRemainingPlayer(GameObject player)
{
if (isSpectating)
{
RemainingPlayers.Remove(player);
// 죽은 친구가 지금 관전 중인 친구면 카메라를 옮겨야 함
if (player == SpectatingTarget)
UpdateSpectatingPlayer();
}
}
}
SpectatorMode.cs
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class SpectatorCamera : MonoBehaviour
{
public GameObject SpectatingTarget; // 카메라가 따라다닐 타겟
public float offsetX = 0f; // 카메라의 x좌표
public float offsetY = 1.0f; // 카메라의 y좌표
public float offsetZ = 0f; // 카메라의 z좌표
public float CameraSpeed = 10.0f; // 카메라의 속도
Vector3 TargetPos; // 타겟의 위치
public void SetSpectatingTarget(GameObject target)
{
SpectatingTarget = target;
gameObject.GetComponentInChildren<MouseComponent>().playerBody = gameObject.transform;
// gameObject.GetComponent<MouseComponent>().playerBody = target.transform;
Debug.Log("Set Spectating Target: " + target.name);
}
private void FixedUpdate()
{
// 타겟의 x, y, z 좌표에 카메라의 좌표를 더하여 카메라의 위치를 결정
TargetPos = new Vector3(
SpectatingTarget.transform.position.x + offsetX,
SpectatingTarget.transform.position.y + offsetY,
SpectatingTarget.transform.position.z + offsetZ
);
transform.position = TargetPos;
// 카메라의 움직임을 부드럽게 하는 함수(Lerp)
// transform.position = Vector3.Lerp(transform.position, TargetPos, Time.deltaTime * CameraSpeed);
}
}
SpectatorCamera.cs
현재 로직 정리
개선 사항
클릭하면 다른 플레이어로 이동
중심축에서 살짝 떨어져서 회전
// 마우스 클릭했을 때 호출되는 함수
private void MoveToAnotherPlayer(int idx_move)
{
if (RemainingPlayers.Count == 0)
return;
int idx = RemainingPlayers.IndexOf(SpectatingTarget);
idx += idx_move;
if (idx < 0)
idx = RemainingPlayers.Count - 1;
else if (idx >= RemainingPlayers.Count)
idx = 0;
SpectatingTarget = RemainingPlayers[idx];
GetComponent<SpectatorCamera>().SetSpectatingTarget(SpectatingTarget);
Debug.Log("Move to another player: " + SpectatingTarget.name);
}
// 마우스 왼쪽 오른쪽 입력 받기
private void Update()
{
if (isSpectating)
{
if (Input.GetMouseButtonDown(0)) // 마우스 왼쪽 클릭
{
MoveToAnotherPlayer(-1);
}
else if (Input.GetMouseButtonDown(1)) // 마우스 오른쪽 클릭
{
MoveToAnotherPlayer(1);
}
}
}
SpectatorMode.cs
active input handling이 input system package로만 되고 있기 때문에
이대로 하면 오류만 남. both로 바꾸면 되긴 하는데 기존 input system에 맞추기로.
// 마우스 클릭했을 때 호출되는 함수
private void MoveToAnotherPlayer(int idx_move)
{
if (RemainingPlayers.Count == 0)
return;
int idx = RemainingPlayers.IndexOf(SpectatingTarget);
idx += idx_move;
if (idx < 0)
idx = RemainingPlayers.Count - 1;
else if (idx >= RemainingPlayers.Count)
idx = 0;
SpectatingTarget = RemainingPlayers[idx];
GetComponent<SpectatorCamera>().SetSpectatingTarget(SpectatingTarget);
Debug.Log("Move to another player: " + SpectatingTarget.name);
}
// 마우스 왼쪽 클릭 시 이전 플레이어로 전환
public void OnPrevPlayer(InputAction.CallbackContext context)
{
if (isSpectating)
{
MoveToAnotherPlayer(-1); // 왼쪽 클릭은 이전 플레이어
}
}
// 마우스 오른쪽 클릭 시 다음 플레이어로 전환
public void OnNextPlayer(InputAction.CallbackContext context)
{
if (isSpectating)
{
MoveToAnotherPlayer(1); // 오른쪽 클릭은 다음 플레이어
}
}
변경 완료
관전 중인 플레이어를 태양,
카메라를 지구라고 했을 때
태양의 시점이 움직일 때마다 공전(카메라의 위치를 뒤통수로 이동)을 시켜야 하고
관전자가 마우스를 움직일 때마다 자전(시점 이리저리 이동)을 시켜야 한다
이게 아니라 다른 방식이었음
플레이어를 바라보면서 빙글빙글 도는거였
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.InputSystem;
public class SpectatorMode : MonoBehaviour
{
private List<GameObject> RemainingPlayers = new List<GameObject>(); // 남아있는 플레이어
public GameObject SpectatingTarget; // 내가 관전 중인 플레이어
private bool isSpectating = false;
// 마우스 클릭했을 때 호출되는 함수
private void MoveToAnotherPlayer(int idx_move)
{
if (RemainingPlayers.Count == 0)
return;
int idx = RemainingPlayers.IndexOf(SpectatingTarget);
idx += idx_move;
if (idx < 0)
idx = RemainingPlayers.Count - 1;
else if (idx >= RemainingPlayers.Count)
idx = 0;
SpectatingTarget = RemainingPlayers[idx];
GetComponent<SpectatorCamera>().SetSpectatingTarget(SpectatingTarget);
Debug.Log("Move to another player: " + SpectatingTarget.name);
}
// 마우스 왼쪽 클릭 시 이전 플레이어로 전환
public void OnPrevPlayer(InputAction.CallbackContext context)
{
if (isSpectating)
{
MoveToAnotherPlayer(-1); // 왼쪽 클릭은 이전 플레이어
}
}
// 마우스 오른쪽 클릭 시 다음 플레이어로 전환
public void OnNextPlayer(InputAction.CallbackContext context)
{
if (isSpectating)
{
MoveToAnotherPlayer(1); // 오른쪽 클릭은 다음 플레이어
}
}
// 관전모드 시작하는 함수
public void StartSpectating()
{
Debug.Log("Start Spectating");
foreach (Transform child in transform)
{
child.gameObject.SetActive(true);
}
isSpectating = true;
RemainingPlayers = new List<GameObject>();
RemainingPlayers.AddRange(GameObject.FindGameObjectsWithTag("Player"));
Player p = NetworkManager.Instance.myPlayer; // 자기가 조종하고 있는 플레이어
RemainingPlayers.Remove(p.gameObject);
transform.SetParent(null);
gameObject.AddComponent<SpectatorCamera>(); // 쫓아다니기 시작
UpdateSpectatingPlayer();
}
// 누군가 죽었을 때 호출되는 함수
private void UpdateSpectatingPlayer()
{
// 어떤 플레이어가 죽었을 때마다 호출됨
// 남아있는 플레이어 중에서 다음 플레이어로 변경
if (RemainingPlayers.Count == 0)
{
Debug.Log("No players to spectate");
return;
}
// 다음 플레이어로 변경
SpectatingTarget = RemainingPlayers[0];
GetComponent<SpectatorCamera>().SetSpectatingTarget(SpectatingTarget);
Debug.Log("Remaining Players: " + SpectatingTarget.name);
}
// 누군가 죽었을 때 호출되는 함수
public void RemoveRemainingPlayer(GameObject player)
{
if (isSpectating)
{
RemainingPlayers.Remove(player);
// 죽은 친구가 지금 관전 중인 친구면 카메라를 옮겨야 함
if (player == SpectatingTarget)
UpdateSpectatingPlayer();
}
}
}
SpectatorMode.cs
using System.Collections.Generic;
using Cinemachine;
using UnityEngine;
using UnityEngine.InputSystem;
public class SpectatorCamera : MonoBehaviour
{
public GameObject SpectatingTarget; // 카메라가 따라다닐 타겟
[SerializeField] private float offsetX = 0f; // 카메라의 x좌표
[SerializeField] private float offsetY = 1.0f; // 카메라의 y좌표
[SerializeField] private float offsetZ = 0f; // 카메라의 z좌표
[SerializeField] private float distance = 1.5f; // 카메라와 타겟 사이 평면 거리
[SerializeField] private float height = 1.0f; // 카메라의 높이
public float mouseSensitivity = 100f; // 마우스 감도
public float CameraSpeed = 10.0f; // 카메라의 속도
Vector3 TargetPos; // 타겟의 위치
// Input Actions 변수
private PlayerInput playerInput;
private InputAction lookAction;
void Awake()
{
// PlayerInput 컴포넌트에서 InputAction 가져오기
playerInput = GetComponent<PlayerInput>();
lookAction = playerInput.actions["Look"];
Vector3 virtualCameraPosition = transform.Find("Virtual Camera").transform.position;
virtualCameraPosition.z -= distance;
transform.Find("Virtual Camera").transform.position = virtualCameraPosition;
}
void Start()
{
Cursor.lockState = CursorLockMode.Locked;
}
public void SetSpectatingTarget(GameObject target)
{
SpectatingTarget = target;
Debug.Log("Set Spectating Target: " + target.name);
}
private void FollowPosition()
{
transform.position = SpectatingTarget.transform.position;
Vector2 mouseDelta = lookAction.ReadValue<Vector2>();
float mouseX = mouseDelta.x * mouseSensitivity * Time.deltaTime;
transform.Rotate(Vector3.up * mouseX);
}
private void FixedUpdate()
{
if (SpectatingTarget != null)
{
FollowPosition();
}
}
}
팀장님이 주신 코드로 고쳐보려고 했는데 이상해짐.