跳转至

2.4 物理系统

物理节点的类型分类

image-20210128133327033

上图所述的节点组成了最基本的物理系统结构,其中包括对刚体的模拟、碰撞体的模拟、以及触发区域。无论是刚体还是碰撞体抑或是触发区域,都需要指定其形状和大小,把Shape类型的节点作为子节点挂在上述节点上,刚好可以用于定义这些部件的形状。

1.刚体的使用

刚体可以用于模拟不同形状物体的物理效果,使用者可以在刚体上添加各种作用力(包括重力、冲量、持续不间断的力、力矩等等),物理系统根据施加给刚体的不同的作用力,计算刚体每一帧的线速度和角速度,来获知刚体每一帧的运动轨迹。当然使用者也可以不添加作用力,而直接修改刚体的线速度和角速度,同样可以驱使刚体运动;这里需要注意,不能直接修改刚体的变换信息(Transform),因为此时刚体的变换信息是根据物理系统计算得知的,使用者直接修改变换信息会让物理计算结果失效,甚至会造成计算冲突,刚体的运动轨迹会紊乱。

1.1 创建刚体:

image-20210128135913497

如上图所示,创建一个“RigidBody”类型的节点

注意

如果只创建刚体节点,则不会产生任何效果,因为此时没有定义刚体的大小和形状,所以在刚体节点下面挂一个子节点CollisionShape或者CollisionPolygon,用于定义其形状,其次,我们需要找一个mesh节点也作为刚体节点的子节点,否则无法体现刚体带来的物理效果,创建节点树如下图所示

image-20210128153331838

image-20210128153433922

运行一下场景可以发现立方体Mesh随着刚体的重力效果一起掉落了,若地面上有碰撞体的话,刚体还会和地面产生碰撞效果。

1.2 刚体属性:

单击RigidBody节点查看其属性面板:

image-20210128140153307

  • Mode :直接选择默认的刚体("Rigid")即可,若选择其他的模式,

    • Static :与静态碰撞体一个效果;
    • Character(角色) :和"Rigid"模式类似,区别在于该模式不能旋转刚体;
    • Kinematic :和动态碰撞体一个效果
  • 质量 :刚体的质量

  • 重量 :刚体的重量(其实和质量大小成正比的,比值是g=9.8)

  • 物理材质重载 :创建物理材质,可以选择创建或不创建,主要用于改变刚体和物理系统其他模块相互接触碰撞后的效果。如下图,包括刚体表面的摩擦力( 摩擦(Friction) ,从0-1变换)、是否粗糙( (粗糙)Rough ,即是否使用摩擦力)、弹力( (反弹)Bounce ,从0~1变化)、是否可以吸收弹力((吸收)Absorbent ,当两个物体碰撞,自身以及对面都有弹力,勾选则会吸收对面弹力,否则累加两者弹力)。

image-20210128141650517

  • 重力大小 : 重力倍数,实际受到的重力 = 刚体重量(Weight) * Gravity Scale

  • 自定义积分器 : 如果打开,自动施加的力(例如重力、摩擦力等),只要非使用者主动添加的力都会失效,

  • 连续碰撞检测 : 全称是“Continuous_Collision_detection”,是否进行连续的碰撞检测,若勾选,当物体快速移动时物理系统会根据物体的运动轨迹预测是否会发生碰撞,而不是等到物体已经触碰到其他物体了才反应过来是否要采取碰撞后的行动(这样往往会导致物体快速运动来不及反应就穿透了带碰撞体的其他物体),勾选后物理效果更准确但是需要花费更多时间进行计算

  • 接触报告上限 : 刚体碰撞时会有接触点,该属性用于确定最多可以接收多少个接触点,如果刚体和其余组件碰撞产生了n个碰撞点,多于该属性值设置的值m,则最多返回m个碰撞点信息

  • 接触监控 :如果勾选,当刚体发生了碰撞,会发射信号,告知接收者它碰撞了

  • 休眠 : 是否需要处于沉睡状态,若处于沉睡状态,任何的物理效果都会失效,包括碰撞等

  • 可休眠 : 是否可以进入沉睡状态,若不勾选,即使Sleeping参数勾选了也不会进入沉睡状态

  • 轴锁 : 参数如下图所示

image-20210128151408581

一共6个自由度,前3个代表线速度的限制,后三个代表角速度的限制。举个例子,若线性Y被勾选,即物理模拟时Y方向的线速度不管如何都是0,若角度Y被勾选,则物理模拟时刚体永远无法绕Y轴旋转。

  • 线性 :

image-20210128152137931

其中Velocity代表线速度,在游戏运行过程中该值一般都是由物理系统控制的,手动调整也行,但是不需要频繁手动调整,否则影响物理系统的计算。Damp代表阻力系数,越大则越容易让线速度趋于0

  • : 代表角速度的相关参数,和线速度一致

2.碰撞体的使用

2.1 静态碰撞体

该类型的碰撞体主要作用在静态物体上。当静态碰撞体受到刚体等其余部件的冲击,不会产生移动,但是会做碰撞检测,防止刚体穿过该静态碰撞体。

image-20210128173139665

如上图所示,创建一个StaticBody类型的节点,放置一个mesh节点到StaticBody节点下面,然后点中mesh,如下图:

image-20210129110515993

再点中红圈的地方,下拉框中前四个选项,都可以用来创建该mesh的静态碰撞体形状shape,创建即可使用

image-20210129110609392

我们再观察其中的各个参数

image-20210128173241771

  • 物理材质覆盖 , 在刚体的参数介绍中已经介绍,可翻阅刚体的介绍,主要用于设置和物理系统其他部件产生碰撞时碰撞表面的一些参数信息,从而得到不同的碰撞效果。

  • 恒定线速度恒定角速度 :当其他物体,例如一个刚体,和当前的静态碰撞体发生了碰撞以后,这个刚体可能会受到静态碰撞体的影响,从而使得其线速度和角速度被静态碰撞体干扰,干扰的数值大小由这两个参数来控制。譬如制作赛车游戏的时候车转弯,要达到在地面上漂移的效果,把地面设置成静态碰撞体,调节地面碰撞体的这两个参数让车达到漂移效果。

2.2 动态碰撞体

该类型主要作用在可动的物体上。譬如需要操纵的角色,也可以给他添加动态碰撞体,这样角色可以和场景中的静态碰撞体或者刚体交互,可以推开刚体,但是自身不会受到刚体反作用力。

image-20210129105231411

如上图,创建一个KinematicBody,并在该节点下面挂载一个CollisionShape类型的节点来定义形状,再加一个mesh类型节点,组成如下图节点树结构:

image-20210129110058695

此时KinematicBody还不能进行任何交互,我们需要通过脚本指定它的行为,我们在该节点上创建一个脚本,编写如下脚本:

image-20210129111224524

解析一下脚本的意义,这里的常量GRAVITY代表重力加速度,如果你希望KinematicBody受到重力影响,需要自己写交互,因为该节点不会受到物理引擎中力的影响,那么我们可以自己模拟,并通过直接修改速度velocity来改变KinematicBody的行为。常量WALK_SPEED代表节点行走速度。

注意,关于KinematicBody的交互我们必须写在_physics_process(delta)这个函数里面。函数里,我们定义了按“上下左右”按键的时候对速度velocity的影响,譬如按上下键,速度在y方向的值会放生变化,按左右键,速度在x方向的值发生变化;除此以外还加入了重力的模拟,物体y方向速度会受到重力影响。最终通过调用move_and_silde函数来驱动KinematicBody。下面着重介绍下该函数

move_and_silde (Vector3 linear_velocity,Vector3 up_direction=Vector3( 0, 0, 0 ),bool stop_on_slope=false, int max_slides=4,float floor_max_angle=0.785398, bool infinite_inertia=true)

这个函数表面的含义是移动kinematicBody,当body遇到碰撞体时就会沿着碰撞体滑动,特别的,碰到动态碰撞体或者刚体时还可以推开这些物体

  • linear_velocity :表示当前kinematicBody的线速度;

  • up_direction :代表世界上方向,设置这个值主要是用来判别场景里的哪些物体是地板,哪些是天花板,哪些是墙,如果up方向颠倒,原来的地板可能就被认为是天花板了;

  • stop_on_slope :当kinematicBody站在斜坡上时是否会滑下来

  • max_slides :如果body发生了一次碰撞,碰撞后在body停止移动前,滑动方向可能会发生变化,那么滑动方向最多可以变化max_slides次

  • floor_max_angle :根据斜坡的坡度来定义该斜坡是楼梯还是墙,这个参数代表一个角度即坡度,大于这个坡度就是墙否则就是楼梯,默认值转化成角度就是45度左右

  • infinite_inertia :开启后,body就可以不费吹灰之力推开挡住它的刚体,但是作用力是单方面的,也就是说,对于刚体而言,被该body碰到后就好比受到了一个很大的冲量马上被弹开,但对body来说无论这个刚体存不存在都不影响自身的运动轨迹,游戏中控制的主角往往会带这种效果,关闭后body遇到刚体,想要推开就没那么容易了,更多的时候面对刚体就好像面对静态碰撞体一样,前进不了。

函数会返回一个Vector3的线速度linear_velocity,代表经过函数处理后的线速度,譬如物体可能滑下来或者碰到静态碰撞体就水平移动了等等

还有一个函数也可以移动碰撞体并产生碰撞,函数介绍如下:

move_and_collide(Vector3 rel_vec, bool infinite_inertia = true , bool  excluded_raycast_shapes = true, bool test_only = false)

使用起来比上面的函数还要简单一些,第一个参数代表实际移动速度,第二个参数infinite_inertia 还是和上述函数的参数一样,true的话惯性无穷大,会给碰到body的刚体一个很大的冲量 ; 参数为false的话我们断言只有当body的速度比较大的时候才有机会冲飞前面的刚体障碍物,事实上, F = m*Δv / Δt ,此时质量不大,只有通过速度的急速变化来弥补。

3.触发区域的使用

2.1 Area节点创建:

触发区域可用于检测物体是否进入或者离开某块区域,也可以对进入这块区域的物理对象修改其部分物理属性,例如重力,阻力等。

image-20210129144926818

如上图,创建Area节点,创建完毕后再创建一个CollisionShape类型的节点作为其子节点,用于描述区域的大小和形状。节点树如下图所示:

image-20210129145613088

2.2 Area节点参数介绍:

image-20210129145704942

  • 空间重载 : 可选选项有以下几种 ​ 首先假设现在有两块Area区域,而且互相叠加,分别记为area1,area2,且分别会带来物理效果p1,p2(这里指的物理效果是抽象化的集合,可以理解为重力、阻力等可能的物理效果的集合体),并且area1的优先级(priority)高于area2的优先级,所以计算的时候先计算area1带来的效果再计算area2带来的效果。再假设现在有个物体obj正好进入了这两个叠加区域,且物体本身带有物理效果p_obj, 如此,再介绍每个选项作用

​ (1) 禁用(Disable) : 区域area不会影响进入其中的物体的物理属性

​ (2) 叠加(Combine) : 叠加物理效果,如果area1和area2都选择了该选项,那么最终物体的物理效果是p_obj + p1 + p2

​ (3) 叠加替换(Combine_replace) : 会无视掉低优先级的区域,比如area1选择了该选项,area1就成了最后一个被考虑的区域,不会继续考虑area2带来的物理效果,最终物理效果是p_obj+p1,若在area1之前还叠加计算了其他区域的效果,并且记已经叠加的效果是p_prev,那么最终物理效果变成p_prev+p_obj+p1

​ (4) 替换(Replace) : 一旦有区域area选择这个选项,并且它有幸能够发挥它的作用,那么会让所有之前叠加的效果全部抹去,换成它自身的物理效果,低优先级也一并不考虑,例如area2选择了该选项并且考虑到了它,最终物理效果就是p2,注意物体本身的效果也被抹去了。

​ (5)替换叠加(Replace_combine) :和.Replace的区别在于选择该选项的区域在计算完成后,还会继续计算接下来的其他区域的效果,例如area1选择了这个选项,area2选择了.Combine,最终的物理效果就是 p1+p2

  • 重力点 : 若勾选,就会在区域中心产生一个重心点,从而产生万有引力,此时进入区域的物体会被重心点吸引而绕其旋转

  • 重力距离缩放 : 若有重心点,重心点对物体有吸引力,但是吸引力是随着物体距离重心点的距离变大而变小的,即力的大小和距离平方成反比

image-20210129164341062

  • 重力矢量 : 假若没有重心点,物体在area中受到的重力方向就是沿着这个参数所示的方向的,这个向量只代表方向,不考虑长度

  • 重力 : 重力的大小,一个数值,方向在Gravity Vec 中给出了

  • 线性阻尼 : 线速度的阻力值,越大的话,物体在area中线性运动受到的阻力更大

  • 角阻尼 : 同上述,角度的阻力值,越大的话,物体越难转动

  • 优先级 : 在讲解Space Override这个参数的时候提到过,即区域叠加的时候到底先计算哪个区域的效果,是依据优先值大小来确定的

  • 监测 : 若开启,当有物体进出该区域时会被该区域检测到

  • 可检测的 : 若开启,其他区域area可以检测到当前的区域是否有进出它们的区域

2.3 Area节点检测物体进出:

点中Area节点,进入节点树的Node面板,发现上面有一系列的回调函数,双击其中一个。

image

双击后面板中我们点中一个我们希望接收消息的节点

image

然后connect,就会在这个节点的脚本中出现一个回调函数,该回调函数指的是,当这个节点进入那块area区域时,area就会发送消息,当前节点接收到消息并会走一次这个回调函数,这个函数中可以编写节点进入area后的一些逻辑操作。

image-20210129171950110

image