王者荣耀实时对战服务器Photon之PUN实现摄像机跟随

发表于2017-11-18
评论0 2.4k浏览

本节将完成Camera摄像机的跟随角色功能,创建CameraWork脚本,来实现以跟随角色的功能,这个脚本可以通用在不同的角色上。

这个部分和Photon pub网络没有什么关系,只是单纯的CameraWork脚本的功能实现和代码讲解。 

Creating the CameraWork Script

1.创建一个名为CameraWork的新C#脚本

2.将CameraWork的内容替换为以下内容:

using UnityEngine;

using System.Collections;

namespace Com.MyCompany.MyGame

    /// <summary>

    /// Camera work. Follow a target

    /// </summary>

    public class CameraWork : MonoBehaviour

    {

        #region Public Properties

        [Tooltip("The distance in the local x-z plane to the target")]

        public float distance = 7.0f;

        [Tooltip("The height we want the camera to be above the target")]

        public float height = 3.0f;

        [Tooltip("The Smooth time lag for the height of the camera.")]

        public 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.")]

        public 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.")]

        public bool followOnStart = false;

        #endregion

        #region Private Properties

        // 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 = 0.0f;

        // Represents the position we are trying to reach using SmoothDamp()

        private float targetHeight = 100000.0f;

        #endregion

        #region MonoBehaviour Messages

        /// <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

    }

3.保存脚本

跟随玩家脚本的关键问题是数学知识,如果你刚刚开始使用3d编程,需要有矢量和四元数学的基本了解和认识。

通常,让我们摄像机始终跟随玩家。当你连接并进入到一个拥有玩家的房间时,其他玩家实例上的每个CameraWork脚本都会争取控制“主镜头”,以便它看起来它的角色...我们不想要,我们只想跟随本机用户对应的本机的角色。

一旦我们明确了一个问题,我们只有一个摄像头,但有几个角色实例,我们可以很容易地找到几种方法来解决。

1.仅将CameraWork脚本附加到本地角色身上上。

2.通过关闭和启动CameraWork行为来控制,具体取决于角色是否为本地角色

3.将CameraWork附加到相机,并注意当场景中有本地角色实例时,仅跟随该实例。

3个选项并不详尽,可以找到更多的方法,但是在这3个选项中,我们将随意选择第二个。

我们已经拥有了一个公共属性followOnStart,如果我们想在非联网环境中使用它,例如在我们的测试场景中,或者在完全不同的场景中,我们可以设置为true

当在我们基于网络的游戏中运行时,当我们检测到Player是本地角色时,我们将调用OnStartFollowing()的公共方法。这将在“角色预制网络”一章中创建和说明的Script PlayerManager中完成。


不管你有关于Photon产品的问题或者是Photon价格问题或者Photon教程方面的问题或者其他问题都可以联系我们给我我们留言,我们真诚的为您服务。关注我们公众号PhotonServer获取等多新鲜资讯。


关注我们公众号PhotonServer 获取最新教程资源。

王者荣耀实时对战服务器Photon之Pun应用系列文章 如果你喜欢请关注我公众号,并推荐给你你的小伙伴,谢谢。

如社区发表内容存在侵权行为,您可以点击这里查看侵权投诉指引