学习Unity 一段时间了,很多游戏中都有 炮台的实例。那么怎样才能制作一个合格的炮台呢?以下就是我的制作方式,供大家学习。
项目中使用的是 VRSimple 中的 炮台模型。
模型的父子级关系如下图所示:
那么何为合格的炮台呢?在我看来,炮台 rotator 和 chassis 的旋转相互不影响。rotator 只在 rotator.transform.up 为法线向量的平面 上旋转,而 chassis 的旋转只存在于 chassis.transform.right 为法线向量的平面 上旋转。
下面放上代码:
public class MazeTurret : MonoBehaviour
{
private Quaternion ChassisRot, rotatorRot; //默认旋转
public Transform chassis, rotator; //获取 chassis 和 rotator 的组件
public Transform target; //需要 跟随的目标
public float rotSpeed = 10; //旋转速度
public float minRot = -89f, MaxRot = 10f; //最小旋转角,最大旋转角。(向上旋转为负)
// Update is called once per frame
void Update()
{
Vector3 tarDir = target.position - rotator.position; //获取 rotator 到 target 的方向向量 tarDir。
Vector3 rotatorDir = Vector3.ProjectOnPlane(tarDir, transform.up); //获取 tarDir 到 rotator 所在平面的 投影向量 rotatorDir。
Vector3 tempDir = transform.InverseTransformVector(rotatorDir); //将 rotatorDir 转换到炮台 自己的空间坐标中
Quaternion tempRQ = Quaternion.LookRotation(tempDir); //计算 rotator 应该转向的方向四元数
rotator.localRotation = Quaternion.Lerp(rotator.localRotation, tempRQ, Time.deltaTime * rotSpeed); //插值旋转 rotator 。
Vector3 chassisDir = target.position - chassis.position; //获取 chassis 到 target 的方向向量。
float angle = Vector3.Angle(chassisDir, rotatorDir); //利用 这个向量,计算出 该向量 与 rotatorDir 的夹角 angle 这样计算的 angle 为正数。
if (chassis.parent.InverseTransformPoint(target.position).y > 0) //判断 target 与 chassis 的空间相对位置。
{ //如果 y>0 则表示 target 在 chassis 的上方 则此时 angle 应该为负值。
angle *= -1;
angle = Mathf.Clamp(angle, minRot, MaxRot); //旋转 限值。
}
Quaternion tempCQ = Quaternion.Euler(angle, 0, 0); //计算 chassis应该转向的方向四元数
chassis.localRotation = Quaternion.Lerp(chassis.localRotation, tempCQ, Time.deltaTime * rotSpeed); //插值旋转 chassis
}
}
炮台的 Inspecter 面板上的信息如下:
按照上边拖上去之后,再拖进去 target 就行了。点击运行,在game模式下看下效果吧。
这时候如果旋转炮台的方向呢?
一切按照预想的运行着。目标完成!!
但是这种方式还有些不足,讲道理,炮台的旋转不应该用插值的方式进行,而是应该按照角度进行旋转。举个栗子:应该按照 Quaternion.Euler(angle, 0, 0),改变angle的旋转值而旋转,差多少度就该旋转多少度。而Lerp插值是按照比例进行的,如果目标角度大小不同,那么在同一帧内,炮台旋转的角度就会不同。所以优化空间还是有的。
本人原创,虽然小例,但如果文章有所引用,请标明出处。