這部分將會知道你創(chuàng)建CameraWork腳本,再你玩游戲的時(shí)候讓相機(jī)跟隨你的角色。這個(gè)腳本和網(wǎng)絡(luò)沒什么關(guān)系,所以簡短介紹。
主要內(nèi)容
- 創(chuàng)建CameraWork腳本
創(chuàng)建CameraWork腳本
新建一個(gè)C#腳本,命名為CameraWork
-
把CameraWork的內(nèi)容替換成下面的代碼
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 } }
保存腳本
如果你剛剛開始與實(shí)時(shí)3d,向量和四元數(shù)學(xué),那么跟隨玩家角色的數(shù)學(xué)是復(fù)雜的。所以我嘗試在本教程中解釋這一點(diǎn)。但是如果你好奇,想學(xué)習(xí),不要猶豫與我們聯(lián)系,我們會盡最大努力解釋清楚。
然而,這個(gè)腳本不僅僅是瘋狂的數(shù)學(xué),設(shè)置也是重要的,以及控制何時(shí)應(yīng)該主動跟隨玩家的能力。理解這點(diǎn)很重要:我們?yōu)槭裁匆刂剖裁磿r(shí)候跟隨玩家。
通常,讓我們想象如果總是跟隨玩家會發(fā)生什么。當(dāng)你連接到一個(gè)充滿玩家的房間,其他玩家的每個(gè)CameraWork腳本為了一直看著自己的角色會相互打架...我們不想要這種,我們只想跟隨本地玩家角色,它代表的是計(jì)算機(jī)后面的用戶。
一旦我們定義了這個(gè)問題,我們只有一個(gè)攝像機(jī),但有多個(gè)Player實(shí)例,我們可以很容易找到幾種方法。
- 僅在本地玩家上附加CameraWork腳本。
- 通過關(guān)閉和打開來控制CameraWork行為,具體取決于要關(guān)注的Player是否是本地玩家。
- 讓CameraWork連接到相機(jī),并注意當(dāng)場景中有一個(gè)本地玩家實(shí)例時(shí)只跟隨那個(gè)。
這3個(gè)選項(xiàng)并不詳盡,可以找到更多的方法,但在這3個(gè)選項(xiàng)中,我們將任意選擇第二個(gè)。上面的選項(xiàng)沒有更好或更壞,但是這是一個(gè)可能需要最少的編碼和最靈活的...“有趣...”我聽到你說:)
我們暴露了一個(gè)公共屬性followOnStart,如果我們想在非聯(lián)網(wǎng)環(huán)境中使用它,我們可以設(shè)置為true,例如在我們的測試場景中,或者在完全不同的場景
當(dāng)在我們的網(wǎng)絡(luò)游戲中運(yùn)行時(shí),當(dāng)我們檢測到Player是本地玩家時(shí),我們將調(diào)用公共方法OnStartFollowing()。這將在PlayerManager腳本中完成,該腳本PlayerManager在“Player Prefab Networking”一章中創(chuàng)建和解釋。
原文
http://doc.photonengine.com/en-us/pun/current/tutorials/pun-basics-tutorial/player-camera-work