Unity 3D 簡易制作攝像機圍繞物體隨鼠標旋轉效果
梗概:
一. 攝像機圍繞目標物體旋轉, 即攝像機離目標物體有一定的距離且旋轉軸心為該物體的位置.
二. 當目標物體被障礙物擋住后, 需要將攝像機移動到障礙物前方能看見目標物體的位置.
思路:
一. 攝像機繞軸心旋轉, 可以在軸心處創建一個空物體, 將攝像機設為該軸心的子物體. 如圖: 







這樣便可以簡單地實現攝像機旋轉軸心 (注意: 旋轉時應旋轉軸心而不是單獨旋轉攝像機) . 還應注意, 如果攝像機的目標物體可以移動的話, 就應每幀將軸心的坐標設為目標物體的坐標 (盡量不要直接將軸心設為目標物體的子物體! 除非有特別需要) .
二. 當目標物體被障礙物擋住后, 可以在目標物體處發射一條射線, 射線原點就是目標物體的坐標 (也就是軸心) , 射線方向就是從原點到攝像機的方向. 此時射線的碰撞點就是將要把攝像機調整到的位置. 



三. 當將攝像機移動到后方沒有障礙物的位置時, 就應將攝像機移回至原距離. 

過程:
-
創建任意目標物體;
-
創建一個空物體並命名, 這個空物體就是軸心, 並將其 Tag 設為 "3rdCameraAxle":


或者將其 Tag 設為你喜歡的一個都可以;
-
創建攝像機, 將其 Tag 設為 "MainCamera", 並設為剛創建的軸心的子物體;
-
創建任意障礙物.
代碼:
一. 此時繞物體旋轉攝像機便可簡化為直接旋轉軸心, 代碼也簡化了許多:
-
定義鼠標靈敏度:
public float mouseSensitivity = 2;
-
定義目標物體的 Transform :
public Transform targetTrans;
-
定義軸心 Transform 與軸心旋轉角度:
Transform thirdPCamAxle; Vector3 thirdPCamEuler;在 void Start() 下對其賦值:
void Start () { thirdPCamAxle = GameObject.FindGameObjectWithTag("3rdCameraAxle").transform; //括號里的引號中也可以寫上你自己對軸心設的 Tag. thirdPCamEuler = thirdPCamAxle.localEulerAngles; //推薦寫 localEulerAngles, 要不之后處理起來會比較麻煩. }
-
定義攝像機:
Camera thirdPCam;
在 void Start() 下對其賦值:
void Start () { thirdPCam = Camera.main; }
-
定義並賦值攝像機離物體的最大距離, 攝像機離物體的當前距離:
float camForwardMaxDistance = 9; float camForwardDistance; float camBackDistance;
-
在 void Update() 下寫:
thirdPCamAxle.position = targetTrans.position; //將攝像機旋轉軸心位置設為目標物體位置 //定義旋轉量 float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity; float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity; thirdPCamEuler.y += mouseX; //控制攝像機左右旋轉 //控制攝像機上下旋轉, 並且上下旋轉范圍不能超過90°或-90°, 此方法適用於 localEulerAngles. if (thirdPCamEuler.z < 90 && mouseY > 0) { thirdPCamEuler.z += mouseY; } if (thirdPCamEuler.z > -90 && mouseY < 0) { thirdPCamEuler.z += mouseY; } thirdPCamAxle.localEulerAngles = thirdPCamEuler; //將旋轉量應用到攝像機上.
至此, 控制攝像機旋轉完成. 此部分代碼如下:
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 5 public class ThirdPCamC : MonoBehaviour { 6 public float mouseSensitivity = 2; 7 public Transform targetTrans; 8 9 Transform thirdPCamAxle; 10 Vector3 thirdPCamEuler; 11 12 Camera thirdPCam; 13 float camForwardMaxDistance = 9; 14 float camForwardDistance; 15 float camBackDistance; 16 17 void Start () { 18 thirdPCamAxle = GameObject.FindGameObjectWithTag("3rdCameraAxle").transform; 19 thirdPCamEuler = thirdPCamAxle.localEulerAngles; 20 21 thirdPCam = Camera.main; 22 } 23 24 void Update () { 25 thirdPCamAxle.position = targetTrans.position; 26 27 float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity; 28 float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity; 29 thirdPCamEuler.y += mouseX; 30 if (thirdPCamEuler.z < 90 && mouseY > 0) { thirdPCamEuler.z += mouseY; } 31 if (thirdPCamEuler.z > -90 && mouseY < 0) { thirdPCamEuler.z += mouseY; } 32 thirdPCamAxle.localEulerAngles = thirdPCamEuler; 33 } 34 }
二. 攝像機避開障礙物, 並在后方沒有障礙物時移回原距離 (原距離可通過設置對 camForwardMaxDistance 的賦值來改變):
在 void Update() 下寫:
Ray camForwardRay = new Ray(thirdPCam.transform.position, thirdPCam.transform.forward); //在攝像機處發射一條向前的射線, 用來檢測攝像機當前離目標的距離 (此處不必擔心射線碰撞處是障礙物的情況). RaycastHit forwardRayHit; //定義射線碰撞. if (Physics.Raycast(camForwardRay, out forwardRayHit)) //當射線有碰撞物時 (也就是目標物體), { camForwardDistance = Vector3.Distance(thirdPCam.transform.position, forwardRayHit.point); //計算從攝像機到碰撞點的距離 (碰撞點也可以改為目標物體的位置). } Vector3 dir = thirdPCam.transform.position - targetTrans.position; //定義從目標物體到攝像機的方向. dir = dir.normalized; //將方向單位化. Ray ray = new Ray(targetTrans.position, dir); //在目標物體處發射一條射線, 方向即為剛剛定義的向量. RaycastHit hit; //定義射線碰撞. if (Physics.Raycast(ray, out hit)) //當該射線有碰撞, 即目標物體被障礙物擋住時, { thirdPCam.transform.position = hit.point; //將攝像機位置設為碰撞點位置. } else //如果沒有碰撞, 即目標物體沒有被障礙物擋住, { if (camForwardDistance < camForwardMaxDistance) //並且當前距離沒有超過最大距離時, { thirdPCam.transform.Translate(Vector3.back * Time.deltaTime * 5); //將攝像機緩慢后移至最大距離. } }
全部代碼如下:
1 using System.Collections; 2 using System.Collections.Generic; 3 using UnityEngine; 4 5 public class ThirdPCamC : MonoBehaviour { 6 public float mouseSensitivity = 2; 7 public Transform targetTrans; 8 9 Transform thirdPCamAxle; 10 Vector3 thirdPCamEuler; 11 12 Camera thirdPCam; 13 float camForwardMaxDistance = 9; 14 float camForwardDistance; 15 float camBackDistance; 16 17 void Start () { 18 thirdPCamAxle = GameObject.FindGameObjectWithTag("3rdCameraAxle").transform; 19 thirdPCamEuler = thirdPCamAxle.localEulerAngles; 20 21 thirdPCam = Camera.main; 22 } 23 24 void Update () { 25 thirdPCamAxle.position = targetTrans.position; 26 27 float mouseX = Input.GetAxis("Mouse X") * mouseSensitivity; 28 float mouseY = Input.GetAxis("Mouse Y") * mouseSensitivity; 29 thirdPCamEuler.y += mouseX; 30 if (thirdPCamEuler.z < 90 && mouseY > 0) { thirdPCamEuler.z += mouseY; } 31 if (thirdPCamEuler.z > -90 && mouseY < 0) { thirdPCamEuler.z += mouseY; } 32 thirdPCamAxle.localEulerAngles = thirdPCamEuler; 33 34 Ray camForwardRay = new Ray(thirdPCam.transform.position, thirdPCam.transform.forward); 35 RaycastHit forwardRayHit; 36 if (Physics.Raycast(camForwardRay, out forwardRayHit)) 37 { 38 camForwardDistance = Vector3.Distance(thirdPCam.transform.position, forwardRayHit.point); 39 } 40 41 Vector3 dir = thirdPCam.transform.position - targetTrans.position;; 42 dir = dir.normalized; 43 Ray ray = new Ray(targetTrans.position, dir); 44 RaycastHit hit; 45 if (Physics.Raycast(ray, out hit)) 46 { 47 Debug.DrawLine(ray.origin, hit.point, Color.green); 48 thirdPCam.transform.position = hit.point; 49 } 50 else 51 { 52 if (camForwardDistance < camForwardMaxDistance) 53 { 54 thirdPCam.transform.Translate(Vector3.back * Time.deltaTime * 5); 55 } 56 } 57 } 58 }
最終效果圖:


希望本篇教程能夠幫到大家!
源碼: [GitHub](https://github.com/JadMax/Unity3D-Miscellaneous/blob/master/ThirdpersonCameraController.cs)
