在游戏中为了实现如下的效果:
一些常见的游戏物体,车辆,坐骑等,放置在地形上和在地形上移动时,需要根据地形的坡度来做倾斜,达到一个比较逼真的效果。下面就说一个简单的实现方案,帮助新手解决这个问题。
首先,需要了解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。
Vector3 rotation = Vector3.zero;
rotation.y = unit.rotation.y;
unit.gameObj.transform.rotation = Quaternion.Euler(rotation);
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);
此时物体的倾斜角度就被正确设置了。
一些细节:
1. 物体在Y轴上转向的时候,可以渐进的改变角度,使得转向不是那么生硬。
2. 地形的法线可以不用实时获取,可以使用网格,将地图分割为很多单元,每个单元设置一个法线,减少倾斜改变的频率。
本来打算放一个gif动画文件的,结果发现csdn不支持……