This document is about: PUN 2
SWITCH TO

PUN Classic (v1), PUN 2, Bolt는 휴업 모드입니다. Unity2022에 대해서는 PUN 2에서 서포트하지만, 신기능의 추가는 없습니다. 현재 이용중인 고객님의 PUN 및 Bolt 프로젝트는 중단되지 않고, 퍼포먼스나 성능이 떨어지는 일도 없습니다. 앞으로의 새로운 프로젝트에는 Photon Fusion 또는 Quantum을 사용해 주십시오.

8 - 플레이어 인스턴스 생성

이 섹션에서는 네트워크를 통한 "Player" 프리팹 인스턴스 생성과 플레이 하는 동안 자동 씬 전환에 필요한 다양한 기능에 대해서 구현 할 것 입니다.

플레이어 인스턴스 생성하기

"Player" 프리팹의 인스턴스를 생성하는 것은 정말로 쉽습니다. 룸에 들어갔을 때 바로 인스턴스를 생성할 필요가 있으며, 우리가 경기장을 로드 했다는 것을 의미 하는 GameManager 스크립트 Start() 에서 할 수 있습니다. 이 의미는 설계상에서 우리가 룸에 있다는 의미 입니다.

  1. GameManager 스크립트를 오픈합니다.

  2. Public Variables region 에서 다음의 변수를 추가 합니다.

    C#

    [Tooltip("The prefab to use for representing the player")]
    public GameObject playerPrefab;
    
  3. Start() 메소드에서 다음을 추가한 다음 GameManager 스크립트를 저장 합니다.

    C#

    if (playerPrefab == null) 
    {
        Debug.LogError("<Color=Red><a>Missing</a></Color> playerPrefab Reference. Please set it up in GameObject 'Game Manager'",this);
    } 
    else 
    {
        Debug.LogFormat("We are Instantiating LocalPlayer from {0}", Application.loadedLevelName);
        // we're in a room. spawn a character for the local player. it gets synced by using PhotonNetwork.Instantiate
        PhotonNetwork.Instantiate(this.playerPrefab.name, new Vector3(0f,5f,0f), Quaternion.identity, 0);
    }
    
  4. GameManager 스크립트를 저장합니다.

노출된 public 필드는 "Player" 프리팹을 참조합니다. Player 프리팹이 에셋이므로 참조가 온전하게 유지 되기 때문에 "GameManager" 프리팹은 각 신에서 작업 하는 대신 직접 드래그앤 드롭 할 수 있어 편리합니다(계층에서 GameObject를 참조하는 것과 반대로, Prefab은 동일한 장면에서 인스턴스화되었을 때만 할 수 있습니다).

경고: 프리팹은 Resources 폴더안에서 네트워크를 통하여 인스턴스 생성되어야 하는 것이 Photon 의 요건임을 항상 확인 하세요.
gamemanager inspector
GameManager Inspector

그리고 나서 Start() 에서 인스턴스를 생성 했습니다( 프리팹 "Player" 레퍼런스를 적절히 체크 한 이후)

바닥 위에 인스턴스가 잘 생성한 것을 주목 하세요( 플레이어가 2 유닛 높이를 가졌고 5 유닛 위에). 새로운 플레이어가 룸에 참여 할 때 플레이어들이 경기장 중심에서 돌아 다닐 수 있도록 갑작스러운 충돌을 방지하는 방법들 중 하나의 방식입니다. 또한 "떨어지는" 플레이어는 게임에서 새로운 엔터티라고 깔끔하게 알려주게 됩니다.

하지만 우리의 경우에 있어 충분하지가 않습니다. 트위스트가 있습니다 :) 다른 플레이어들이 참여할 때, 다른 신들이 로드될 것이며 일관성을 유지하고 나갔기 때문에 제거 하지는 않을 것 입니다. 따라서 유니티에게 우리가 생성했던 인스턴스를 제거 하지 말라고 알려 줄 필요가 있습니다. 씬이 로드 될 때 인스턴스 생성이 필요한지 체크하는 것이 필요 합니다.

플레이어 인스턴스의 파악

  1. PlayerManager 스크립트를 오픈 합니다.

  2. "Public Fields" 영역에서 다음을 추가 합니다.

    C#

    [Tooltip("The local player instance. Use this to know if the local player is represented in the Scene")]
    public static GameObject LocalPlayerInstance;
    
  3. Awake() 메소드에서 다음을 추가 합니다.

    C#

    // #Important
    // used in GameManager.cs: we keep track of the localPlayer instance to prevent instantiation when levels are synchronized
    if (photonView.IsMine)
    {
        PlayerManager.LocalPlayerInstance = this.gameObject;
    }
    // #Critical
    // we flag as don't destroy on load so that instance survives level synchronization, thus giving a seamless experience when levels load.
    DontDestroyOnLoad(this.gameObject);
    
  4. PlayerManager 스크립트를 저장합니다

이 변경사항으로 GameManager 스크립트 내에서 필요한 인스턴스만 체크하는 구현을 할 수 있습니다.

  1. GameManager 스크립트를 오픈 합니다

  2. if 문장으로 인스턴스 생성 호출을 둘러싸 줍니다.

    C#

    if (PlayerManager.LocalPlayerInstance == null)
    {
        Debug.LogFormat("We are Instantiating LocalPlayer from {0}", SceneManagerHelper.ActiveSceneName);
        // we're in a room. spawn a character for the local player. it gets synced by using PhotonNetwork.Instantiate
        PhotonNetwork.Instantiate(this.playerPrefab.name, new Vector3(0f, 5f, 0f), Quaternion.identity, 0);
    }
    else
    {
        Debug.LogFormat("Ignoring scene load for {0}", SceneManagerHelper.ActiveSceneName);
    }
    
  3. GameManager 스크립트를 저장합니다

이것으로 PlayerManagerlocalPlayer 의 기존 인스턴스의 참조가 없을 때만 인스턴스 생성을 하게 됩니다.

경기장 밖에 있을 때 플레이어 위치 관리

우리가 주의 해야 할 것이 하나 더 있습니다. 경기장의 크기는 플레이어 수에 따라 변합니다. 이 의미는 한명의 플레이어가 나가고 다른 플레이어들이 현재 경기장 크기의 제한에 가까울 경우가 있다는 의미 입니다. 이 상황을 고려할 필요가 있으며 이 경우에 경기장의 중심부로 플레이어들의 위치를 단순히 재조정 합니다. 이것은 분명히 게임 플레이와 레벨 디자인에 이슈가 발생 할 수 있습니다.

Unity가 "Scene Management"를 혁신하고 Unity 5.4가 일부 콜백을 감가상각하여 모든 Unity 버전(Unity 4.7부터 최신 버전)에서 작동하는 코드를 만드는 것이 약간 더 복잡해졌습니다. Unity 버전에 따라 다른 코드가 필요합니다. Photon Networking과 관련이 없지만 업데이트에서 살아남기 위해 프로젝트를 마스터하는 것이 아무리 중요합니다.

  1. PlayerManager 스크립트를 오픈합니다

  2. Start() 메소드의 끝에서 다음의 코드를 추가합니다

    C#

    #if UNITY_5_4_OR_NEWER
    // Unity 5.4 has a new scene management. register a method to call CalledOnLevelWasLoaded.
    UnityEngine.SceneManagement.SceneManager.sceneLoaded += (scene, loadingMode) =>
            {
                this.CalledOnLevelWasLoaded(scene.buildIndex);
            };
    #endif
    
  3. "MonoBehaviour CallBacks" 영역에 다음 두 개의 메소드를 추가합니다.

    C#

    #if !UNITY_5_4_OR_NEWER
    /// <summary>See CalledOnLevelWasLoaded. Outdated in Unity 5.4.</summary>
    void OnLevelWasLoaded(int level)
    {
        this.CalledOnLevelWasLoaded(level);
    }
    #endif
    
    void CalledOnLevelWasLoaded(int level)
    {
        // check if we are outside the Arena and if it's the case, spawn around the center of the arena in a safe zone
        if (!Physics.Raycast(transform.position, -Vector3.up, 5f))
        {
            transform.position = new Vector3(0f, 5f, 0f);
        }
    }
    
  4. PlayerManager 스크립트를 저장합니다.

이 새로운 코드가 하는 일은 로딩되는 레벨을 감시하는 것입니다. 그리고 레이캐스트는 현재 플레이어의 위치를 따라 우리가 어떤 것을 치는지 알아보는 것입니다. 만약 그렇지 않다면, 이것은 우리가 경기장 상공에 있지 않다는 것을 의미합니다. 그리고 우리는 다시 중앙으로 옮겨져야 합니다. 우리가 처음으로 그 방에 들어갈 때와 똑같이 말이죠.

유니티 5.4 버전 보다 낮은 버전을 사용하고 있으시면, 유니티의 콜백인 OnLevelWasLoaded 를 사용할 것 입니다. 유니티 5.4 이상을 사용하면 OnLevelWasLoaded더 이상 사용불가이므로 새로운 SceneManagement 시스템을 사용해야 합니다. 마지막으로 코드 중복을 피하기 위해서, OnLevelWasLoaded 에서 호출 또는 SceneManager.sceneLoaded 콜백에서 호출되는 CalledOnLevelWasLoaded 메소드를 가질 것 입니다.

다음 파트.
이전 파트.

Back to top