纳金网

标题: 有关游戏角色控制的几种实现方式(二) [打印本页]

作者: wyb314    时间: 2012-10-24 23:23
标题: 有关游戏角色控制的几种实现方式(二)
  这一篇我接着上一篇继续讨论角色控制方面:利用胶囊体与刚体对角色的动作进行控制。我仿照了官方的Angrybots,自己写了3个控制脚本,分别为:SuperMarioMoveAnimaiton.cs,SuperMarioRigidbody.cs,SuperMoveMotor.cs。这三个脚本我也一并奉上。
    与前面的控制方法不同的是,这次没有用角色控制器来控制角色了。现在我来演示一遍我的做法。
    我们在刚才的官方的工程中新建一个场景,取名为:TestRigibody。然后从Project面板下展开Goober Artwork文件夹下的子文件夹FBX,将area这个FBX文件拖拽到Scene视图中去。



顺便也将goober的FBX文件拖拽到Area上。至此我们的场景已经搭建好了,如图:



接下来我们要做好几项准备工作了:
首先,我们为goober添加一个Capsule Collider( 胶囊碰撞器 :菜单-->Component-->hysics-->Capsule Collider),然后,我们调节此胶囊碰撞的一些参数,直至适合goober的大小,再次注意一下,胶囊碰撞器的底部一般要高于角色的脚部的高度,这样运行起来角色就不会像悬浮在地面上一样。我调的具体参数的截图如下:





现在,我们像goober加入Rigidbody(  刚体 :菜单-->Component-->hysics-->Rigidbody )组件,然后再在Inspector面板下调节缸体组件中的Constraints参数,如图:










我此时冻结了刚体的X与Z轴向的旋转,具体为什么要这样做呢?因为刚体这个组件一旦添加到角色身上,那么英伟达的PhysicX引擎将作用于角色,角色如果受到哪怕一丁点力的作用就会产生物理效果,这里我们不想让角色倒地,所以冻结了它的X与Z轴。
接下来我们就要来拖拽脚本到我们的goober上去了,好,我将这三个脚本全都拖拽到goober上面。摄像机还是用的是SmoothFollow这个js脚本( 以后一定会用更特别的脚本来控制摄像机的 )。这样做还不够,我们还必须将goober从Hierachy面板下拖拽到刚才goober本身的Super MarioRigidbody.cs脚本下的Motor变量位置,由于Motor的类型是SuperMoveMotor,那么此时Motor选项中的goober自动提取其下附着的SuperMarioRigidbody组件作为此变量值。
首先,我将我的两个脚本的截图奉上:




我们可以观察一下,上面这个脚本中有一个SuperMoveMotor类型的变量,名字与我自己写这三个脚本中的一个名字相同。其实,我们的脚本就是一个类,可以继承别的脚本,也可以被继承( 有点面向对象了! )。并且脚本也是一个组件,其实,Unity里的所有组件归根结底就是脚本。甭废话了,看我们的代码吧!
首先还是老规矩,如果变量很多的话,就先看函数,貌似我的脚本中的变量也不多啊,算了。第15行,初始化motor中的moveDirection向量为Vector3( 0,0,0 ),我们看下面这张截图,可以发现motor下正好有一个moveDirection变量,而且还是公有的,正好可以再其他脚本中使用。下一行就比较简单了,存储摄像机的transform。我们看Update函数。

   因为Update函数每帧都在执行,所以他的第一行不出意外也会每帧执行一次,也就是UpdateMoveDirection每帧更新。
我们先跳转到UpdateMoveDirection这个函数下。第29~33行我截个图:


第二十九行,我们发现了我们刚才一开始没有看的成员变量screenMovementSpace现在被赋值了,其值的类型是Quaternion,四元数。而且是将摄像机的世界Y轴方向的旋转角转换为四元数,现在还不清楚要做什么,我们看第31行,将此四元数与世界坐标系中的Z轴方形的单位向量相乘。四元数与三维向量相乘,功能是将此三维向量用该四元数来旋转,就是用摄像机绕世界Y轴旋转的角度来旋转此单位向量,这就是这个乘法的功能。下面第33行也是同样的道理。我们可以想象一下,如果摄像机绕世界Y轴没有旋转的话,那这两个向量会是什么情况?从顶视图看就会使这个样子:





一般情况下是这个样子 :





注意:蓝颜色的是Z轴,红颜色的是X轴,绿颜色的是Y轴,图中的那个空的GameObject的Z与X轴可以看做是我们的Vector3.forward与Vector3.right,组合成一个十字架。
那么如果摄像机绕世界Y轴旋转,那么这个十字架的世界坐标系Y轴方向旋转角度也会与其一致,你此刻会发现,这个向量或许可以作为我们goober移动的方向,这样想很好,但是接下来我们看到的代码会有点特殊,因为此刻我们不再用CharacterController这个组件了。
下面这两行的用意很明显,利用方向键来控制motor.moveDirection的值,与前一篇一样。然后保持此向量的方向,让其长度为1个单位长度。接下来我们就来分析motor了。




motor是SuperMoveMotor类型的,且moveDirection这个变量最终是要在这个脚本中大显身手的。由于此脚本也绑定在goober身上,那么他必然起着一些直接作用。老样子,先看函数,
我们看第12行,将刚才的moveDirection与一个walkSpeed变量相乘,存储在一个临时变量targetVelocity里面,紧接着用此变量减去刚体组件的速度。一个好像是将要移动的方向,另一个
又是移动时速度,这两者相减得到一个类似于速度差的向量deltaVelocity。我们再往下看,if语句,如果刚体使用了重力,那么就向下执行。先看第15行,让刚才的速度差的Y轴方向分量为0,也就是让此向量平行于世界坐标系中的XZ平面。然后对刚体施加力。那为什么施加这样一个力呢?




我们可以运算一下:
deltaVelocity + rigidbody.velocity = targetVelocity -rigidbody.velocity + rigidbody.velocity=targetVelocity
=moveDirection * walkingSpeed。至此,你应该明白了为什么要施加这样一个方向的方向力给刚体了,是为了校正刚体的移动方向 与moveDirectoin一致。
其大小deltaVelocity与一个浮点型的变量的乘积,且施加力的模式是渐渐增加的( ForceMode.Acceleration)。我们再看下面if里面的语句:




出现了一个好像与旋转相关的变量rotationAngle,此变量的值是由AngleAroundAxis这个静态函数来处理的。为此,我们必须了解这个函数该怎么使用。截个图:







我们看穿进去的是什么参数:transform.forward,这个是goober的自身Z轴的单位方向向量。moveDirection,这个与goober将要移动的方向有关,也是单位向量。Vector3.up,还是单位向量
只是它是平行于世界Y轴方向的。
我们看第28,29行,用到了一个平时很少用到的函数Vector3.Project( )。那么这个函数是用来做什么的呢?是用来求得dirA投影到axis上的向量的。如果你的向量运算方面比较好,那么这两行的意思你立马就能明白。其实就是将dirA与dirB这两个向量的Y分量设为0。也就是让这两个向量水平罢了。具体是这样算的:
首先用dirA投影到axis上的向量为b,由于axis传进来的参数是Vector3.up,也就是世界坐标Y轴单位向量,设dirA与世界Y轴的夹角为a,我画一张图你就能明白的:


第30行是求dirA与dirB之间的夹角,第31行中涉及到了向量的两种基本概念,即点乘与差乘。你应该熟悉点乘,就是两个向量的x,y,x分别相乘之和,但是差乘就有点麻烦了,但是我这里提供以下我自己的一点点经验:两个向量a,b的差乘的结果是一个向量c,且c垂直与a与b形成的平面。而且c的方向可以用左手定则来确定,也可以利用3阶行列式相乘来确定。左手定则的具体做法是:伸出你的左手,让大拇指垂直ab平面,且四指朝向向量a指向的方向,然后你可以试着顺时针旋转左手看能不能顺利的旋转到向量b所指向的方向,如果可以,则大拇指指向的方向就为c的方向,反之亦然。
那么第31行的意思就是:如果俯视向量dirA与dirB,发现从dirA旋转到dirB只需要旋转一个小于180度的角,那么该函数最后的返回值为angle,否则为-angle。如果读者还不明白,可以给我留言.

我们回到24行,由静态函数AngleAroundAxis返回的角度变量用作对角色施加的角速度的一个度量,然后对其大小进行一番调节,即乘以turningSmoothing。最后对刚体施加一个角速度。




至此为止,我们用刚体加胶囊碰撞器控制角色已经全部完成了。总体思路就是:对刚体不断施加一个渐渐增长的很小的一个力,并且相应的施加一定的角速度来触使角色边移动边旋转。并播放动画(动画脚本比较简单,读者可以自行研究一下,以后如有机会,我会专门讲动画这一部分的)。里面涉及到了不少向量方面的运算,都比较基础,如果空间几何学的不错,那么理解这些真的是不费吹灰之力。这种实现方式跟官方的AngryBots是一致的,只不过官方的实现要复杂很多,读者用兴趣可以认真分析一下官方的例子。


















作者: .    时间: 2012-10-25 21:04
顶起
作者: may    时间: 2012-11-30 22:20
支持楼主的帖子
作者: may    时间: 2012-11-30 22:21
支持楼主的帖子
作者: 王者再临    时间: 2012-12-28 23:24
学习了,虽然还是有难度,谢谢楼主的用心




欢迎光临 纳金网 (http://old.narkii.com/club/) Powered by Discuz! X2.5