unity3D:游戲分解之角色移動和相機跟隨


      游戲中,我們經常會有這樣的操作,點擊場景中某個位置,角色自動移動到那個位置,同時角色一直是朝向那個位置移動的,而且相機也會一直跟着角色移動。有些游戲,鼠標滑動屏幕,相機就會圍繞角色旋轉。
看似很簡單的操作,那么到底是怎么實現的呢?
 
我們把上述操作分解為以下幾個步驟
 
角色的移動
1. 移動到下一個路點,線性插值、 曲線插值
2. 角色朝向,一直面朝下一個路點
 
相機跟隨角色
1. 相機俯視角度,決定相機的高度
2. 相機跟隨距離,前向距離或者直線距離(就是三角形的水平邊長或者斜邊長)
3. 相機一直看角色的后背(Y軸旋轉角度和角色一致)
4. 相機圍繞角色旋轉
 
技術點:
1. 向量
2. 旋轉
 
先來看效果,請原諒我未注冊屏幕錄像orz
 
角色移動
  包括位移和方向,就是移動角色的同時角色一直要朝向移動的方向。
 
 
 
左邊的圖,角色從A移動到B,朝向卻一直是向前方的,明顯不符合跑動的顯示邏輯。正確的表現是右圖所展示那樣,角色面朝移動方向。
 
那么我們要怎么做才能實現這個效果呢?位移很簡單,A到B的坐標插值。
 
其次是旋轉角色,Unity提供了一個方法 Quaternion.LookRotation。關於這個方法,官方的解釋如下:

Quaternion.LookRotation 注視旋轉

static function LookRotation (forward : Vector3, upwards : Vector3 = Vector3.up) : Quaternion

Description描述

Creates a rotation that looks along forward with the the head upwards along upwards

創建一個旋轉,沿着forward(z軸)並且頭部沿着upwards(y軸)的約束注視。也就是建立一個旋轉,使z軸朝向view  y軸朝向up。

Logs an error if the forward direction is zero.

如果forward方向是0,記錄一個錯誤。

 

光看描述,是不是比較難理解。網上對這個方法的解釋也挺多的,但是各說紛紜,沒個簡單明了的說法,更容易誤導人。

我們知道向量,包含大小和方向。大小很容易得到,那么方向怎么獲得呢?常規來說,可以通過把向量分解為x、y、z三個分量,然后通過三角函數依次求得個分量的夾角。
Unity提供了更簡單的方法,就是 Quaternion.LookRotation,這個方法就是獲得傳入向量的方向,即旋轉值,是個四元數。
 
代碼實際上很簡單,就幾行。主要是要理解為什么
1             //計算當前位置到下一個坐標點的向量
2             var vector = (posB - posA).normalized;
3             //取得向量的方向
4             var rotation = Quaternion.LookRotation(vector).eulerAngles;
5             //將物體旋轉到指向下一個坐標點的方向
6             transform.rotation = Quaternion.Euler(0, rotation.y, 0);
7             //設置物體的坐標
8             transform.position = posB;
想想為什么Quaternion.Euler(0, rotation.y, 0)這里x和z方向都是填的0?
因為角色的朝向是根據偏轉角Yaw,也就是Y軸決定的,x和z軸是沒有發生偏轉的,倘若改變x軸z軸旋轉值,就會發現角色會有俯仰、翻滾的效果。
 
相機跟隨角色
好了,角色的朝向解決了。那么,如果我要讓相機一直跟着角色走,同時相機一直看到角色的后背,也就是角色旋轉時,相機要跟着轉動,同時保持固定距離,該如何實現?
 
我們先計算相機的位置,然后在旋轉相機朝向角色的后背。
1. 計算相機的旋轉值,這里需要指定相機的俯仰角Pitch的值,假定是30度,可以根據具體情況調節
//相機的俯仰角和偏航角,Y方向偏航和目標對象一致
Quaternion ro = Quaternion.Euler(Pitch, transform.rotation.eulerAngles.y, 0);
2. 計算指定長度Distance的向量,這個向量是與世界坐標z方向平行
var vector = Vector3.forward * Distance;
3. 用上面的相機旋轉值左乘第二步得到的向量,改變這個向量的方向( 四元數左乘向量,改變向量的方向)
vector  = ro * vector;
4. 用目標位置減去vector,得到指向目標位置的坐標點,也就是相機的最終位置。(為什么這樣就得到位置了,回去看看向量的知識吧)
var pos = transform.position - vector; 
5. 最后,將旋轉值和坐標賦值給相機,相機就完成了跟隨效果, 是不是很簡單
CameraGo.transform.position = pos;
CameraGo.transform.rotation = ro;
1 //相機的俯仰角和偏航角,Y方向偏航和目標對象一致
2 Quaternion ro = Quaternion.Euler(Pitch, transform.rotation.eulerAngles.y, 0);
3 //給向量賦予旋轉
4 var distanceVector = ro * Vector3.forward * Distance;
5 var pos = transform.position - distanceVector;
6 CameraGo.transform.position = pos;
7 CameraGo.transform.rotation = ro;
 
至於相機圍繞角色旋轉,我們只需要改變一下Quaternion.Euler(Pitch, transform.rotation.eulerAngles.y, 0) 中transform.rotation.eulerAngles.y這個值
本來這個值是指定相機朝向角色的方向,我們改變這個值,就可以實現相機圍繞角色的效果。我們可以這樣做
//delta就是圍繞角色旋轉的旋轉角度0~360.
Quaternion ro = Quaternion.Euler(Pitch, transform.rotation.eulerAngles.y + delta, 0)
 
最終,上訴代碼如下,代碼不完整,請各位自行補全:
 
 1      //角色移動
 2         void SmoothMove()
 3         {
 4             Vector3[] vector3s = _transDataList;// CurvePath.PathControlPointGenerator(_transDataList);
 5             int sample = _transDataList.Length * SampleRate;
 6  
 7             _movePtg += Time.deltaTime * MoveSpeed;
 8  
 9             //曲線插值
10             transform.position = CurvePath.Interp(vector3s, _movePtg / sample);
11  
12             //計算當前位置到下一個坐標點的向量
13             var vector = (transform.position - _prevPos).normalized;
14             //取得向量的方向
15             var rotation = Quaternion.LookRotation(vector, Vector3.right).eulerAngles;
16             //去處x和z方向的影響,僅作用y方向偏轉
17             rotation.x = 0;
18             rotation.z = 0;
19  
20             //將物體旋轉到指向下一個坐標點的方向
21             transform.rotation = Quaternion.Euler(rotation);
22  
23  
24             _prevPos = transform.position;
25             if (_movePtg >= sample)
26             {
27                 ResetLocalData();
28             }
29         }
30  
31         //相機跟隨
32         void FollowCamera()
33         {
34             if (CameraGo == null) return;
35  
36             if(UseFollow != 0)
37             {
38                 //相機的俯仰角和偏航角,Y方向偏航和目標對象一致
39                 Quaternion ro = Quaternion.Euler(Pitch, transform.rotation.eulerAngles.y + Slider, 0);
40  
41                 //給向量賦予旋轉
42                 var distanceVector = ro * Vector3.forward * Distance;
43                 var pos = transform.position - distanceVector;
44                 CameraGo.transform.position = pos;
45                 CameraGo.transform.rotation = ro;
46                 return;
47             }
48         }

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM