在遊戲中為了實作如下的效果:

一些常見的遊戲物體,車輛,坐騎等,放置在地形上和在地形上移動時,需要根據地形的坡度來做傾斜,達到一個比較逼真的效果。下面就說一個簡單的實作方案,幫助新手解決這個問題。
首先,需要了解u3d中地形的一些屬性:
Terrain 這個類,表示了u3d中的地形,其中我們需要知道的它的屬性有:
成員:terrainData -- 包含了各種地形資料
方法:SampleHeight -- 擷取指定位置地形的高度
其中terrainData是TerrainData類的一個對象,它下面需要知道的屬性有:
成員:size -- 地形在世界坐标系中的尺寸
方法:GetInterpolatedNormal -- 擷取地形指定位置上的插值法線
由于GetInterpolatedNormal函數的參數x,y的範圍是0到1,是以需要把世界坐标做相應轉換;如果地形是在0,0,0坐标處向x,z方向延伸,如下圖:
那麼可以封裝一個簡單的方法:
public Vector3 GetNormal(float x, float z)
{
return terrain.terrainData.GetInterpolatedNormal(x / terrain.terrainData.size.x,
terrain.terrainData.size.z);
}
擷取到法線就相當于知道了目前位置的地形是怎麼傾斜的了,就可以根據這個資訊來調節物體的旋轉角度,達到比對上地形的目的;下面就來進行對物體的旋轉變換。
1. 修改gameObject的構造
由于像車輛這種類型的物體在地形上移動的時候,在x,y,z三個軸上面都需要旋轉,為了讓他們的旋轉互相不幹擾,是以需要使用兩個節點(transform)來實作,類似于第三人稱錄影機控制主角的技巧。是以在gameObject之外,再包一個gameObject,如下所示:
outUnit.gameObj = new GameObject(unit.gameObj.name + "_out");
unit.gameObj.transform.parent = unitItem.gameObj.transform;
unit.gameObj.transform.position = Vector3.zero;
unit.gameObj.transform.rotation = Quaternion.identity;
outUnit.gameObj.transform.position = unit.position;
這樣,物體就有了外層和内層兩個gameObject:outUnit.gameObj是外層gameObject,而unit.gameObj是内層gameObject。
2. 改變物體Y方向上的旋轉
在改變物體傾斜角度時,先改變他的朝向,也就是俯視地圖的視角下,車輛行駛時車頭應該朝向的方向。
Vector3 rotation = Vector3.zero;
rotation.y = unit.rotation.y;
unit.gameObj.transform.rotation = Quaternion.Euler(rotation);
保持x軸和z軸上沒有任何偏轉,在y軸上設定朝向,并且把這個朝向設定到内層gameObject上。
3. 改變地形上的傾斜角度
Vector3 normal = GetNormal(unit.position.x, unit.position.z);
Vector3 rotaion = Vector3.zero;
rotation.x = Mathf.Rad2Deg * Mathf.Atan2(normal.z, normal.y);
rotation.z = 360 - Mathf.Rad2Deg * Mathf.Atan2(normal.x, normal.y);
outUnit.gameObj.transform.localRotation = Quaternion.Euler(rotation);
保持y軸上沒有任何偏轉,在x軸上和z軸上設定旋轉角度,并且把這個朝向設定到外層gameObject上。
此時物體的傾斜角度就被正确設定了。
一些細節:
1. 物體在Y軸上轉向的時候,可以漸進的改變角度,使得轉向不是那麼生硬。
2. 地形的法線可以不用實時擷取,可以使用網格,将地圖分割為很多單元,每個單元設定一個法線,減少傾斜改變的頻率。
本來打算放一個gif動畫檔案的,結果發現csdn不支援……