PhotonView Class Reference

Public Member Functions

void RequestOwnership ()
 Depending on the PhotonView's ownershipTransfer setting, any client can request to become owner of the PhotonViewMore...
 
void TransferOwnership (PhotonPlayer newOwner)
 Transfers the ownership of this PhotonView (and GameObject) to another player. More...
 
void TransferOwnership (int newOwnerId)
 Transfers the ownership of this PhotonView (and GameObject) to another player. More...
 
void OnMasterClientSwitched (PhotonPlayer newMasterClient)
 Check ownerId assignment for sceneObjects to keep being owned by the MasterClient. More...
 
void SerializeView (PhotonStream stream, PhotonMessageInfo info)
 
void DeserializeView (PhotonStream stream, PhotonMessageInfo info)
 
void RefreshRpcMonoBehaviourCache ()
 Can be used to refesh the list of MonoBehaviours on this GameObject while PhotonNetwork.UseRpcMonoBehaviourCache is true. More...
 
void RPC (string methodName, PhotonTargets target, params object[] parameters)
 Call a RPC method of this GameObject on remote clients of this room (or on all, inclunding this client). More...
 
void RpcSecure (string methodName, PhotonTargets target, bool encrypt, params object[] parameters)
 Call a RPC method of this GameObject on remote clients of this room (or on all, inclunding this client). More...
 
void RPC (string methodName, PhotonPlayer targetPlayer, params object[] parameters)
 Call a RPC method of this GameObject on remote clients of this room (or on all, inclunding this client). More...
 
void RpcSecure (string methodName, PhotonPlayer targetPlayer, bool encrypt, params object[] parameters)
 Call a RPC method of this GameObject on remote clients of this room (or on all, inclunding this client). More...
 
override string ToString ()


PhotonView 클래스는 네트워크상에 전송되는 오브젝트를 위한것으로 보인다 유니티네트워크의 NetworkIdentity 컴포넌트와 비슷한 역할을 하는듯하다


홈페이지에서는 아래와같이 설명되었있다


네트워크 객체

일반 GameObject들은 PhotonView 컴포넌트가 있는 네트워크 객체로 전환될 수 있습니다. PhotonView는 네트워크를 통해 객체를 식별하고 해당 객체의 상태를 동기화하는 데 사용됩니다. 일반적으로, PhotonView는 런타임에 인스턴스화된 프리팹에 연결됩니다. 종종 모든 선수들은 통제할 자신만의 객체들을 가지고 있습니다.

GameObject에 PhotonView를 추가하기위해서는, 단순히 GameObject를 선택하고 사용하면 됩니다:"Components/Miscellaneous/Photon View"

Transform 동기화


튜도리얼에 따르면 트랜스폼 동기화를 위한 컴포넌트가 PhotonTransformView  라고 되었는데 PUN2 에서는  튜토리얼버전은 클래식으로 되어있다. 클래식에 비해 옵션이 없기때문에 사용이 좀더 편해보인다



Animation 동기화


PhotonAnimatiorView 스크립트를 추가하면 해당 오브젝트의 animator 에서 레이어와 파라미터를 친절하게 가져와준다


Discreate : 초당 10회의 데이터를 전송

Continuous : 매 프레임마다 데이터를 전송






위에 두 컴포넌트를 추가한 뒤 PhotonView 컴포넌트에 observed components에 추가해주자





기타 컴포넌트 동기화


동기화가 필요한 컴포넌트일 경우 IPunObservable 인터페이스를 상속받아 OnPhotonSerializeView를 정의 후 

위 컴포넌트들 처럼 PhotoView 컴포넌트에 추가해준다


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class PlayerManager : MonoBehaviourPunCallbacks , IPunObservable
{
 
     public void OnPhotonSerializeView(PhotonStream stream, PhotonMessageInfo info)        
    {
            if (stream.IsWriting)
            {             
                stream.SendNext(IsFiring);
            }
            else
            {          
                this.IsFiring = (bool)stream.ReceiveNext();
            }
    }
}
cs


https://doc.photonengine.com/ko-kr/pun/v2/demos-and-tutorials/pun-basics-tutorial/player-prefab


캐릭터 프리펩을 만들기 위한 애니메이션, 입력 관련이 주된내용으로 관련 내용은 따로 포스팅을 해보자


이번 장에서 사용한 포톤 관련 클래스는 PhotonView 클래스로 해당 오브젝트가 클라이언트의 소유인지 확인 할 수 있다


bool PhotonView.isMine
get

True if the PhotonView is "mine" and can be controlled by this client.

PUN has an ownership concept that defines who can control and destroy each PhotonView. True in case the owner matches the local PhotonPlayer. True if this is a scene photonview on the Master client.

https://doc-api.photonengine.com/en/pun/current/class_photon_view.html


아래와 같이 빔에 맞았을 때 본인의 캐릭터일때만 hp를 깍게 되어있다


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
void OnTriggerEnter(Collider other)
        {
            if (!photonView.IsMine)
            {
                return;
            }
 
            if (!other.name.Contains("Beam"))
            {
                return;
            }
            Health -= 0.1f;
        }
 
        void OnTriggerStay(Collider other)
        {
 
            if (!photonView.IsMine)
            {
                return;
            }
 
            if (!other.name.Contains("Beam"))
            {
                return;
            }
   
            Health -= 0.1f * Time.deltaTime;
        }
cs








1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using Photon.Pun;
using Photon.Realtime;
 
 
namespace Com.MyCompany.MyGame
{
    public class GameManager : MonoBehaviourPunCallbacks
    {
 
        public override void OnLeftRoom()
        {
            SceneManager.LoadScene(0);
        }
 
        public void LeaveRoom()
        {
            PhotonNetwork.LeaveRoom();
        }
 
        private void LoadArena()
        {
            if(!PhotonNetwork.IsMasterClient)
            {
                Debug.LogError("PhotonNetwork : Trying to Load a level but we are not the master Client");
            }
 
            Debug.LogFormat("PhotonNetwork : Loading Level : {0}", PhotonNetwork.CurrentRoom.PlayerCount);
            PhotonNetwork.LoadLevel("Room for " + PhotonNetwork.CurrentRoom.PlayerCount);
        }
 
 
        public override void OnPlayerEnteredRoom(Player other)
        {
            Debug.LogFormat("OnPlayerEnteredRoom() {0}", other.NickName); 
 
 
            if (PhotonNetwork.IsMasterClient)
            {
                Debug.LogFormat("OnPlayerEnteredRoom IsMasterClient {0}", PhotonNetwork.IsMasterClient);
 
                LoadArena();
            }
        }
 
        public override void OnPlayerLeftRoom(Player other)
        {
            Debug.LogFormat("OnPlayerLeftRoom() {0}", other.NickName); 
 
            if (PhotonNetwork.IsMasterClient)
            {
                Debug.LogFormat("OnPlayerLeftRoom IsMasterClient {0}", PhotonNetwork.IsMasterClient); 
 
                LoadArena();
            }
        }
    }
}
cs

GameManager 스크립트에  OnPlayerEnteredRoom 메소드로 현재 플레이 인원에 따라 만들어둔 씬을 로드하게 하자
** PhotonNetwork.LoadLevel() 는 MasterClient 만이 호출가능하다

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
 
namespace Com.MyCompany.MyGame
{  
    public class Launcher : MonoBehaviourPunCallbacks
    {
 
        [SerializeField]
        private GameObject controlPanel;
        [Tooltip("The UI Label to Inform the user that the connection is in progress")]
        [SerializeField]
        private GameObject progressLabel;
 
        string gameVersion = "1";
 
        bool isConnecting=false;
 
        private void Awake()
        {
            PhotonNetwork.AutomaticallySyncScene = true;
        }
 
        void Start()
        {
            progressLabel.SetActive(false);
            controlPanel.SetActive(true);
 
        }
   
        void Update()
        {
        
        }
        public void Connect()
        {
            isConnecting = true;
            if (PhotonNetwork.IsConnected)
            {
                PhotonNetwork.JoinRandomRoom();
            }
            else
            {
                PhotonNetwork.GameVersion = gameVersion;
                PhotonNetwork.ConnectUsingSettings();
            }
 
            progressLabel.SetActive(true);
            controlPanel.SetActive(false);
 
        }
 
        public override void OnConnectedToMaster()
        {
            Debug.Log("PUN Basics Tutorial/Launvher: OnConnectedToMaster() was called by PUN");
            if (isConnecting)
            {
                PhotonNetwork.JoinRandomRoom();
            }
        }
        public override void OnJoinRandomFailed(short returnCode, string message)
        {
            Debug.Log("PUN Basics Tutorial/Launcher:OnJoinRandomFailed() was called by PUN. No random room available, so we create one.\nCalling: PhotonNetwork.CreateRoom");
            PhotonNetwork.CreateRoom(nullnew RoomOptions());
        }
 
        public override void OnDisconnected(DisconnectCause cause)
        {
            Debug.LogWarningFormat("PUN Basics Tutorial/Launcher: OnDisconnected() was called by PUN with reason {0}", cause);
        }
 
        public override void OnJoinedRoom()
        {
            Debug.Log("OnJoinedRoom Event");
            if (PhotonNetwork.CurrentRoom.PlayerCount == 1)
            {
                Debug.Log("We load the 'Room for 1' ");
 
                PhotonNetwork.LoadLevel("Room for 1");
            }
        }
    }
}
cs


Launcher 스크립트에 PhotonNetwork.JoinRandomRoom() 으로 랜던룸에 입장을 시도 할때 방이없으면 접속에 실패하게되는데 해당 코드를 작성하지 않았다


OnJoinRandomFailed 콜백 메소드를 통하여 방이없을 때 방을 만들어보자


이 후 서버에 연결을 해보면 어제 만든 씬으로 이동하는 것을 볼 수 있다


대강 접속로직 알것같다




https://doc.photonengine.com/ko-kr/pun/v2/demos-and-tutorials/pun-basics-tutorial/game-scenes

페이지 번역이 되어있지 않지만 전 튜토리얼과 크게다르지 않다


패널에 버튼을 만들고 방나가는 이벤트를 등록하고 바닥과 벽오브젝트를 생성


씬을 같은 구조의 씬을 4개만들고 바닥과 벽스케일과 위치만 변경한다


이후 빌드 설정에서 지금까지 만든 씬들을 등록한다


이번에 만든 GameManager 스크립트는 방에서 나가는 메소드와 방을 나갔을 때 첫 로비씬으로 바꾸는 이벤트메소드말고는 없다


퇴근 후 귀가가 늦었으므로 오늘은 여기까지


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
using System;
using System.Collections;
using UnityEngine;
using UnityEngine.SceneManagement;
using Photon.Pun;
using Photon.Realtime;
 
 
namespace Com.MyCompany.MyGame
{
    public class GameManager : MonoBehaviourPunCallbacks
    {
 
        public override void OnLeftRoom()
        {
            SceneManager.LoadScene(0);
        }
 
        public void LeaveRoom()
        {
            PhotonNetwork.LeaveRoom();
        }
 
    }
}
cs



4일차 


https://doc.photonengine.com/ko-kr/pun/v2/demos-and-tutorials/pun-basics-tutorial/lobby-ui


해당 튜토리얼을 보고 유저네임 입력 UI와 스크립트를 만들었다




1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using Photon.Pun;
using Photon.Realtime;
 
namespace Com.MyCompany.MyGame
{
 
    [RequireComponent(typeof(InputField))]
    public class PlayerNameInputField : MonoBehaviour
    {
 
        const string playerNamePrefKey = "PlayerName";
        // Start is called before the first frame update
        void Start()
        {
            string defaultName = string.Empty;
            InputField _inputField = this.GetComponent<InputField>();
            if(_inputField != null)
            {
                if (PlayerPrefs.HasKey(playerNamePrefKey))
                {
                    defaultName = PlayerPrefs.GetString(playerNamePrefKey);
                    _inputField.text = defaultName;
                }
            }
 
            PhotonNetwork.NickName = defaultName;
        }
 
        // Update is called once per frame
        void Update()
        {
        
        }
 
        public void SetPlayerName(string value)
        {
            if (string.IsNullOrEmpty(value))
            {
                Debug.LogError("Player Name is null or empty");
                return;
            }
            PhotonNetwork.NickName = value;
 
            PlayerPrefs.SetString(playerNamePrefKey, value);
        }
    }
}
cs


**InputField 의 on value changed 이벤트에 SetPlayName걸어도 null이 나가서 

인자를 InputField로 변경 후  value.text로 접근하니 접근이 가능했다.

 ** public void SetPlayerName(InputField value){ value.text ...........

원인을  찾아보자

추가

위에 Dynamic string 쪽에 선택을 했어야했다 ... 글을 대충읽지 말자




[RequireComponent(typeof(컴포넌트))]

스크립트가 달린 오브젝트에 해당 컴포넌트가 없다면 추가를 요청한다


C#에서 [] 연산자 용법중 어트리뷰트 부분을 참고해보자

https://docs.microsoft.com/ko-kr/dotnet/csharp/programming-guide/concepts/attributes/index


PlayerPrefs 클래스는 로컬에 간단한 자료를 저장 할 수있게 해준다

https://docs.unity3d.com/ScriptReference/PlayerPrefs.html





3일차 


공식 홈페이지에 튜토리얼이 한글로 잘 나와있다

참조 : https://doc.photonengine.com/ko-kr/pun/v2/demos-and-tutorials/pun-basics-tutorial/intro



유니티 에셋스토에서 PUN을 받는다







 PUN 을 임포트하고 포톤 클라우드의 애플리케이션 ID를 입력하면 된다

 




씬을 하나 만든 후 빈 오브젝트에 아래 스크립트를 추가해 보자


https://doc-api.photonengine.com/ko-kr/pun/current/index.html 

API 도 한글로 잘 되어있다


1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
 
namespace Com.MyCompany.MyGame
{  
    public class Launcher : MonoBehaviour
    {
 
        string gameVersion = "1";
 
        private void Awake()
        {
            PhotonNetwork.AutomaticallySyncScene = true;
        }
 
        void Start()
        {
            Connect();
        }
   
        void Update()
        {
        
        }
        public void Connect()
        {
            if (PhotonNetwork.IsConnected)
            {
                PhotonNetwork.JoinRandomRoom();
            }
            else
            {
                PhotonNetwork.GameVersion = gameVersion;
                PhotonNetwork.ConnectUsingSettings();
            }
        }
 
    }
}



PhotomNetwork가 사용중이니


https://doc-api.photonengine.com/ko-kr/pun/current/class_photon_network.html

관련 API를 보자




Window -> Photon Unity Networking ->PUN Wizard

PUN 관련 세팅을 할 수 있다





Logging 을 full로 설정하면 전체 로그를 확인 할 수 있다









포톤  회원가입

https://dashboard.photonengine.com/ko-KR/account/SignUp



메일 주소 입력


가입한 메일에 비밀번호 설정 URL이 온다

outlook 메일을 사용했더니 정크메일 보관함들어간다

메일이 보이지않으면 스팸메일함을 찾아보자




비밀번호를 설정 후 포톤클라우드 관리화면을 보면 

20 CCU 짜리 무료 플랜을 볼 수 있다

 CCU( Concurrent connected User ) : 동시 접속자수 




어플리케이션 ID을 확인해 놓자


PUN 사용은 다음에 해보자


2일차


멀티 플레이를 위해 서버 엔진을 찾아 나서자


직접 만들기에는 어렵다


어떤 친철한 분이 서버 엔진을 이쁘게 정리한 것을 찾았다 


구축 방식으로 나눠보자


무료 라이센스와 자료가 많아 보이는   ProudNet , Photon Cloud 를 두고 고민을 해보자


포톤 클라우드 -  클라우드 환경을 제공하여 별도의 서버구축이 필요하지 않다. 서버 커스텀이 불가능하고 릴레이 서버로 빠른 반응이 필요한 곳에 적합하                        지 않다는 평이있다 포톤 서버라고 self-hosting 제품도 있다. 유니티 프로젝트에서 많이쓰는듯하다.


프라우드넷 - 국내 업체에서 제작해서인지 한글 문서가 잘되어있다. 하지만 서버를 직접 구축해야함. 홀펀칭 p2p도 지원을 하는듯해서 빠른 반응이 필요한 경우에도 사용 할 수 있을듯하다. 


기왕 하게된거 둘다 써보자 



츨처: http://www.gamecodi.com/board/zboard.php?id=GAMECODI_Talkdev&no=4749









1일차

 

유니티를 설치해보자


https://store.unity.com/kr


돈이없으니 Personal을 설치하자




모바일이나 웹 버전을 빌드 할 수도있니 일단 설치하자




적당히 다음 다음


설치 끝


+ Recent posts