仅仅使用键盘对游戏主角进行控制是远远不够的,在没有键盘的设备上如手机、平板等就不能进行游戏,所以我们接下来要对游戏添加用鼠标控制主角的功能,当游戏移植到手机上后,鼠标操作会自动转换为触屏操作。
l 使用鼠标点击控制角色移动原理:当我们点击屏幕时,我们按照一定的方法,将屏幕上的二维坐标转化为三维坐标,然后我们从摄像机位置发射一条经过该点的射线,则这条射线与大地平面的交点,就是我们的目标位置。那么确定了这个位置以后,我们需要做的就是让角色从原来的位置移动到这个位置,并在其间添加角色动画即可。我们创建的平面默认有一个组件Mesh Colider,它会使用模型的三角面进行碰撞检测,而碰撞的对象就是由摄像机位置发射的经过目标点的射线。这个用于碰撞的面是不需要显示出来的,可以取消Mesh Renderer复选框,同时因为只是用于检测不需要渲染出来的缘故,所以使用只包含有两个三角网格的quad以减少计算的负担显得更加合理。
l 由于场景中含有很多碰撞体,不加以区分的话就及其容易让游戏出现问题。在动手实践的过程中,就因为原先主角Player的得分原则是当主角碰上了不是玩家子弹的碰撞体代码表述为if(other.tag.CompareTo("PlayerRocket")!=0),但是带有碰撞检测的平面quad和玩家是处于同一高度的,两个物体从一开始就是已经发生碰撞的,所以在游戏运行之后就直接进入了重新开始进行游戏的游戏失败界面。所以我们还要做的就是对碰撞体加以区分,这里我们新建一个层。在属性管理器里下拉layer选择Add Layer,添加一个名为plane的层,然后将刚才创建的quad的层选为plane。
l 代码实现部分:相关功能在Player.cs实现。
1) 声明:声明部分声明两个变量一个用于存储目标位置,另一个用于指向鼠标射线碰撞的对象(就是我们创建的平面quad),这里我们进行序列化,然后在属性管理器中将quad指定给m_inputMask。
2) 控制函数主体编写:
voidMoveTo()
{
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,move_speed*Time.deltaTime);
this.m_transform.position=pos;//更新当前位置
}
3) 编写好MoveTo()函数之后,在Update函数中引用MoveTo(),并且将用键盘控制主角移动的代码部分注释掉。
l Physics.Raycast:Physics.Raycas是一个公共静态布尔类型变量,应用格式为Raycast(Vector3 origin, Vector3 direction, floatmaxDistance = Mathf.Infinity, int layerMask= DefaultRaycastLayers, QueryTriggerInteraction queryTriggerInteraction= QueryTriggerInteraction.UseGlobal);其中Vector3 origin为射线的起点在世界的坐标,Vector3 direction为射线的方向,float maxDistance为射线应检查碰撞的最大距离,int layerMask为一个图层掩码, 用于在投射光线时有选择地忽略对撞机,queryTriggerInteraction为指定此查询是否应命中触发器。booliscast=Physics.Raycast(ray,out hitinfo,1000,m_inputMask);语句中的1000就是射线应检查碰撞的最大距离。Iscast是一个布尔类型的变量,因为调用的方法Physics.Raycast返回值只能是true或false,当发生碰撞时返回ture,则可以通过if语句判断将线面交点赋给指定变量。
l 其它注意事项:在进行实践时,我误将场景中的主摄像机删除,然后创建了一个新的摄像机后运行会一直报错,即Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition)会报错空引用,此时解决的方法是选中新建的相机,在Inspector属性管理器中将当前摄像机的tag选为MainCamera 即可解决。(参考:Camera添加tag名为MainCamera就可以解决)