본문 바로가기

Unity 개발 공부

[내배캠] 본캠 57 pun2 공부3

AutomaticallySyncScene : awake 나 start에서 true로 만들어두면
방장이 씬을 이동하면 모두 같이 이동한다.
LoadLevel(int levelNumber) : 로 씬 전환한다.

IsConnected : 연결됐는지
InLobby : 로비에 있는지(마스터서버아님)
InRoom : 방에 있는지
NetworkClientState : 본인의 상태 체크가능


switch(PhotonNetwork.NetworkClientstate)
로해서 누락된것 붙여주기하면
case ClientState.PeerCreated:
break;

case Clientstate.Authenticating:
break;

...


OfflineMode : start에서 true로 하면 멀티코드가
싱글에서도 버그가 안난다.
해당 기능을 이용한 싱글에서는
LocalPlayer - 엑터넘버는 항상 -1로 되어지며
NickName,Instatiate, Destroy는 싱글기반으로 바뀌어서 작동

PlayerList- 로컬플레이어만 포함
PlayerListOthers - 항상 비어있음
Time - Time.time
IsMasterClient - 항상 true
RPC - 일반 함수로 호출

방에서
MasterClient 방장 플레이어
LocalPlayer: 자기자신(IsMIne이 True)인 플레이어
PlayerList: 현재 방에 접속해있는 모든플레이어를 담은 배열, 
액터넘버 순서로 정렬된 플레이어 리스트 오름차순으로 작은순서에서 증가한다.
PlayerListOthers: 마찬가지로 Player[]타입인데, (LocalPlayer) 나를 제외한 액터넘버 순서로 정렬된 플레이어 리스트

PhotonNetwork.CurrentRoom. ~
IsOpen : false 하면 방이 닫혀서 로비에 있는 사람은 참가 불가, 방은 보임
IsVisible: false 하면 로비에서 방자체가 안보임
Name : 방이름
PlayerCount : 방에 있는 사람 수

PhotonNetowrk.LocalPlayer.~
혹은 
PhotonNetwork.PlayerList[0].~
등 Player형식에 다가능... 그뒤 뒤에 붙일수있음
ActorNumber: 방에[ 참여한 순서대로 1부터 증가하는 플레이어를 구별하는 고유 숫자.
IsMasterClient: 방장인지
NickName: 닉네임
CustomProperties: 태그를 가져올때
SetCustomProperties: 태그를 저장할때


방관리꿀팁

네트워크 매니저에서 변수 동기화하는 방법이있다.

[HideInInspector] public PhotonView PV;

[SerializeField] bool isStart;
public bool IsStart { get => isStart; set => PV.RPC(nameof(SetIsStartRPC), RpcTarget.AllBufferedViaServer, Value);}
[PunRPC] void SetIsStartRPC(bool value) => isStart = value;

void Update()
{
  if(Input.GetKeyDown(KeyCode.Alpha1)) IsStart = !IsStart;
}
불값 플래그가 선언이되었을때,
get은 그냥 isStart를 리턴한다는데,
업데이트에서 특정 키를 누르면 IsStart가 false가 되게끔하는 혹은 플래그 상태를 반전시키는 코드가있다면
Set부근에서 RPC로 감싸줘서 한사람이 바꾸면 모두에게 바뀌도록 변수를 동기화할 수 있다.
여기서 nameof로 한것은 string 으로 해당 맴버나 필드를 변환해주는 기능을하고있기때문에,
그냥 "SetIsStartRPC"를 넣어줘도된다.
저렇게 한이유는 아래의 SetIsStartRPC가 사용중이다라는것을(참조) 코드상에서 구분해주기때문에
nameof를 썼을뿐 로직적으로는 string으로 써줘도 똑같이 작동한다.
AllBufferedViaServer의 경우 한번에 들어와서 시작하는게아니라 조금 순서가 다르게
방을 나왔다 들어올때도 그때그때 동기화되게하려면 써주는 기능이다.


매니저와 플레이어간의 작용 꿀팁
public class NetworkManager : MonoBehaviourPunCallbacks
{
 public static NetworkManager NM; // 전역으로 변수 선언
 void Awake() => NM = this;  // 캐싱
 
 public List<PlayerScript> players = new List<PlayerScript>(); 
 public PlayerScript myPlayer;
 public Text LogText;
 
 public void ShowLog(string log) => LogText.text = log;
 public void SortPlayers() => players.Sort((p1, p2) => p1.actor.CompareTo(p2.actor)); // p1의 액터넘버, p2의 액터넘버
를 비교해서 Sort로 오름차순한다, actor는 PlayerScript에 액터넘버가 캐싱되어있다.

 void Start()
{
 Scree.SetResoultion(960, 450, false);
 PhotonNetwork.ConnectUsingSettings();
}

public override void OnConnectedToMaster() => PhotonNetowrk.JoinLobby();
public override void OnJoinedLobby() => PhotonNetwork.JoinOrCreateRoom("Room", new RoomOptions { MaxPlayer = 4 } , null}
public override void OnJoinedRoom()
{
 myPlayer = PhotonNetwork.Instantiate("Player", new Vector3(Random.Rage(-5,5), 0 ,0 ), Quaternion.identity)
.GetComponent<PlayerScript>();
}

...

그다음 
using static NetworkManager; // 해당 static을 바로 꺼내쓰기위해

public class PlayerScript: MonoBehavioruPun
{
 [HideInInspector] public PhotonView PV;
 [HideInInspector] public string nick;
 [HideInInspector] public int actor;

 [SeriliazeField] int coin;
 public int Coin {get => coin; set => Pv.RPC("SetCoinRPC", RpcTarget.AllBufferedViaServer, value);}
[PunRPC] void SetCoinRPC(int value) => coin = value;

void Start() // 캐싱해주고 , 해당 players 리스트에 이 스크립트자체를 넣어주고, SortPlayers()도 실시해준다.
{
 PV = PhotonView;
 nick = PV.Owner.NickName;
 actor = PV.OwnerActorNr;
 
 NM.M.players.Add(this);
 NM.SortPlayers();
}

....

이러면
myPlayer.PV.RPC("DDuckRPC", RpcTarget.AllViaServer);

players.Find(x => x.ColorIndex == 5)?.PV.RPC("DDuckRPC", RpcTarget.AllViaServer); 등 처럼 사용가능하다.
?는 널이아니라면 컬러인덱스가 5인게 있다는거니까 해당 플레이어를 찾아 뒤에 내용을 쓸수잇는것이다.


비밀방
공개된 방은 [방이름]만으로 생성한다.
비밀방은 _로 나누어 [방이름_비밀번호] 꼴로 생성한다.
로비에서 방이 보여질때는 _이후를 잘라낸다.
_있으면 비밀방이니 열쇠아이콘 표시.
로비에서 일반방을 클릭하면 방 이름으로 참가하고,
비밀방을 클릭하면 비밀방패널을 띄윈다.
패널을 띄울때 투명하게 [방이름_비밀번호] 텍스트를 적어 비교가 쉽게한다.
비밀번호를 오바르게 입력하여 [방이름_비밀번호] 꼴을 투명하게 적어놓은 텍스트와 비교후 같은면 입장한다.


중립오브젝트와 오브젝트풀링

void Update()
{
 if ( Input.GetKeyDown(keyCode.Alpha1))
 {
  GameObject CurPortion = PhotonNetwork.InstantiateRoomObject("Portion", Vector3.up * 3, Quaternion.identity);
 CurPortion.GetComponent<Rigidbody2D>().AddForce(Random.insideUnitSphere * 400);
 }
}
중립 오브젝트는 방장만 만들 수 있고 방장이 나가도 파괴되지않는다.

PhotonView를 보면
IsMine : True (master)
Controller : 1(master)
Owner : null
Creator : null 이다.
해당 오브젝트들은 프리팹화해서 세팅을
PhotonView 컴포넌트 추가후 Ownership Transfer는 Fixed로 해서 (Scene소유)로 만들고
Observed Components에는 없음으로 주로한다.