5-9 摄像机移动控制
在上一章中,我们完成了摄像机视距控制的功能,通过鼠标滚轮可以控制摄像机视距的远近。接下来我们继续完善摄像机控制的相关功能。
要让摄像机在水平和垂直方向移动,与调整摄像机视距思路相似,可以检测水平和垂直的输入信息,对应Hex Map Camera
在X和Z方向的运动。代码如下
1 | private void Update() |
使Hex Map Camera
移动最简单的方式,就是先获取当前位置,然后再加上X和Z轴的输入增量,这样的出来的结果就是移动后的位置。代码如下:
1 | private void AdjustPosition(float xDelta, float zDelta) |
现在我们就可以通过WSAD来控制摄像机在X和Z轴方向上的移动了。但是这样移动的速度并不是恒定的,会受到帧率的影响。为了避免受到帧率的影响,我们改变一下思路,使用方向乘以位移距离的方式来描述摄像机的移动。而距离则是由时间增量和速度所组成的。我们添加moveSpeed
变量,用来控制摄像机的移动速度,初始值为100。代码如下:
1 | public class HexMapCamera : MonoBehaviour |
通过勾股定理我们可以发现,摄像机在斜向移动的时候,会比只沿着X或Z轴速度更快。所以需要将移动方向进行归一化处理,这样就保证摄像机向着各个方向移动时速度相同。代码如下:
1 | private void AdjustPosition(float xDelta, float zDelta) |
修复了移动速度的问题后,还存在一个问题,就是当我们持续按下一个方向键一段时间,抬起后摄像机的移动不会立刻就停止,而是会持续移动一段时间。这是因为当我们按下方向键后摄像机位置不会立即变为计算后的位置,而是需要一个过渡时间,抬起按键也是相同的原理,而且我们将表示方向的向量进行了归一化,所以在这段时间内,摄像机都会以一个恒定的速度运动一段时间。
解决这个问题的方式,就是增加一个阻尼值,阻尼值取X或Z轴向两个输入值中绝对值最大的那个,这样既保留了开始和停止时的平滑感,又解决了抬起按键还会持续移动的问题。代码如下:
1 | private void AdjustPosition(float xDelta, float zDelta) |
现在摄像机移动的相关代码已经完成了,但是当我们将镜头视距在默认位置时没没有什么问题,拉至最远的时候会感觉摄像机运动的比较慢。那就需要我们有两个速度值,一个是视距最远的时候,一个是视距最近的时候。按照这个思路,将moveSpeed
拆分为2个变量,默认值分别为400和100,对应视距最远和最近时的移动速度,通过zoom
变量进行插值计算。代码如下:
1 | public class HexMapCamera : MonoBehaviour |
至此摄像机终于可以正确的移动了。但是还存在一个问题,就是摄像机不应该移动到地图的边界之外。为了让摄像机只能在地图范围内移动,我们首先要知道地图的范围,在HexMapCamera
中创建HexGrid
变量,并在Unity中将HexGrid
物体拖入这个变量对应栏位中。代码如下:
1 | public class HexMapCamera : MonoBehaviour |
获取到地图实例后,使用一个新的方法来计算当前摄像机的位置是否在地图的范围内,并将这个计算后的位置赋值为摄像机当前的位置。代码如下:
1 | private void AdjustPosition(float xDelta, float zDelta) |
X的范围最小值是0,最大值则需要获取地图的实际尺寸。
1 | private Vector3 ClampPosition(Vector3 position) |
Z的范围取值也是相同的原理,代码如下:
1 | private Vector3 ClampPosition(Vector3 position) |
实际上只是获取地图的宽度并不精确,我们希望摄像机最终会停在最右边地图单元的中心上,因此需要在X的最大值上减去半个地图单元的宽度。代码如下:
1 | private Vector3 ClampPosition(Vector3 position) |
Z的取值范围也是相同,不过因为地图单元的排列在横纵坐标的度量方式不同,所以这里要减去整个地图单元的高度。代码如下:
1 | private Vector3 ClampPosition(Vector3 position) |
当我们现在移动摄像机时,就不会超出地图范围了。这里还有一个细节需要注意,因为我们使用的是检测水平和垂直的输入,所以Unity会响应WSAD和方向键上下左右的输入。但是同时UI也会响应方向键的输入。这样的结果就是当我们点击UI并把鼠标停留在UI上,同时使用方向键控制摄像机移动的时候,UI中的滑动条也会跟着移动。可以取消选择EventSystem上的Send Navigation Event
选项来禁止UI监听按键事件来解决这个问题。
这样,我们就完成了摄像机的移动控制功能,在接下来的一章中,我们将完成通过鼠标旋转摄像机视角的功能。