크래프톤 정글 TIL : 1023

lazyArtisan·2024년 10월 23일
0

정글 TIL

목록 보기
115/147

👾 나만무


관전 모드 구현

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

현재 로직 정리

  • 자신이 죽으면 StartSpectating() 호출해서 관전 모드 시작.
  • 카메라를 그룹핑한 오브젝트가 부모였던 플레이어 오브젝트로부터 독립해서 파괴를 피한다.
  • CharacterController를 추가해서 기존 MouseComponent 스크립트를 재활용하여 마우스로 시점을 이동할 수 있도록 한다.
  • SpectatorCamera 스크립트가 추가되면서 FixedUpdate로 타겟을 따라가기 시작한다.

개선 사항
클릭하면 다른 플레이어로 이동
중심축에서 살짝 떨어져서 회전

관전 시점 이동

    // 마우스 클릭했을 때 호출되는 함수
    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();
        }
    }
}

팀장님이 주신 코드로 고쳐보려고 했는데 이상해짐.

0개의 댓글