2.13 用鼠标控制主角

仅仅使用键盘对游戏主角进行控制是远远不够的,在没有键盘的设备上如手机、平板等就不能进行游戏,所以我们接下来要对游戏添加用鼠标控制主角的功能,当游戏移植到手机上后,鼠标操作会自动转换为触屏操作。

l  因为当前游戏是一个3D游戏,鼠标的位置只是屏幕的坐标,当需要获取到相应的3D坐标时,通常需要一个参照物。我们将创建一个平面并将其放在与主角飞船等高的位置上(Y轴的坐标相同),在菜单栏依次选择GameObject->Creator->Quad创建平面,设置 该平面的大小,使得该平面的大小可以覆盖整个摄像机的视野范围,即使得平面铺满游戏窗口的整个屏幕。需要注意的是,quad是两个三角形组成四边形,plane会有很多三角形,quad和plane的区别是很大的,它对内存消耗以及制作的项目是否卡有很大的影响,如果你做的项目不是很大或者画面不需要太精细建议使用quad,反之用plane。为什么这里用quad而不用plane,这与Unity中实现如何使用鼠标点击控制角色移动原理有关。

使用鼠标点击控制角色移动原理:当我们点击屏幕时,我们按照一定的方法,将屏幕上的二维坐标转化为三维坐标,然后我们从摄像机位置发射一条经过该点的射线,则这条射线与大地平面的交点,就是我们的目标位置。那么确定了这个位置以后,我们需要做的就是让角色从原来的位置移动到这个位置,并在其间添加角色动画即可。我们创建的平面默认有一个组件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(),并且将用键盘控制主角移动的代码部分注释掉。

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语句判断将线面交点赋给指定变量。

其它注意事项:在进行实践时,我误将场景中的主摄像机删除,然后创建了一个新的摄像机后运行会一直报错,即Ray ray = Camera.main.ScreenPointToRay(Input.mousePosition)会报错空引用,此时解决的方法是选中新建的相机,在Inspector属性管理器中将当前摄像机的tag选为MainCamera 即可解决。(参考:Camera添加tag名为MainCamera就可以解决

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值