본문 바로가기
유니티 최고/유니티 구현

유니티(Unity) Photon을 이용한 멀티 플레이 구현하기 (간단)

by Lee_story_.. 2023. 2. 3.
728x90

방학동안 진행 하던 프로젝트에서 네트워크 부분을 구현하다

포톤이 생각보다 간단하게 이루어 진다는 걸 알게 되어 글을 쓰게 되었습니다!

 

 

 

이번에 참고한 블로그!

 

[Unity] 포톤 멀티 숨바꼭질 만들기 01

포톤2를 사용하여 여러 사용자가 맵에 접속할 수 있도록 한다.

velog.io

 

 

먼저

포톤 사이트에 접속해줍시다. 

 

Multiplayer Game Development Made Easy | Photon Engine

 

www.photonengine.com

 

포톤자체에서 서버를 빌려쓰는 방식이라 

로그인을 해주고 서버 id를 받아 와야합니다.

 

로그인을 했다면  

위와 같은 창이 나오는데 우측상단에서 새로운 앱을 만들어 줍시다. 

 

 

그 다음 포톤을 다운 받아 줍시다.

 

 

에셋 스토어에서 pun 2 무료버전을 사용해 보겠습니다.

다운받아 현재 프로젝트에 임포트 해줍시다. 그러면 사이트에서 생성한 id를 입력할수있는 팝업창이 나올텐데 

파란색으로 표시된 부분을 눌러 전체 복사 붙여넣기 해주시면 됩니다!

 

만약 팝업창을 닫아버렸다면 

 

 Window -> Photon Unity Networking -> Highlight server settings 을 눌러 줍시다. 

그러면 아래와 같은 에셋이 나오는데 여기다가 id를 선택해주시면 됩니다.

 

 

여기까지가 기초 끝!

 

 

이제 부터는 작동이 되는지를 확인해 보겠습니다. 

 

먼저 커다란 바닥과 네트워크 메니저(빈 오브젝트) 를 만들어 주었습니다.

 

다음은 서버에서 작동할 에셋들을 Resources 파일에 생성해 줍시다.  (폴더 이름 중요!)

 

 

이제 스크립트를 작성해줍시다.

 

NetworkManager.cs

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

public class NetworkManager : MonoBehaviourPunCallbacks
{
    public Text StatusText;
    public InputField NickNameInput;
    public GameObject Cube;
    public string gameVersion = "1.0";


    void Awake()
    {
        PhotonNetwork.AutomaticallySyncScene = true;
    }

    void Start()
    {
        PhotonNetwork.GameVersion = this.gameVersion;
        PhotonNetwork.ConnectUsingSettings();
    }

    void Connect() => PhotonNetwork.ConnectUsingSettings();

    public override void OnConnectedToMaster()
    {
        PhotonNetwork.JoinRandomRoom();
    }

    public override void OnJoinedRoom() // 방에 들어 가면? 
    {
        PhotonNetwork.Instantiate("Cube", Cube.transform.position, Quaternion.identity);
        // 큐브 생성!
    }

    public override void OnJoinRandomFailed(short returnCode, string message) // 방이 없다면 
    { 
        this.CreateRoom(); // 방을 만들어 주고
    }

    void CreateRoom()
    {
        PhotonNetwork.CreateRoom(null, new RoomOptions { MaxPlayers = 4 });
    }
}

게임이 시작될때 방을 만들어 접속하게끔 만들어 주었고 

 

 

 

TestPlayer.cs

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

public class TestPlayer : MonoBehaviourPunCallbacks
{
    public PhotonView PV;
    public Rigidbody rb;
    private Transform tr;

    public Transform spa;
    bool check = true;

    public float m_moveSpeed = 1;
    public float m_turnSpeed = 200;

    private float m_currentV = 0; 
    private float m_currentH = 0; 
    private readonly float m_interpolation = 10;
    private readonly float m_backwardRunScale = 0.66f;


    private void Start()
    {
        rb = GetComponent<Rigidbody>();
        rb.centerOfMass = new Vector3(0, -1.5f, 0);
        tr = GetComponent<Transform>();

        if (PV.IsMine)
            Camera.main.GetComponent<SmoothFollow>().target = tr.Find("camera_loc").transform;

    }


    void Update()
    {

        if (!PV.IsMine && PhotonNetwork.IsConnected)
            return;

        float v = Input.GetAxis("Vertical"); 
        float h = Input.GetAxis("Horizontal"); 

       
        if (Input.GetMouseButton(0)) 
        {
            //float y_rot = Input.GetAxisRaw("Mouse X");
            //transform.Rotate(0, y_rot * m_turnSpeed * Time.deltaTime, 0); 
            
            if (check)
            {
                GameObject temp;

                check = false;
                temp=PhotonNetwork.Instantiate("Sphere", spa.position, Quaternion.identity);

                
                StartCoroutine("SphereSp");
            }
        }
        if (v < 0)
        { 
            v *= m_backwardRunScale;
        }

        m_currentV = Mathf.Lerp(m_currentV, v, Time.deltaTime * m_interpolation); 
        m_currentH = Mathf.Lerp(m_currentH, h, Time.deltaTime * m_interpolation); 

        tr.Translate(Vector3.forward * v * m_moveSpeed * Time.deltaTime);
        tr.Rotate(Vector3.up * h * m_turnSpeed * Time.deltaTime);
        //m_animator.SetFloat("Speed", m_currentV); 
    }


    IEnumerator SphereSp()
    {

        yield return new WaitForSecondsRealtime(2.0f);
        check = true;
        

    }


}

플레이어 스크립은 앞,뒤 회전을 만들어 주고, 클릭시에는 공을 소환하게 해주었습니다.

 

 

 

큐브에는 카메라가 바라볼 방향과 공을 소환할 위치를 찍어주고 

 

이번엔 카메라 

에셋 스토어에 있었던 Standard Assets을 사용할껀데... 없어졌네요..

 

SmoothFollow.cs

using UnityEngine;

#pragma warning disable 649
namespace UnityStandardAssets.Utility
{
	public class SmoothFollow : MonoBehaviour
	{

		// The target we are following
		
		public Transform target;
		// The distance in the x-z plane to the target
		[SerializeField]
		private float distance = 10.0f;
		// the height we want the camera to be above the target
		[SerializeField]
		private float height = 5.0f;

		[SerializeField]
		private float rotationDamping;
		[SerializeField]
		private float heightDamping;

		// Use this for initialization
		void Start() { }

		// Update is called once per frame
		void LateUpdate()
		{
			// Early out if we don't have a target
			if (!target)
				return;

			// Calculate the current rotation angles
			var wantedRotationAngle = target.eulerAngles.y;
			var wantedHeight = target.position.y + height;

			var currentRotationAngle = transform.eulerAngles.y;
			var currentHeight = transform.position.y;

			// Damp the rotation around the y-axis
			currentRotationAngle = Mathf.LerpAngle(currentRotationAngle, wantedRotationAngle, rotationDamping * Time.deltaTime);

			// Damp the height
			currentHeight = Mathf.Lerp(currentHeight, wantedHeight, heightDamping * Time.deltaTime);

			// Convert the angle into a rotation
			var currentRotation = Quaternion.Euler(0, currentRotationAngle, 0);

			// Set the position of the camera on the x-z plane to:
			// distance meters behind the target
			transform.position = target.position;
			transform.position -= currentRotation * Vector3.forward * distance;

			// Set the height of the camera
			transform.position = new Vector3(transform.position.x ,currentHeight , transform.position.z);

			// Always look at the target
			transform.LookAt(target);
		}
	}
}

만들어서 카메라에 넣어줍시다. 

 

이제 나머지도  네트워크 메니저와 플레이어가 될 큐브에 스크립을 넣어주고 

 

여기서 시작하면? 서로 연결이 안됩니다...

 

서버에서 작동시켜줄 에셋들에  photon view 스크립을 추가 해야 보입니다....

 

위치와 회전값만 전달하겠습니다!

 

이상태로 빌드 하면 끝!

 

 

연결은  잘 됩니다!

 

 

 

 

틀린점이 있다면 댓 달아주세요!

 

댓글