1. 程式人生 > >unity3D:遊戲分解之角色移動和相機跟隨

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

ini img form static 錄像 void 方法 lda okr

遊戲中,我們經常會有這樣的操作,點擊場景中某個位置,角色自動移動到那個位置,同時角色一直是朝向那個位置移動的,而且相機也會一直跟著角色移動。有些遊戲,鼠標滑動屏幕,相機就會圍繞角色旋轉。 看似很簡單的操作,那麽到底是怎麽實現的呢? 我們把上述操作分解為以下幾個步驟 角色的移動 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         }

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