- Unity3D网络游戏实战
- 罗培羽
- 240字
- 2024-12-21 00:51:40
2.3 相机跟随
相机是场景中不可缺少的元素,它就像是人的眼睛,三维场景的呈现方式,最后还是要通过相机来确定。图2-9展示了相机的视野范围。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0054_0001.jpg?sign=1739262614-fFRfuTMVdQgtzPkJtnyOMgAkFxP3WXOp-0-7e11374c93551be60bf45092c708361b)
图2-9 相机及其视野范围
通常第一人称或第三人称的游戏,相机会跟随角色移动,故而要实现下面3个功能。
1)相机跟随坦克移动。
2)鼠标控制相机的角度。
3)鼠标滚轮调整相机与坦克的距离。
下面实现的是一套通用的第三人称相机组件,除了可以用于坦克游戏中,还可以把它抽出来,用在更多的游戏中。
2.3.1 数学原理
复习三角函数:因为本节会涉及sin、cos等三角函数,如果遗忘了这些知识,可以参阅相关资料(如百度百科的“三角函数公式”词条)。在图2-10所示的三角形中,角A的角度为θ,假设已知边AB的长度,那么由公式AC=AB·cosθ, BC=AB·sinθ即可求出边AC和BC的长度。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0054_0002.jpg?sign=1739262614-d4KjfNC0V7ZN79LgzJX9OFQUWNVESuzH-0-8da08e67460149c001af8417f99d52a2)
图2-10 三角函数示意图
要想让相机跟随坦克移动,就要明白在一定角度下相机与坦克的位置关系。如图2-11所示,设相机与坦克的距离为distance,相机与xz平面的角度为roll。根据三角关系即可求得映射在xz平面的距离d为distance·cos(roll),相机高度为distance·sin(roll)。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0055_0001.jpg?sign=1739262614-ViDr4dL6r7J9hLBBhxkRRssAxwcIUiKQ-0-cea703e552025c143bd29c9f966ad67d)
图2-11 在yz平面,相机与坦克的位置关系
在图2-12所示的xz平面中,设相机与坦克的距离为d(即图2-11中distance映射在xz平面的长度),相机的旋转角度为rot。由图2-12可知,相机与坦克的连线与x轴的角度为rot-180。根据三角函数,即可得出x轴的位移为d·sin(rot), z轴的位移为d·cos(rot)。所以,只要用坦克的坐标减去相对位移,便能求出相机的坐标。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0055_0002.jpg?sign=1739262614-fyCpQnvgvi53lJgA5jnBurMYZkZVoTRK-0-89905df9d4ca77cd986218b6aa6a2b79)
图2-12 相机与坦克的位置关系
2.3.2 跟随算法
新建名为CameraFollow.cs的文件,在CameraFollow类中编写相机的跟随功能,代码如下所示。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0056_0001.jpg?sign=1739262614-O2rh7wJYqHWyBQd37Zms9hF168WiQgxJ-0-fd2cd8f10e5401caa319e76473133fb7)
程序解释如下所示。
1)定义3个变量distance、rot、roll分别代表距离、横向角度和纵向角度(参见图2-11和图2-12)。由于Mathf.Sin和Mathf.Cos使用弧度作为单位,因此这里的角度都用弧度来表示。根据“弧度=角度*2π/360”可以得知,30f*Mathf.PI*2/360便是30度所对应的弧度值。
2)定义变量target表示相机要跟随的物体。然后在Start()方法中通过Game-Object.Find找到场景中的坦克,赋值给target(或通过2.3.3节实现的SetTarget方法)。注意Find方法的参数要与场景中的坦克名相同。
GameObject.Find(名字)会根据参数所指定的名字,在场景中查找物体。如果场景中存在对应名字的物体,那么它将会返回该游戏对象,否则返回null。层次面板中显示了场景中所有游戏物体的名字,读者可以右键该物体,选择Rename菜单项来修改名字(如图2-13所示)。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0057_0001.jpg?sign=1739262614-syYyEOlJbzQMNkGYW9Ze33VgxWtE8MY3-0-2122dc187830a3198ec2d7c7be31d7ad)
图2-13 修改游戏对象的名字
3)在LateUpdate()中通过上文得出的位置关系计算出相机的新位置,最后使用transform. LookAt方法使相机对准目标。读者还记得前面提及的Update方法吗?Unity3D会在每一帧中调用它,那么LateUpdate又是什么呢?这里将涉及Unity3D的生命周期。
图2-14描述了Unity3D组件的生命周期。当组件被创建时(进入场景后,场景里的所有游戏对象和组件都会被创建), Unity3D会依次调用它们的Awake和Start方法,然后在每一帧中依次调用Update和LateUpdate方法。也就是说Unity3D会在调用所有组件的Update方法后再调用LateUpdate。通过Update和LateUpdate可以控制脚本的执行顺序,例如在Update里编写移动物体的代表,在LateUpdate中实现跟随物体的相机。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0057_0002.jpg?sign=1739262614-0oZKM5El354kT0gmRAluadsMTFfXJMFc-0-fc68d684d98361e1235a81708e4899b6)
图2-14 简化版的组件生命周期
4) Camera.main表示场景中的主相机,它是第一个启用的被标记为“Main-Camera”的相机。只需要给Camera.main.transform.position赋值即可设置相机位置。下列几行代码将根据2.3.1节中所叙述的数学原理,计算相机的位置,并保存到Vector3类型的cameraPos中。
Vector3 cameraPos; float d = distance *Mathf.Cos (roll); float height = distance * Mathf.Sin(roll); cameraPos.x = targetPos.x +d * Mathf.Cos(rot); cameraPos.z = targetPos.z + d * Mathf.Sin(rot); cameraPos.y = targetPos.y + height;
5)Camera.main.transform.LookAt()使相机旋转,对准它所跟随的物体。图2-15 (左)展示了相机与立方体的初始位置关系,在调用LookAt方法后,相机的旋转角度如图2-15(右)所示,对准了立方体。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0058_0001.jpg?sign=1739262614-Zm8L6mdwM5kitOOiCWmfdm6MKeou5YW8-0-81552b40a891c90a2b91f63ee0b5df84)
图2-15 LookAt方法示意图
现在,将CameraFollow脚本拉到相机身上,调整CameraFollow组件的距离和初始角度(如图2-16所示)。然后绘制一块地形,使玩家能够感受到坦克的移动过程。运行游戏,即可看到相机跟随在坦克后面(如图2-17所示)。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0058_0002.jpg?sign=1739262614-Z1VAB2XGMhaTyleOlgax7DaxK6l7EafF-0-17cbcf4a9bc28c5c04fb69980fa984a8)
图2-16 相机跟随组件的属性
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0058_0003.jpg?sign=1739262614-NijPBrHNMalrd6gpyzJ6PTOS39yUlZqn-0-b56036394bbbbdaa61f8847f9f87a08a)
图2-17 相机跟随在坦克后面
2.3.3 设置跟随目标
在CameraFollow类中添加SetTarget方法,设置相机对准的目标。不同的三维模型其中心点会有所不同,图2-18展示的是相机对准不同中心点的情况。中心点不同,玩家所看到的视角也就不同(如图2-20所示)。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0059_0001.jpg?sign=1739262614-TLbss0NLy61ASHcDuChFZz4SDaqftSlm-0-5fcb25570ff432fa5d9130c416f6820c)
图2-18 相机对准不同的中心点
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0060_0001.jpg?sign=1739262614-Ezfw1ZmN8DZsUNlWThCLla5dofu0fLD2-0-bf3b831946d5a3dd0284070ebaf53036)
图2-19 添加一个名为cameraPoint的方块,精确控制相机对准的点
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0060_0002.jpg?sign=1739262614-5bVOAmDuoLEaZH6Xyy22q8VayYxuqrUM-0-ce175239ce7a54a674835bc96bb6adb8)
图2-20 cameraPoint在不同位置时,相机的视角变化
为了能够指定相机对准的中心点,特制定如下规则。
1)如果对准的物体带有名为cameraPoint的子物体,那么相机对准cameraPoint子物体。
2)如果物体不含名为cameraPoint的子物体,则对准物体中心点。
下面是相应的代码。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0059_0002.jpg?sign=1739262614-9sM1EEo76Hb7zNidBXmMw5UQkngPDPYH-0-b2f12a1bda055cb08689dee1eacf0bf0)
可以在炮塔上方添加一个名为cameraPoint的方块(作为Tank的子物体),精确控制相机对准的中心点(如图2-19所示)。
图2-20展示了cameraPoint在不同位置时,相机的视角的变化。
2.3.4 横向旋转相机
本节将实现通过鼠标来控制相机旋转的功能,当鼠标向左移动时,相机随之“左转”;当鼠标向右移动时,相机随之“右转”。这样,玩家便可以从各个方向查看坦克模型(如图2-21所示)。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0061_0001.jpg?sign=1739262614-rOeXUN83A3q0I6Hyo4JHVVKgZ55wiJkt-0-863fc4c57561ef7c38b3ef51b2a2919a)
图2-21 相机随着鼠标的移动而旋转,玩家可以从各个方向查看模型
Unity3D的输入轴Mouse X和Mouse Y代表着鼠标的移动增量,也就是说当鼠标向左移动时,Input.GetAxis ("Mouse X")的值会增大,向右则减小。只要让旋转角度rot与Mouse X成正比关系,便能够通过鼠标控制相机的角度。
在CameraFollow类中新增变量rotSpeed,表示相机旋转的速度。然后编写Rotate()方法,使相机的横向角度rot随着Input.GetAxis ("Mouse X")的改变而改变,代码如下所示。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0061_0002.jpg?sign=1739262614-Q2572J3uN881swNUjEy4JZypUBwTRMiv-0-2cf7f126c6f35db2716da2d9b7717709)
最后在LateUpdate ()中调用Rotate()。运行游戏后,镜头将随着鼠标的移动而转动,玩家便可以从各个角度观察坦克了。
void LateUpdate ()
{
//一些判断
if (target == null)
return;
if (Camera.main == null)
return;
//横向旋转
Rotate();
……
Unity3D的输入轴请参见InputManager面板(可通过Edit→Project Settings→Input打开,面板如图2-22所示),默认包含Mouse X、Mouse Y、Mouse ScrollWheel(鼠标滚轮)、Horizontal(水平轴)、Vertical(垂直轴)等多个参数项。我们会在使用到具体的输入轴时再做说明。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0062_0001.jpg?sign=1739262614-lOjhBBNs4e7TXihxES6kd6pAC0VKPWFu-0-120a3801772db1e0dd24aea0a5920ee5)
图2-22 Unity3D的输入项
2.3.5 纵向旋转相机
除了操控相机的横向角度,玩家还可以调整相机的高度。下面的代码通过maxRoll和minRoll定义了相机的纵向旋转范围(以弧度表示),通过rollSpeed给出旋转的速度。
//纵向角度范围 private float maxRoll = 70f * Mathf.PI * 2 / 360; private float minRoll = -10f * Mathf.PI * 2 / 360; //纵向旋转速度 private float rollSpeed = 0.2f;
在CameraFollow类中编写Roll方法,使相机纵向角度roll随着Input.GetAxis ("Mouse Y")的改变而改变。最后在LateUpdate()里调用它,代码如下所示。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0063_0001.jpg?sign=1739262614-TeWzdNNP6x427kcFVmR9F9379avzc8xk-0-25d1b23c21d71bf5bec2cf9e5974477e)
运行游戏,即可在各个角度观察坦克(如图2-23所示)。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0063_0002.jpg?sign=1739262614-JUeTMVxKW0GsxxFzGIsES65e89iYPCtF-0-f04602c774855ca6c34bbedf5ec023da)
图2-23 在不同角度观察坦克
2.3.6 滚轮调节距离
本节将会实现用鼠标滚轮调节相机与坦克之间距离的功能。输入轴Mouse Scroll-Wheel代表鼠标滚轮,即通过Input.GetAxis ("Mouse ScrollWheel")可以获取鼠标滚轮的增量,当滚轮向上滚动时该值减少,向下滚动时该值增加。添加maxDistance、minDistance和zoomSpeed这3个调整距离的变量,其中maxDistance和minDistance表示距离的范围,zoomSpeed表示缩放的速度,代码如下所示。
//距离范围 public float maxDistance = 22f; public float minDistance = 5f; //距离变化速度 public float zoomSpeed = 0.2f;
在CameraFollow类中添加Zoom方法实现距离缩放,并在LateUpdate ()里调用它,代码如下所示。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0064_0001.jpg?sign=1739262614-NCSqi6scsL0pWj7PAPIUbIvPRoXbVi5J-0-3a6e23f5c77895a0a98d7d3b38d74c5a)
运行游戏,滚动鼠标滚轮,相机与坦克的距离就会随之改变(如图2-24所示)。
![](https://epubservercos.yuewen.com/FABC1B/6158700004756901/epubprivate/OEBPS/Images/figure_0064_0002.jpg?sign=1739262614-2pBrZ5ZFn4OUvAmSwkv4ur2ySVfROXkW-0-9131add31ad4e9466507d4b9deba3f52)
图2-24 在不同距离下观察坦克