본문 바로가기
Unity 공부

[Unity] Photon, Photon View 이용한 멀티 게임 만들기 (간단 예제)

by 개발하는 디토 2022. 10. 23.

나도 공부 중이지만 일단 정리.

 

설치

Photon 종류 PUN 설정 후 이름 짓고 어플리케이션 작성.

Unity Asset Store - Pun 2 Free 다운로드 프로젝트 Window - Package Manager - My Asssets에서 다운로드 후 Import Window - Setup Networking - Server cloud setting - Add ID 에 Photon 사이트의 어플리케이션 아이디 입력

App ID 입력 필요
입력 완료

 

Import 할 때 위의 창이 자동으로 뜨지만, 안 뜨면 이렇게 찾아가서 입력 가능

 

 

캐릭터 생성

  1. 움직일 캐릭터에 Rigidbody, Capsule Collider, Photon View 추가
  2. Resources 폴더에 캐릭터 넣어 Prefab화 주의) 반드시 이름이 Resources여야 함. 그렇지 않으면 Resources 폴더에 갖다두라는 에러 창이 뜸.
    주의) 캐릭터 Prefab 이름을 다음에 작성할 ConnectManager.cs에서의 “Avatar” 부분 이름과 일치하게 만들어주어야 함.
  3. Empty Game object 생성 후 ConnectManager Script 작성
    • Button 생성 후 OnClick()에 ConnectManager.cs의 ConnectBtn() 함수 연결
    • PhotonNetwork.ConnectUsingSettings(); 이 함수를 실행해야만 비로소 Photon 서버를 사용할 수 있게 된다.

ConnectManager.cs

생성할 캐릭터 Prefab의 이름을 PhotonNetwork.Instantiate()의 이름(”Avatar”)과 일치하게 설정해야 생성됨.

  1. using Photon.Pun; 추가
  2. using Photon.Realtime; 추가
  3. MonoBehaviour → MonoBehaviourPunCallbacks
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;

public class ConnectManager : MonoBehaviourPunCallbacks
{
    public void ConnectBtn()
    {
        PhotonNetwork.ConnectUsingSettings();

    }
    public override void OnConnectedToMaster()
    {
        //base.OnConnectedToMaster();
        PhotonNetwork.JoinOrCreateRoom("Room", new RoomOptions(), TypedLobby.Default); // Enter a room when it already exists, otherwise make a room.
    }

    public override void OnJoinedRoom()
    {
        //base.OnJoinedRoom();
        var pos = new Vector3(Random.Range(-3f, 3f), 0.2f, Random.Range(-3f, 3f));
        PhotonNetwork.Instantiate("Avatar", pos, Quaternion.identity); // set spawn location in PhotonNetwork
    }
}

 

결과

가장 먼저 생성한 캐릭터가 마스터가 된다.

 

동기화

  1. 캐릭터 Prefab에 Animator, Transform 동기화를 위한 View 추가
    • Synchronize Parameter를 Discrete로 설정
  2. 캐릭터 Prefab에 Camera 달아주고 꺼놓기
  3. AvatarMover.cs 작성

AvatarMover.cs

더보기

자신의 캐릭터를 움직이고 그에 따라 애니메이션을 재생하며 해당 캐릭터의 카메라를 켠다.

Vertical 키보드로 움직이고 Horizontal 키보드로 시야 회전하는 코드.

PhototnView.IsMine을 통해 각 유저가 자기 캐릭터인지 확인하고 자기 캐릭터만 움직인다.

 

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;


public class AvatarMover : MonoBehaviourPunCallbacks
{
    public float spd = 200f;
    public float rotSpd = 100f;
    public Animator animCon;
    public Rigidbody rb;
    public PhotonView pv;
    public GameObject cam;

    void Start()
    {
        rb = GetComponent<Rigidbody>();
        animCon = GetComponent<Animator>();
        pv = GetComponent<PhotonView>();
        cam = transform.Find("Camera").gameObject;
        
    }

    void Update()
    {
        if (pv.IsMine) // move only my avatar
        {
            cam.SetActive(true);
            transform.Rotate(0, Input.GetAxis("Horizontal") * rotSpd * Time.deltaTime, 0);
            Move();
        }
    }

    private void Move()
    {
        if(Input.GetAxisRaw("Vertical") != 0)
        {
            float fallspeed = rb.velocity.y;
            Vector3 moveDir = new Vector3(0, 0, Input.GetAxisRaw("Vertical")).normalized;
            Vector3 worldDir = transform.TransformDirection(moveDir) * spd * Time.deltaTime;

            worldDir.y = fallspeed;
            rb.velocity = worldDir;
            animCon.SetBool("isRun", true);
        }
        else
        {
            animCon.SetBool("isRun", false);
        }
    }
}

 

캐릭터 닉네임

3D objects - Text Mesh Pro Text를 활용하면 UI가 아닌 월드 상에 존재하는 텍스트를 만들 수 있다.

 

총알 쏘기

동기화하고자 하는 함수에 [PunRPC]를 적어두고 photonView.RPC(실행할 함수 이름, 동기화 범위, 함수에 필요한 인자)를 통해 함수를 호출하면 함수를 실행한 클라이언트뿐 아니라 다른 클라이언트에게도 함수를 통한 변경사항이 눈에 보이게 된다.

  1. Sphere 총알 오브젝트 만들기
  2. Bullet.cs 작성 후 총알 오브젝트에 연결
  3. 캐릭터 총알 발사할 위치에 빈 오브젝트 FirePos 만들기
  4. AvatarFire.cs 작성 후 캐릭터 오브젝트에 연결
  5. Bullet Prefab, Fire Pos 2가지 Inspector 상에서 연결

Bullet.cs

더보기
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class Bullet : MonoBehaviour
{
    private float speed = 5f;
    private Vector3 direction;

    public void Init(Vector3 dir)
    {
        direction = dir;
    }


    // Update is called once per frame
    void Update()
    {
        transform.Translate(direction * speed * Time.deltaTime);
    }

    private void OnBecameInvisible()
    {
        Destroy(gameObject);
    }
}

 

AvatarFire.cs

더보기

photonView.RPC()의 RpcTarget을 활용해 총알 쏘는 모습이 다른 클라이언트에게도 보이게끔!

using UnityEngine;
using Photon.Pun;

public class AvatarFire : MonoBehaviourPunCallbacks
{
    public Bullet bulletPrefab;
    public GameObject firePos;


    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            Vector3 dir = transform.forward;
            //Fire(dir); // 동기화 하기 전
            photonView.RPC(nameof(Fire), RpcTarget.All, dir); // fire bullets in my computer, but also in others' computers
        }   
    }

    [PunRPC]
    private void Fire(Vector3 dir)
    {
        var bullet = Instantiate(bulletPrefab);
        bullet.Init(dir);
        bullet.transform.position = firePos.transform.position;
    }
}

 

결과

플레이어 1이 쏜 총알이 플레이어 3에게도 보이게 된다.

플레이어 1이 쏘고 있는 총알이 플레이어 333에게도 보인다.

 

심화학습

RPC

동기화의 범위를 결정한다.

RpcTarget 신호 보낼 대상을 의미한다.

  • RpcTarget.All 내 클라이언트, 다른 사람 클라이언트에서 모두 실행
  • RpcTarget.Others 다른 사람 클라이언트에서 실행
  • RpcTarget.AllViaServer 서버에 먼저 정보 보내고 그 다음으로 실행

 

Photon Server 설명

Name Server

→ 각 지역 Master 서버로 보냄.

→ Master서버에서 Room 목록을 볼 수 있고 Room을 생성, Room에 참여할 수 있으나 이 단계에서는 플레이어끼리 상호작용 불가.

→ 게임 서버에서 Room에 Join하면 서로 다른 클라이언트끼리 상호작용 가능함.

 

 

Photon View

  • Network Object: 서로 동기화하는 오브젝트. 각 플레이어.
  • Master: 방에 가장 먼저 들어간 유저, 방을 만든 사람. 방장. 다른 사람을 나가게 하는 등의 권한 가짐. PhotonNetwork.IsMasterPlayer 활용해 Master 유저인지 아닌지 확인 가능.
  • Controller: IsMine의 주체. 누가 이 캐릭터를 조작할 수 있는지.
  • Owner
    • Ownership Transfer
    • Fixed : 권한 양도 불가능. 오브젝트 생성한 사람이 끝까지 소유권 가짐
    • Takeover : script 등으로 권한 양도 가능. 다른 클라이언트가 현재 owner로부터 소유권을 가져갈 수 있음
    • Request : 현재 owner에게 소유권을 요청 후 승인하면 가져감. 거절될 수도 있음.
    • 소유권 요청, 양도 관련 정보
 

소유권(Ownership) 양도 | Photon Engine

doc.photonengine.com

 

  • Creator
    • Creator가 null로 되어 있는 물체는 그것을 만든 사람이 나가도 유지됨.
    • PhotonNetwork.InstantiateRoomObject()으로 물체 생성하면 Master 클라이언트가 Room 들어올 때만 생성됨.
  • Synchronization
    • 기본적으로 네트워크에서 튕기면 오브젝트 사라짐.

댓글