2.12 用鼠标控制主角
目前我们的游戏在PC上运行一切正常,因为手机不方便使用键盘操作,如果移植到手机上便会遇到问题。接下来,我们将为主角增加鼠标操作的功能,当将游戏移植到手机上后,鼠标操作会自动转换为触屏操作。
步骤 01 因为是3D游戏,鼠标的位置只是屏幕坐标,当需要获取到相应的3D坐标时,通常需要一个参照物。我们将创建一个平面并将它放置在与主角飞船Y轴坐标接近的位置作为参照物。在菜单栏中选择【GameObject】→【Create Other】→【Quad】,创建一个平面物体,设置它的位置和大小,使其能铺满整个屏幕,如图2-50所示。
图2-50 设置平面物体
步骤 02 默认的平面物体有一个物理组件【Mesh Collider】,它会使用模型的三角面进行碰撞计算。因为我们只需要平面物体参考位置,并不需要显示它,所以可以取消选中【Mesh Renderer】复选框。
步骤 03 因为场景中有很多物体都有碰撞体,为了区分,这里新建一个层,将平面物体放到这个层中,后面的鼠标操作将产生射线,只与这个层中的平面物体碰撞。先选择Layer,然后选择Add Layer,添加一个名为plane的层,将平面物体的层由Default改为plane,如图2-51所示。
图2-51 设置层
步骤 04 打开脚本Player.cs,添加两个新的属性:一个用于定位主角的目标位置,即鼠标单击的位置;另一个用于设置鼠标射线的碰撞层。
protected Vector3 m_targetPos; // 目标位置 public LayerMask m_inputMask; // 鼠标射线碰撞层
步骤 05 在场景中选择主角,将【Input Mask】设置为plane,这样在下面的操作中,鼠标单击产生的射线只与这个plane层内的物体发生碰撞,如图2-52所示。
图2-52 设置层Mask
步骤 06 打开脚本Player.cs,在Start函数中将m_targetPos的值初始化为当前主角的位置,然后添加一个MoveTo函数,代码如下所示:
void Start () { m_transform = this.transform; m_audio = this.GetComponent<AudioSource>(); m_targetPos=this.m_transform.position; // 添加代码,初始化目标点位置 } void MoveTo() { if (Input.GetMouseButton(0)) { Vector3 ms=Input.mousePosition; // 获得鼠标屏幕位置 Ray ray=Camera.main.ScreenPointToRay(ms); // 将屏幕位置转为射线 RaycastHit hitinfo; // 用来记录射线碰撞信息 bool iscast = Physics.Raycast(ray, out hitinfo, 1000, m_inputMask); if (iscast) { // 如果射中目标,记录射线碰撞点 m_targetPos = hitinfo.point; } } // 使用Vector3提供的MoveTowards函数,获得朝目标移动的位置 Vector3 pos = Vector3.MoveTowards(this.m_transform.position, m_targetPos, m_speed * Time.deltaTime); // 更新当前位置 this.m_transform.position = pos; }
使用Input.mousePosition可以获得当前鼠标的屏幕位置,然后使用ScreenPointToRay函数将其转化为一条射线,使用Physics.Raycast函数射出射线,将碰撞结果返回到RaycastHit对象中。Vector3提供了很多种移动、旋转物体的方法,这里使用了它提供的MoveTowards函数,计算出从当前位置朝目标位置移动,返回一个新的位置。
注意,在Physics.Raycast这个函数中,我们引用了m_inputMask参数,射线只会与m_inputMask指定的层中的物体发生碰撞。实际上,我们也可以通过层的名字来指定碰撞层,下面的代码作用与之前是完全一样的,但省去了在编辑器中指定层的步骤,如下所示:
bool iscast=Physics.Raycast(ray, out hitinfo,1000, LayerMask.GetMask("plane"); );
最后不要忘记将MoveTo函数放到Update函数中执行。
现在运行游戏,主角将会按鼠标的位置移动,如果将这个游戏移植到手机上,即是按照手指的位置移动。