用Unity实现Minecraft中的镜头控制

在学习Unity的过程中,最基本而又最重要的一部分就是镜头控制(Camera Control)

镜头控制就是通过鼠标、键盘等输入设备的操作,来实现在游戏中的导航。在Unity中的本质是通过接收鼠标的移动和键盘的按键,来变换相机对象(Camera)的位置(position)和旋转(rotation),这两个值位于cameratransform组件(conponent)中。

在这里我们通过实现《我的世界》中创造模式的镜头控制方式来学习第一人称的镜头控制。

在我的世界中,镜头的朝向(旋转)是通过鼠标在XY方向的平移来控制的,镜头的前后左右移动是通常的WASD键,升起(向上移动)为空格键,降落(向下移动)Shift键。

下面我先给出完整代码和Demo的建立步骤。运行成功后,我们再进行代码剖析。

 

建立Demo

1. 新建一个Unity项目。

2. 将下面代码保存为BasicCameraControl.cs,放到Unity项目的Assets文件夹下。

using UnityEngine;
using System.Collections;

public class BasicCameraControl : MonoBehaviour
{
    float yaw = 0;         // 偏航角,绕Y轴旋转的角度
    float pitch = 0;       // 俯仰角,绕Z轴旋转的角度
    const float roll = 0;  // 翻滚角,绕X轴旋转的角度

    void FixedUpdate ()
    {
        // Move forward or backward
        if (Input.GetKey (KeyCode.W)) 
            transform.position += Vector3.ClampMagnitude (transform.forward, 0.1f);
        else if (Input.GetKey (KeyCode.S)) 
            transform.position -= Vector3.ClampMagnitude (transform.forward, 0.1f);

        // Move left or right
        if (Input.GetKey (KeyCode.A)) 
            transform.position -= Vector3.ClampMagnitude (transform.right, 0.1f);
        else if (Input.GetKey (KeyCode.D)) 
            transform.position += Vector3.ClampMagnitude (transform.right, 0.1f);

        // Move up or down
        if (Input.GetKey (KeyCode.Space)) 
            transform.position += new Vector3 (0, 0.1f, 0);
        else if (Input.GetKey (KeyCode.LeftShift)) 
            transform.position -= new Vector3 (0, 0.1f, 0);

        // Rotate
        pitch -= Input.GetAxis ("Mouse Y") * 5;
        pitch = Mathf.Clamp (pitch, -90, 90);
        yaw += Input.GetAxis ("Mouse X") * 5;
        transform.rotation = Quaternion.Euler (pitch, yaw, roll);
    }
}

3. 为场景中的默认相机对象(Main Camera)添加此脚本组件。具体做法为,选择Main Camera,在Inspector中点击底部的Add Component按钮,点击Scripts菜单,点击Basic Camera Control完成。

4. 在场景的中心位置添加一些物体作为移动相机时的参照,比如一个正方体(Cube)

5. 点击Play按钮,移动鼠标进行转向,按下WASD、空格和Shift进行移动。

 

细节解析

1. 镜头平移控制

镜头的平移实际上是在检测到键盘上WASD、空格、Shift的按下后,修改camera.transform.positonx, y, z分量。

在这里我们需要注意的是,y分量也就是升起和降落,是永远平行于世界坐标系的y轴的,所以直接修改y分量即可:

transform.position -= new Vector3 (0, 0.1f, 0);

但是对于前进后退和左右平移是不一样的,因为我们在这四个方向的移动还和我们面朝的方向有关。所以我们通过tansform.forwardtransform.right获取朝向然后与与transform.position进行加减。

使用Vector3.ClampMagnitude()函数是为了减慢移动速度到合适的程度。

2.镜头旋转控制

关于镜头的旋转我们或许可以用下面的一行代码实现:

transform.Rotate (- Input.GetAxis ("Mouse Y") * 5, Input.GetAxis ("Mouse X") * 5, 0);

但是这样无法保证我们的镜头始终与地面保持垂直。通过在屏幕上不断地画圆圈,我们可以实现倒立。我们不是杂技团,所以这肯定不是我们想要的。

为了避免这种情况发生,我们通过先对旋转角的分量进行偏移,然后再用Quaternion.Euler()函数转换为四元数即可。

3.为什么用FixedUpdate()

Update()FixedUpdate()的区别是Update()是随渲染(Render)过程发生的。而FixedUpdate()是按照固定的周期发生的,也就是说即使由于画面上人物众多,刷新率降低,也能保证函数执行的次数恒定。

了解到这些,我们就可以设想。假如我们在Minecraft中进行一场赛跑,一台高配台式电脑以60FPS运行,而一台笔记本以平均30FPS运行。如果我们用Update()来驱动人物运动的话,那么笔记本上的人物肯定移动没有台式机快。这样肯定不符合公平的原则,所以我们在这里必须使用FixedUpdate()

End

posted @ 2016-05-18 20:45  牛俊为  阅读(3020)  评论(0编辑  收藏  举报
【End】