This document is about: PUN 1
SWITCH TO

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

파트 2 - 로비 UI

이 파트에서는 로비의 사용자 인터페이스(UI) 생성에 집중 할 것 입니다. 아주 기본적인 것을 다루며 네트워킹에 관련된 것이 아닙니다.

플레이 버튼

현재 로비에서는 접속하면 자동으로 룸으로 안내 해주는데 초기 테스팅에 매우 편리하지만 사용자가 룸을 선택하여 플레이 하는 것을 원하고 있습니다. 따라서 이를 위해 간단히 버튼이 제공 됩니다.

  1. Launcher 신을 오픈 합니다.
  2. 유니티 메뉴 'GameObject/UI/Button' 에서 UI 버튼을 생성하고 Play Button 으로 이름을 변경 합니다. 캔버스와 이벤트 시스템 게임오브젝트가 Hierarchy 에 생성되어 있다는 것을 확인 해보세요. 우리가 생성하지 않아도 되니 좋군요 :)
  3. Play Button 의 Child Text 를 "Play" 로 변경 합니다.
  4. Play Button을 선택 하고 버튼 컴포넌트의 On Click ()섹션으로 이동합니다.
  5. 작은 '+' 버튼을 클릭하여 항목을 추가합니다.
  6. Hierarchy에서 Launcher 게임오브젝트를 드래그하여 필드로 이동시킵니다.
  7. 드롭다운 메뉴에서 Launcher.connect() 를 선택 합니다. 이제 Launcher 스크립트에 버튼을 연결 시켰으므로 사용자가 그 버튼을 누르게 되면 Launcher 스크립트의 "Connect()" 메소드를 호출 하게 됩니다.
  8. Launcher 스크립트를 오픈 합니다.
  9. Connect() 를 호출하는 Start() 내의 라인을 제거 합니다.
  10. Launcher 스크립트를 저장하고 신도 같이 저장 합니다.

지금 플레이를 누르게 되면 버튼을 누르기 전까지는 접속하지 않게 될 것 입니다.

플레이어 이름

전형적인 게임에서 가장 중요한 것중의 하나는 사용자가 자신의 이름을 지을 수 있도록 하여 누가 상대하고 있는 지 알수 있도록 하는 것 입니다. 이 작업을 약간 변형하여 PlayerPrefs 에 이름의 값을 저장하도록 하여 사용자가 게임을 오픈 했을 때 그 이름을 복구 할 수 있습니다. 구현하기 매우 쉽고 중요한 기능으로 사용자 경험을 최대로 주기 위하여 많은 영역에서 활용 할 수 있습니다. 플레이어의 이름을 관리하며 기억하고 관련된 UI 를 생성하는 스크립트를 생성 하겠습니다.

PlayerNameInputField 생성

  1. 새로운 C# 스크립트를 생성하여 PlayerNameInputField 로 이름을 만듦니다.
  2. 아래는 소스의 전체 내용입니다. PlayerNameInputField 스크립트를 맞게 편집하고 저장해 주세요:

C#

using UnityEngine;
using UnityEngine.UI;

using System.Collections;

namespace Com.MyCompany.MyGame
{
    /// <summary>
    /// Player name input field. Let the user input his name, will appear above the player in the game.
    /// </summary>
    [RequireComponent(typeof(InputField))]
    public class PlayerNameInputField : MonoBehaviour
    {
        #region Private Variables

        // Store the PlayerPref Key to avoid typos
        static string playerNamePrefKey = "PlayerName";

        #endregion

        #region MonoBehaviour CallBacks
        
        /// <summary>
        /// MonoBehaviour method called on GameObject by Unity during initialization phase.
        /// </summary>
        void Start () {
        
            string defaultName = "";
            InputField _inputField = this.GetComponent<InputField>();
            if (_inputField!=null)
            {
                if (PlayerPrefs.HasKey(playerNamePrefKey))
                {
                    defaultName = PlayerPrefs.GetString(playerNamePrefKey);
                    _inputField.text = defaultName;
                }
            }

            PhotonNetwork.playerName =    defaultName;
        }

        #endregion
        
        #region Public Methods

        /// <summary>
        /// Sets the name of the player, and save it in the PlayerPrefs for future sessions.
        /// </summary>
        /// <param name="value">The name of the Player</param>
        public void SetPlayerName(string value)
        {
            // #Important
            PhotonNetwork.playerName = value + " "; // force a trailing space string in case value is an empty string, else playerName would not be updated.

            PlayerPrefs.SetString(playerNamePrefKey,value);
        }
        
        #endregion
    }
}

스크립트를 분석 해 보도록 하겠습니다:

이 스크립트에서는 InputField 가 필요 한데 스크립트를 어려움 없이 편리하고 빠른 방식을 제공 합니다.

PlayerPrefs 은 엑셀의 두개 컬럼으로 구성되어 있는 것과 같이 keyValue 의 쌍으로 묶여진 항목들의 리스트의 룩업 리스트 입니다. 키는 모든 값을 가질 수 있는 문자열이고 개발 전 과정에서 준수해야할 명명법을 결정 합니다. 이 때문에 PlayerPrefs 키들을 한 장소에 저장하는 것이 좋습니다. 편리한 방법으로 [Static] 변수로 선언하여 사용하시기 바랍니다. 왜냐하면 게임내에서 변하지 않고 언제나 동일 하기 때문입니다. 상수(Const)로도 선언하여 사용할 수 있지만 C# 언어에서 스코프를 벗어 나게 되면 귀찮은 일이 되는 것임을 C# 경험이 많으신 분은 알 수 있을 것 입니다.

로직은 매우 직관적입니다. PlayerPrefs 에 키가 주어 졌다면 그 키에 대한 값을 직접 넣을 수 있습니다. 시작할 때, 편집할 때 InputFiled 의 현재값을 PlayerPref 에 설정하고 사용자 단말에 나중(사용자가 이 게임을 다음에 다시 오픈 할때)에 가져오기 위하여 저장 하게 될 것 입니다.

이 스크립트의 중요한 부분 이며 네트워크상의 플레이어 이름을 설정합니다. 스크립트에서는 이것을 두 부분에서 사용하고 있습니다. PlayerPrefs 에 저장된 이름이 있는지 체크한 후 Start() 부분과 public 메소드인 SetPlayerName() 내부에서 사용합니다. 지금 당장은 아무것도 이 메소드에서 호출하지 않습니다. InputField 의 OnValueChange() 에서 SetPlayerName() 를 호출하도록 바인드 하여 사용자가 InputField 값을 편집했을 때 저장하도록 합니다. 이 사항은 Play 를 눌렀을 때 하도록 할 수 도 있습니다. 이렇게 하면 추가적인 스크립트가 더 필요하기 때문에 좀 더 간단하고 명확하게 하기 위하여 이대로 유지 하겠습니다. 이렇게 하면 사용자가 무엇을 의도 하던간에 입력된 값은 항상 기억될 것이고 종종 우리가 원하는 방식일 것 입니다.

플레이어 이름을 위한 UI 생성

  1. Launcher 신이 오픈되어 있는지 확인 합니다.
  2. 유니티 메뉴의 'GameObject/UI/InputField' 를 이용하여 UI InputFiled 를 생성하고 이 게임오브젝트의 이름을 Name InputField 로 변경 합니다.
  3. RectTransform 에 있는 PosY 값을 35 로 설정하여 Play Button 위에 위치 시킵니다.
  4. Name InputField의 자식인 PlaceHolder 의 텍스트를 "Enter your Name..."로 값을 변경 합니다.
  5. Name InputField 게임 오브젝트를 선택 합니다.
  6. 방금전에 생성했던 PlayerNameInputField 를 추가 합니다.
  7. InputField 컴포넌트의 On Value Change (String) 섹션으로 이동 합니다.
  8. 작은 '+' 버튼을 클릭하여 항목을 추가 합니다.
  9. PlayerNameInputField 를 필드로 드래그 합니다.
  10. Dynamic String 섹션의 드롭다운 메뉴에서 PlayerNameInputField.SetPlayerName() 를 선택 합니다.
  11. 신을 저장 합니다.

이제 Play 후 이름을 입력하고 플레이를 중지 합니다. 다시 플레이 하면 방금전에 입력했던 내용이 나타나게 됩니다. 점점 더 나아지고 있으나 사용자 경험 측면에서는 연결과정과 연결하고 룸에 참여하는 문제등에 대한 피드백을 주지는 않았습니다.

연결 진행 과정

여기에서는 간결함을 유지 할 것이고 이름 필드와 플레이 버튼을 감추고 간단한 문자열인 "Connecting..."은 연결하는 동안 표시하고 필요시에 다시 되돌릴 것 입니다.

이렇게 하기 위해서 플레이 버튼과 이름 필드를 그룹핑 하여 그룹단위로 활성 또는 비활성 시킬 것 입니다. 나중에 그룹에 추가적인 기능을 추가할 수 있고 로직에 영향은 주지 않을 것 입니다.

  1. Launcher 을 오픈하고 있어야 합니다.
  2. 'GameObject/UI/Panel' 메뉴를 통하여 UI Panel 을 생성하고 이름을 Control Panel 으로 변경 합니다.
  3. 이 panel 에서는 컨텐츠만을 다루고 시각적인 사항이 필요없기 때문에 Control PanelImageCanvas Renderer 를 삭제 합니다.
  4. Control PanelPlay ButtonName InputField 를 드래그 합니다.
  5. 유니티 메뉴 'GameObject/UI/Text' 에서 UI Text를 생성 후 Progress Label 로 이름을 부여 합니다. 시각적인 요소에 대해서는 크게 걱정하지 않아도 됩니다. 실행시에 상황에 따라 활성/비활성 해 줄 것입니다.
  6. Progress LabelText 컴포넌트를 선택 합니다.
  7. Alignmentcenter alignmiddle align 로 설정 합니다.
  8. Text 값을 "Connecting..." 으로 설정 합니다.
  9. Color를 흰색으로 또는 배경에서 강조될 수 있는 색상으로 설정 합니다.
  10. 신을 저장합니다.

현재까지 테스트로 Control PanelProgress Label을 여러 연결 단계가 어떻게 진행되고 있는지 보기 위해 사용가능/불가로 할 수 있습니다. 두 개의 게임오브젝트들을 어떻게 활성시키는지 스크립트를 편집 해 보도록 하겠습니다.

  1. Launcher 스크립트를 편집 합니다.

  2. Public Properties 위치에 다음의 프로퍼티들을 추가 합니다.

    C#

        [Tooltip("The Ui Panel to let the user enter name, connect and play")]
        public GameObject controlPanel;
        [Tooltip("The UI Label to inform the user that the connection is in progress")]
        public GameObject progressLabel;
    
  3. Start() 메소드에 다음을 추가 합니다.

    C#

        progressLabel.SetActive(false);
        controlPanel.SetActive(true);
    
  4. Connect() 메소드의 시작 부분에 다음을 추가 합니다.

    C#

            progressLabel.SetActive(true);
            controlPanel.SetActive(false);
    
  5. OnDisconnectedFromPhoton() 메소드의 시작 부분에 다음을 추가 합니다.

    C#

            progressLabel.SetActive(false);
            controlPanel.SetActive(true);
    
  6. Launcher 스크립트를 저장하고 유니티 컴파일이 완료될 때 까지 기다립니다.

  7. 아직 Launcher 신에 있어야 합니다.

  8. Hierarchy 에서 Launcher 게임오브젝트를 선택 합니다.

  9. Hierarchy 에서 Control PanelProgress Label 을 드래그 하여 Launcher 컴포넌트의 각각의 필드에 드래그 합니다.

  10. 신을 저장 합니다.

이제 신을 플레이 합니다. Control Panel 이 표시되고 플레이 버튼을 클릭하자마자 Progress 레이블이 표시 될 것 입니다.

지금까지 로비 부분에 대해서 잘 해 왔습니다. 로비의 추가적인 기능을 위해서 게임 자체를 변환하고 다양한 신을 생성하여 룸에 참여 했을 때 레벨에 맞는 화면을 로드 할 수 있어야 합니다. 다음 섹션에서는 이러한 사항을 다룰 것 이며 로비 시스템에 대해 마치겠습니다.

다음 파트.
이전 파트.

Back to top