본문 바로가기

Photon

Photon 마지막 날 (Photon Voice, Photon 소유권 넘기기, Map Editor(맵 툴 제작))

목차


Photon Voice 세팅

플레이어 안에 스피커 역할 하는 애를 하나 만들거임

 

우리가 필요한 정보들 =

 

Game Scene----->

voice 오브젝트

여기에 Recorder 컴포넌트 넣기

(참고)

더보기
더보기

눌러서 말하기 하려면 Transmit Enablked 를 코딩으로 제어해주삼~

이거 체크되어있어야 시작하자마자 말하기 가능함!

Voice 오브젝트에

Photon Voice Network  컴포넌트도 추가해주자!

Photon Voice Network

Primary Recorder 에 Recorder 를 넣어야 하는데,

지금 Voice 오브젝트에 붙어있으니까, Voice 를 집어넣자


그다음에 우리가 만든 Player 에 가보자

Player 라는 프리팹은 Photon.Instantiate 때문에

Reseources 폴더에 넣어놨을 거임!

 

여기에 Speaker 라는 오브젝트추가하고

Player 프리팹에 Speaker 빈게임오브젝트 추가한 모습

Speaker 의 Position 등을 Reset 시켜준다.

Speaker 가 멀어지면 소리도 잘 안들리기 때문이다

 

저 위의 컴포넌트 2개를 추가한다

Audio 와 Speaker 

 

그 후, Player Object 에서 Photon Voice View 컴포넌트 추가!

그리고 Speaker In Use 에 Speaker 컴포넌트 넣자! (Player 안에 있는 컴포넌트)

 

위에 AudioSource 는 예전에 총소리 때문에 넣었던거임

Use Primary Recordcer 에 체크 하면 Recorder In Use 에 안넣어도 알아서 찾아줌!

원래는 저것도 넣어야 하는데, 그럴려면 아까 GameScene 에 넣어줬던 Recorder 오브젝트를 넣어줘야 하는데,

프리팹에는 오브젝트를 넣을 수 없다! (프리팹에 프리팹은 넣을 수 있는데)

 

그렇기 때문에 Use Primary Recorder 를 체크해서 알아서 찾게 하게 하자

 

Speaker 는 각자가 나와야 하기 때문에 Player 안에 있는 Speaker 를 넣자


재생 해보면 GameScene 에 있는 Recorder 에 Level 값이 나옴

내가 말했을 때 저게 올라가고 그런거면, 상대방도 들리는거임!

재생 했을 때만 저 Level 이 나온다!!!


 

마이크 체크 해보기

LobbyManager.cs 에서

Start() 에

이렇게 마이크 디바이스 배열로 넣어서 확인 해볼 수 있음

지금은 마이크 1개만 있어서 위와 같이 나오는거임

 

보이스는 여기서 마무리!


포톤 소유권 넘기기

isMine 의 소유권을 넘길 수가 잇음

그러면

B는 움직여도 아무것도 안움직이는데

 

A 가 움직이면 A,B 둘다 움직여짐

 

어떤 협동게임에서, A는 몸을 맡고 B는 팔을 맡았을 때,

어떨 때는 A가 두개 다 컨트롤 하는 기획의 게임이 있었다.

그럴 때, 이런식으로 isMine 의 소유권을 넘겨줘서 하는 방식을 쓰기도 한다.


좀 재밌는거 해보기

 ( Feat. 서버에서 움직임을 자체적으로 통제하는 방법 )

 

소유권 문제

 

2D Shooting 느낌으로 Plane 하나 만든다

PlaneMove

스크립트도 하나 만들어서 집어넣는다

그냥 2D 슈팅임

 

그리고 Resources 에 Plane 을 Prefab 으로 넣자

Photon으로 생성시키려고

GameManger 에서 Plane 소환하는 코드 넣자

게임씬에 카메라 넣자.

Plane 에는 카메라 없으니까

 

방장 컴퓨터에 있는 오브젝트들은 같이 움직임. 

방장이 같이 움직여준거임

 

 

왜? IsMine 을 안걸러줬기 때문!

 

그래서 IsMine 을 넣어보자

photonView.IsMine 

조건문 안에 다 넣어서, 내꺼만 실행 되게 해보자

이제 이 조건문을 Update 문에 넣을 건데

 

저게 무슨말이냐면, 5번키를 눌렀을때

만약 방장이 아니고, 내 것일 때

나의 소유권을 방장한테 넘긴다는거임!

 

왜 방장이 아니고, 내것이어야 하냐면,

소유권을 방장한테 넘겨줄건데, 방장이면 안되지?

 

그리고 내거를 상대방한테 소유권을 넘겨준다는거니까 그런거임!

 

 

이거 되게 하려면 Photon View 에 옵션을 하나 건드려야함

 

TakeOver 를 해줘야 저게 바꿀 수 있음

 

Request 는 요청하는거임!

 

실행 했을 때 B 의 컴퓨터의 B캐릭터

True 상태

5번 키를 넘기면 False 가 된다.

Controller 와, Owner 의 이름도 A꺼로 바뀌는데

 

지금 A의 이름도 123 이고 B 의 이름도 123 이어서 안바뀐것 처럼 보이는 것이다.

이제는

방장이 둘 다 움직이게 할 수 있음!


근데 이 상황에서  B 가 움직이게 할 수 있음

B의 키값을 A가 받고

그 키값을 통해 A가 B 의 오브젝트를 움직이게 하는것이다.

 

 

이게 시사하는 바가 크다.

아니, 굳이 B가 원래 움직이게 할 수 있었는데

A한테 소유권 주고 B가 왜 또 움직이게 하게 하는 건지?

라고 생각 할 수 있다.

 

근데 이렇게 해버리면, 

모든 움직임을 서버에 보내고 그 서버가 통제하게 할 수 있는것이다.

구조로 보자면 이게 훨씬 합리적이고, 원래 이런식으로 서버에서 통제 하게 한다.

isCreator 라는 bool 형식을 하나 생성

시작할 때, isMine 을 넣으면 true 가 들어갈꺼임

 

A든 B 든 

각각의 PC 에서 자기자신은 IsMine 이 true 이기 때문

(당연한 말)

B PC 에서 캐릭터 B 의 경우

 

이렇게 하면, isCreator 가 true 이니까

저게 Update 에 있는 코드가 사용은 되는데

 

transform.position 이 안먹힘

방장한테 소유권을 줘버렸으니까

이 코드도 추가한다.

transform.position 코드는 위에서 끌고 내려온거임

 

만약 내가 방장일 때,

움직임이 감지되면

이동시킨다.

 

움직임 벡터 dir 의 크기가 0보다 클 때, 움직이게 하는것.

저기서 sqrMagnitude 는 루트를 안씌운 상태이다.

Ex)  Vector2 (1,1) 의 Magnitude(크기)  는 루트(1^2 + 1^2) 이다. 루트(x의 제곱 + y의 제곱)

근데 위의 경우는 0이상인지만 판단 하면 되니까, 루트까지 굳이 계산할 필요없게

(x의 제곱 + y의 제곱)

인 경우이다.

 

그리고, Rpc 함수로 , 아까 구현했던 dir 을 넣는다.

 

여기에 RPC 함수 호출 (방장한테만 호출)

(이렇게 되면 B PC 에 있는 B 가 호출 할 거임

isCreator 가 true 라는 얘기는, 원래 자기 PC 에 주인이었다는 소리기 때문에)

 

그러면 B pc 에 있는 B 가 자기 dir 을 동기화 요청을 함

 

그럼 이제 여기서,

 

A pc 가 MasterClient 이니까,

A pc 에서 A, B 둘 다 움직이게 한다.


즉, B의 dir 값을 A한테 보내고, 

A는 그 값을 받아서 A pc 에 있는 p=p0 + Vt 계산을 해서

B 를 움직이게 한다.

 

서버에서 다 계산하고 움직이게 한거임


중요한건 이거임

소유권을 넘길 수 잇음

일단 이건 방장한테 보낸 모습이고

이거는 지금 나한테 준다는거고,

다른사람의 Owner 를 찾아서 가져오면 내 소유권을 다른사람한테 줄 수 있다는거임

 

결국 시사하는 바는

이렇게 하면 모든 움직임을 다 서버에서 하겠다는거임

 

나의 소유권을 가지고 있는 사람한테 보낸다는거임


맵 툴 제작 

MapStudy

Project 를 새로 만들자!

 

빈게임 오브젝트 Map 을 만들고

Script 이름도 Map 으로 해서 넣자

 

가로 3 세로 3인 타일을 맵 툴을 이용해서 만들어 볼거임

 

 

좀 커스텀 해볼거야 ㅎㅎ

일단 위처럼 작성하고,

 

MapEditor 라는 스크립트를 하나 더 만들자

 

MapEditor ---->

네임스페이스로 using UnityEditor; 작성한 후,

[CustionEditor] 위에 저렇게 꼭 써줘야 한다

얘는 플레이를 안해도 계속 돌아가고 있음. Editor 로 쓰게 저렇게 작성하면.

 

실험으로, 해당 게임오브젝트(Map) 이 선택되면 불러지는 함수를 작성해보자

OnEnable 이라고 있음

 

다른오브젝트 눌렀다가 

Map 누르면 계속 선택된다고 뜬다!

 

Override 로 OnInspectorGUI 를 불러오자

그리고 base 에서 저렇게 또 뜰 텐데,

저걸 주석처리 해버리면  해버리면 자식이 저걸 없앤거임.

그러면 인스펙터 창에 보면 저게 안나올 거임

 

짠!

있었는데,,?

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEditor;

[CustomEditor(typeof(Map))]
public class MapEditor : Editor
{
    // target 을 담을 변수
    Map map;

    // 해당 게임 오브젝트가 클릭되었을 때 호출되는 함수
    private void OnEnable()
    {
        Debug.Log("선택됨");
        // 선택될 때마다 map 에 넣는거임
        map = (Map)target;
    }
    
    //Inspector 에 변화가 있을 때 호출되는 함수
    public override void OnInspectorGUI()
    {
        //base.OnInspectorGUI();

        // tileX, tileZ 를 표현
        EditorGUILayout.IntField("타일 가로", map.tileX);

    }
}

이제 이렇게 작성해보자

OnEnable() 

안에 map = (Map)target; 을 해버리면

Map 컴포넌트를 가져오게 하는거임

 

target 으로 하면 무조건 잡히게 되어있음

Map 컴포넌트를 가져오는 느낌

 

위처럼 입력하면

짠! 이렇게 나옴

근데 Enter 만 눌러도 0이 되버리네,,?

 

그러니까, map 에서 변수를 가져와서 저장하자

 

Z까지 해보자

이렇게 작성!

 

타일은 -1 값이 있으면 안되니까,

0~100까지 제한 해주자

Clamp도 넣고

제한 됨
이거 넣어주면

저 변수 사이에 공간이 생김

 

이렇게 사이에 공백을 줄 수 있음!

Map 을 클릭하면 저렇게 나옴

 

이제 이걸 만들어보자!

 

    //Scene 화면을 그리는 함수
    private void OnSceneGUI()
    {
        Vector3 start;
        Vector3 end;
        Handles.color = Color.red;
        //Handles.DrawLine(Vector3.zero, Vector3.one * 5);

        for (int i = 0; i <= map.tileX; ++i)
        {
            start = new Vector3(i, 0, 0);
            end = new Vector3(i, 0, map.tileZ);

            Handles.DrawLine(start,end);
        }

        Handles.color = Color.blue;
        for (int i = 0; i <= map.tileZ; ++i)
        {
            start = new Vector3(0, 0, i);
            end = new Vector3(map.tileX, 0, i);

            Handles.DrawLine(start, end);
        }
    }

이렇게 작성해버리면

타일 가로 세로에 따라서 그리드가 생김!

 

그리고 이걸 DrawGrid() 함수로 빼자!

이건 해도 되고 안해도 됨!