其实不需要什么空物体了,war3式的平移效果其实是高度不变平行地面的一个平面上四处移动的问题了,光translate摄像机是不行的 
 
贴上我完整的代码吧
 
复制代码

//rts方式镜头移动 旋转 缩放控制 javascript        


         var ZoomSpeed = 30;//镜头缩放速率        


         var MovingSpeed = 1;//镜头移动速率        


         var RotateSpeed = 1;  //镜头旋转速率        


         private var distance = 0.0f;//保存镜头和中心点的直线距离        


                  


         function Start () {        


                  //先用镜头斜视的角度和离地面的高度算出距离视野中心的直线距离        


                  //要省事也可以直接指定一个距离 这个不重要        


                  //镜头的高度可以减去一个修正值 这样就是正视地图上方的效果 看需要        


                  distance = Mathf.Abs(transform.position.y/Mathf.Sin(transform.eulerAngles.x));        


         }        


                  


         function LateUpdate () {        


                  var rotation;        


                  var position;        


                  


                  //按住鼠标左键移动鼠标拖动镜头,改成键盘输入或者鼠标靠近屏幕边缘输入都是可以的           


                  if(Input.GetMouseButton(0))        


                  {        


                  var delta_x = Input.GetAxis("Mouse X") * MovingSpeed;        


                  var delta_y = Input.GetAxis("Mouse Y") * MovingSpeed;        


                  


                  //镜头其实就是在平行地面的水平面上四处移动 所以构造一个变换矩阵 与世界坐标唯一的差异就是y轴旋转的角度        


                  rotation = Quaternion.Euler(0, transform.rotation.eulerAngles.y,0 );        


                  //把镜头要移动的分量乘以这个变化矩阵就是相对世界坐标的移动量啦 再加上镜头当前坐标 就是镜头新位置啦        


                  transform.position =rotation * Vector3(-delta_x,0,-delta_y)+transform.position;        


                  }        


                  


                  //用滚轮控制镜头拉伸和推进        


                  if(Input.GetAxis("Mouse ScrollWheel")){           


                  var delta_z = -Input.GetAxis("Mouse ScrollWheel") * ZoomSpeed;        


                  //直接用镜头的translate函数在镜头参考系Z方向上运动就可以啦        


                  transform.Translate(0,0,-delta_z);        


                  //再用delta_z修正镜头与视野中心点的距离 其实不记录也是可以的 每次都用sin算比较麻烦        


                  distance += delta_z;        


                  }        


                  


                  //按住鼠标右键移动鼠标旋转镜头        


                  if (Input.GetMouseButton(1)) {        


                  var delta_rotation_x = Input.GetAxis("Mouse X") * RotateSpeed;        


                  var delta_rotation_y = -Input.GetAxis("Mouse Y") * RotateSpeed;        


                  


                  //旋转是以镜头当前视野中心点为原点进行的 在一个平行于地面的水平面上旋转        


                  


                  //先算出当前视野中心的坐标,中心的概念就是正对 上下左右都对齐,离开一个distance距离        


                  //所以中心点相对镜头参照系的坐标就是0,0,distance,乘以镜头的变换,在加上镜头的世界坐标 就是中心点的世界坐标了        


                  position =transform.rotation* Vector3(0,0,distance)+transform.position;        


                  


                  //Y轴方向上用世界坐标的变换就可以拉 否则镜头会歪的               


                  transform.Rotate(0,delta_rotation_x,0,Space.World);        


                  //x轴方向的旋转是相对自身的 否则镜头也会歪        


                  transform.Rotate(delta_rotation_y,0,0);        


                  //转完以后 把这个新的旋转角度 乘以一个“正对中心”的相对坐标 再加上中心点的坐标 就是新的镜头世界坐标啦        


                  transform.position =transform.rotation* Vector3(0,0,-distance)+position;        


                  }        


         }





 


另存为一个什么xxxx.js 拖给你的摄像机,随便搞个地形走走看吧


如果速度太快/太慢 就调整3个参数吧


 


除去鸡婆的注释和输入 if什么的,全部平移 旋转 缩放 也就是8行代码 基本没有用神马内建的转换功能(用了一次translate),也没有搞什么空物体指引方向、投射x/y/z一堆sin cos什么的。那都不太符合3d编程的基本精神,只用了转换矩阵 坐标变换来搞定全部控制了


 


要注意的是:


旋转其实有两种意思 一种是以摄像机为中心的旋转,那种效果很简单了 就是摄像机在世界的y方向上转一个角度就行了。但是那种旋转不符合rts游戏的要求,举个例子我建了个铁匠铺,挡住了我的小兵,我想转一个角度去点小兵,如果是以摄像机为中心转,那铁匠铺就转出视野了。所以应该是以视野中心转比较符合,虽然这样实现起来麻烦一些。


 


在摄像机的参照系里,屏幕上的东西永远是前方 是z方向上加,摄像机的最中心就是正对位置,在这个位置上中心和摄像机的坐标偏移永远是0,0,镜头距离,有这个前提就能做出各种变化的效果来


 


以摄像机为参照点计算中心,那就是加上镜头距离(摄像机z轴的前方),以中心为参照点计算摄像机应该的位置,就是减去镜头距离,所以这个distance一会加一会减的 想明白了就很好理解了。


 


把中心点的position换成一个目标的position那就是跟随目标进行这3种变换,效果都是一样的,会自动跟随。


紧跟目标屁股后面 那变换方法就是:


Quaternion.Euler(0,target.rotation.eulerAngles.y,0)*(0,0,与目标的距离)+目标当前位置

想要斜后方紧跟,那就是目标的

Quaternion.Euler(斜视角度,target.rotation.eulerAngles.y,0)*(0,0,与目标的距离)+目标当前位置,

距离为0那就是

Quaternion.Euler(0,target.rotation.eulerAngles.y,0)*(0,0,0)=0 + 目标当前位置,fps第一人称视角啦。

目标的x z旋转都不用理会的 他摔倒镜头也不用水平转吧。。他往前倾我们也不用跟着他看地板(fps需要这样。。所以很晕)


有变换,神马都是一样的原理。


再贴一个自己写的适合RPG用的镜头跟随脚本,C#的 
 
复制代码


using UnityEngine;        


         using System.Collections;        


                  


         public class MouseFollow_ForRPG_CSharp : MonoBehaviour {        


                  


                  public GameObject target;        


                  public float ZoomSpeed = 30;//镜头缩放速率        


                  public float MovingSpeed = 1;//镜头移动速率        


                  public float RotateSpeed = 1;  //镜头旋转速率        


                  public float distance = 20;//设置距离角色的距离        


                  public float ViewAngle = 30;//设置镜头斜视的角度        


                  


                  void Start () {        


                  if(target){        


                  transform.rotation = Quaternion.Euler(ViewAngle, target.transform.rotation.eulerAngles.y,0 );        


                  transform.position = transform.rotation * new Vector3(0,0,-distance)+target.transform.position;           


                  }        


                  }        


                  


                  void Update () {        


                  Quaternion rotation;        


                  Vector3 position;        


                  float delta_x,delta_y;        


                  float delta_rotation_x,delta_rotation_y;        


                  


                  if(target){        


                  if(Input.GetMouseButton(0))        


                  {        


                  delta_x = Input.GetAxis("Mouse X") * MovingSpeed;        


                  delta_y = Input.GetAxis("Mouse Y") * MovingSpeed;        


                  rotation = Quaternion.Euler(0, transform.rotation.eulerAngles.y,0 );        


                  transform.position = rotation * new Vector3(-delta_x,0,-delta_y)+ transform.position;        


                  }        


                  else{        


                  if(Input.GetAxis("Mouse ScrollWheel")!= 0){           


                  distance += -Input.GetAxis("Mouse ScrollWheel") * ZoomSpeed;        


                  }        


                  if (Input.GetMouseButton(1)) {        


                  delta_rotation_x = Input.GetAxis("Mouse X") * RotateSpeed;        


                  delta_rotation_y = -Input.GetAxis("Mouse Y") * RotateSpeed;        


                  transform.Rotate(0,delta_rotation_x,0,Space.World);        


                  transform.Rotate(delta_rotation_y,0,0);        


                  }        


                  else {        


                  transform.rotation = Quaternion.Slerp(transform.rotation,        


                  Quaternion.Euler(transform.rotation.eulerAngles.x, target.transform.rotation.eulerAngles.y,0        


                  ),Time.deltaTime*2);        


                  }        


                  transform.position = transform.rotation* new Vector3(0,0,-distance)+ target.transform.position;        


                  }        


                  }        


                  }        


         }





copy另存为MouseFollow_ForRPG_CSharp.cs,拖给你的镜头,就能用啦。想跟随哪一个就把目标物体拖到Inspector里target那一栏。


自动跟随角色正后方,按住鼠标右键移动鼠标,围着角色上下左右旋转镜头,滚轮缩放,放开鼠标镜头自动平滑的转回后方跟随的角度,镜头高度不变,经典的魔兽世界控制方式。另外多一个魔兽没有的功能,左键按住移动鼠标可以冻结摄像机镜头上下左右拖动,因为只是演示控制,一般左键都是战斗相关的功能,不想要把那几行删掉就行啦。全部这些核心变换代码也就10行左右。


 


如果不是用理论的旋转模型,那这个问题就太复杂啦 目标在动 在旋转,镜头相对目标又在动在旋转,要加多少参考物体,搞多少x/y/z分量的投射变换啊。。思维方式很重要


 


原理都一样 不细说了,变化就是把rts的以视野中心为参考改成了以目标为参考


一个细节就是因为要跟随,所以不管有没有输入每次update都要参考目标位置修正镜头位置的,否则就不叫跟随了。