본문 바로가기

Server

Photon Unity Networking PUN 튜토리얼 따라하기 6

원문: doc.photonengine.com/ko-kr/pun/current/demos-and-tutorials/pun-basics-tutorial/player-networking

 

7 - 플레이어 네트워킹 | Photon Engine

Photon Quantum 혁신적인 멀티플레이 게임 개발에 도전! MOBA, 브라울러, RTS, 격투, 스포츠게임을 신속한 예측 네트워크 엔진으로 개발할 수 있습니다.

doc.photonengine.com

 

1. PhotonView 컴포넌트

My Robot Kyle에 photonView 컴포넌트를 삽입한다. 옵션은 건드리지 않아도 Unreliable On Change로 들어가있다. 

2. Transform 동기화

 

캐릭터의 Poisition, Rotation 및 그 외의 데이터를 동기화해야 한다.

 

My Robot Kyle 에 PhotonTransformView 컴포넌트를 추가한다. 그러면 PhotonView에 자동으로 등록된다. (원문과 다른 부분)

Photon Transform View도 클래식과 현재 버젼이 따로 있는 것 같다. 클래식 버젼이 원문의 내용과 일치하는 것으로 보인다. 나는 신규버젼을 그대로 이용한다. 따로 옵션 수정을 하지 않았다.

 

 

3. Animator 동기화

My Robot Kyle 객체에 PhotonAnimatorView를 추가한다.

그러면 또 Photon View에 자동으로 해당 내용이 등록된다.(원문과 다른부분)

Photon Animator View를 일부 수정하여 아래처럼 맞춰준다.

다하고 나면 잊지말고 프리팹 apply를 해주자.

 

 

4. 사용자 입력 관리

 

PlayerAnimatorManager 스크립트를 연다.

 

using Photon.Pun;
using Photon.Realtime;

을 맨 위에 추가해준다.

 

나머지는 원문을 따라해준다. 

 

 

5. 카메라 제어

CameraWork 라는 새로운 C# 스크립트를 생성하고 아래 코드를 작성한다. (원문: doc.photonengine.com/ko-kr/pun/current/demos-and-tutorials/pun-basics-tutorial/player-camera-work)

 

namespace Com.MyCompany.MyGame
{
    /// <summary>
    /// Camera work. Follow a target
    /// </summary>
    public class CameraWork : MonoBehaviour
    {
        #region Private Fields


        [Tooltip("The distance in the local x-z plane to the target")]
        [SerializeField]
        private float distance = 7.0f;


        [Tooltip("The height we want the camera to be above the target")]
        [SerializeField]
        private float height = 3.0f;


        [Tooltip("The Smooth time lag for the height of the camera.")]
        [SerializeField]
        private float heightSmoothLag = 0.3f;


        [Tooltip("Allow the camera to be offseted vertically from the target, for example giving more view of the sceneray and less ground.")]
        [SerializeField]
        private Vector3 centerOffset = Vector3.zero;


        [Tooltip("Set this as false if a component of a prefab being instanciated by Photon Network, and manually call OnStartFollowing() when and if needed.")]
        [SerializeField]
        private bool followOnStart = false;


        // cached transform of the target
        Transform cameraTransform;


        // maintain a flag internally to reconnect if target is lost or camera is switched
        bool isFollowing;


        // Represents the current velocity, this value is modified by SmoothDamp() every time you call it.
        private float heightVelocity;


        // Represents the position we are trying to reach using SmoothDamp()
        private float targetHeight = 100000.0f;


        #endregion


        #region MonoBehaviour CallBacks


        /// <summary>
        /// MonoBehaviour method called on GameObject by Unity during initialization phase
        /// </summary>
        void Start()
        {
            // Start following the target if wanted.
            if (followOnStart)
            {
                OnStartFollowing();
            }


        }


        /// <summary>
        /// MonoBehaviour method called after all Update functions have been called. This is useful to order script execution. For example a follow camera should always be implemented in LateUpdate because it tracks objects that might have moved inside Update.
        /// </summary>
        void LateUpdate()
        {
            // The transform target may not destroy on level load,
            // so we need to cover corner cases where the Main Camera is different everytime we load a new scene, and reconnect when that happens
            if (cameraTransform == null && isFollowing)
            {
                OnStartFollowing();
            }
            // only follow is explicitly declared
            if (isFollowing)
            {
                Apply ();
            }
        }


        #endregion


        #region Public Methods


        /// <summary>
        /// Raises the start following event.
        /// Use this when you don't know at the time of editing what to follow, typically instances managed by the photon network.
        /// </summary>
        public void OnStartFollowing()
        {
            cameraTransform = Camera.main.transform;
            isFollowing = true;
            // we don't smooth anything, we go straight to the right camera shot
            Cut();
        }


        #endregion


        #region Private Methods


        /// <summary>
        /// Follow the target smoothly
        /// </summary>
        void Apply()
        {
            Vector3 targetCenter = transform.position + centerOffset;
            // Calculate the current & target rotation angles
            float originalTargetAngle = transform.eulerAngles.y;
            float currentAngle = cameraTransform.eulerAngles.y;
            // Adjust real target angle when camera is locked
            float targetAngle = originalTargetAngle;
            currentAngle = targetAngle;
            targetHeight = targetCenter.y + height;


            // Damp the height
            float currentHeight = cameraTransform.position.y;
            currentHeight = Mathf.SmoothDamp( currentHeight, targetHeight, ref heightVelocity, heightSmoothLag );
            // Convert the angle into a rotation, by which we then reposition the camera
            Quaternion currentRotation = Quaternion.Euler( 0, currentAngle, 0 );
            // Set the position of the camera on the x-z plane to:
            // distance meters behind the target
            cameraTransform.position = targetCenter;
            cameraTransform.position += currentRotation * Vector3.back * distance;
            // Set the height of the camera
            cameraTransform.position = new Vector3( cameraTransform.position.x, currentHeight, cameraTransform.position.z );
            // Always look at the target
            SetUpRotation(targetCenter);
        }


        /// <summary>
        /// Directly position the camera to a the specified Target and center.
        /// </summary>
        void Cut()
        {
            float oldHeightSmooth = heightSmoothLag;
            heightSmoothLag = 0.001f;
            Apply();
            heightSmoothLag = oldHeightSmooth;
        }


        /// <summary>
        /// Sets up the rotation of the camera to always be behind the target
        /// </summary>
        /// <param name="centerPos">Center position.</param>
        void SetUpRotation( Vector3 centerPos )
        {
            Vector3 cameraPos = cameraTransform.position;
            Vector3 offsetToCenter = centerPos - cameraPos;
            // Generate base rotation only around y-axis
            Quaternion yRotation = Quaternion.LookRotation( new Vector3( offsetToCenter.x, 0, offsetToCenter.z ) );
            Vector3 relativeOffset = Vector3.forward * distance + Vector3.down * height;
            cameraTransform.rotation = yRotation * Quaternion.LookRotation( relativeOffset );
        }


        #endregion
    }
}

그리고 원문을 따라한다. (Camera work 컴포넌트가 이제 두개가 된건가?)

 

 

6. 광선 발사 제어

원문을 따라하자. 

ProcessInputs에 if를 넣는건 위 이미지 처럼 하면 된다. 

 

여기 중요한 개념이 등장하는데, 캐릭터의 위치와 방위는 PhotonTransformView와 PhotonAnimatorView가 처리해주는데, 그 외의 값을 다루는 방법이 소개된다.

 

원문을 따라서 PlayerManager.cs 스크립트를 아래 처럼 변경하자. 

스크립트를 저장하고 나면 PhotonView에 자동으로 등록되어 아래 이미지처럼 나온다.

 

7. 체력 동기화

빔 발포 여부에 체력 수치를 추가해준다.

 

원문을 따라서 진행한다.

 

 

 

 

뭔가 눈으로 보이는것이 없어서 심심한 파트였다. 오늘은 여기까지