Unity 物理系列二 AddForce velocity

一、AddForce ForceMode

https://docs.unity3d.com/cn/2019.4/ScriptReference/Rigidbody.AddForce.html
https://docs.unity3d.com/cn/2019.4/ScriptReference/ForceMode.html
Unity中关于作用力方式ForceMode的功能注解

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ForceMode_ts : MonoBehaviour
{
    public Rigidbody A, B, C, D;
    //作用力向量
    Vector3 forces = new Vector3(10.0f, 0.0f, 0.0f);

    void Start()
    {
        //初始化4个刚体的质量,使其相同
        A.mass = 2.0f;
        B.mass = 2.0f;
        C.mass = 2.0f;
        D.mass = 2.0f;
        //对A、B、C、D采用不同的作用力方式
        //注意此处只是对物体增加了1帧的作用力
        //如果要对刚体产生持续作用力请把以下代码放在FixedUpdate()方法中
        A.AddForce(forces, ForceMode.Force);
        B.AddForce(forces, ForceMode.Acceleration);
        C.AddForce(forces, ForceMode.Impulse);
        D.AddForce(forces, ForceMode.VelocityChange);
    }

    void FixedUpdate()
    {
        Debug.Log("ForceMode.Force作用方式下A每帧增加的速度:" + A.velocity);
        Debug.Log("ForceMode.Acceleration作用方式下B每帧增加的速度:" + B.velocity);
        Debug.Log("ForceMode.Impulse作用方式下C每帧增加的速度:" + C.velocity);
        Debug.Log("ForceMode.VelocityChange作用方式下D每帧增加的速度:" + D.velocity);
    }
}

功能注解:ForceMode为枚举类型,用来控制力的作用方式,有4个枚举成员,在以下举例中均设刚体质量为m=2.0f,力向量为f=(10.0f,0.0f,0.0f)。

1.ForceMode.Force

默认方式,使用刚体的质量计算,以每帧间隔时间为单位计算动量。设FixedUpdate()的执行频率采用系统默认值(即0.02s),,则由动量定理f•t=m•v可得:10*0.02=2*v1,从而可得v1=0.1,即每帧刚体在X轴上值增加0.1米,从而可计算得刚体的每秒移动速度为v2=(1/0.02)*v1=5m/s。

2.ForceMode.Acceleration

在此种作用方式下会忽略刚体的实际质量而采用默认值1.0f,时间间隔以系统帧频间隔计算(默认值为0.02s),即f•t=1.0•v即可得v1= f•t=10*0.02=0.2,即刚体每帧增加0.2米,从而可得刚体的每秒移动速度为v2=(1/0.02)*v1=10m/s。

3.ForceMode.Impulse

此种方式采用瞬间力作用方式,即把t的值默认为1,不再采用系统的帧频间隔,即f•1.0=m•v即可得v1=f/m=10.0/2.0=5.0,即刚体每帧增加5.0米,从而可得刚体每秒的速度为v2=(1/0.02)*5.0=250m/s。

4.ForceMode.VelocityChange

此种作用方式下将忽略刚体的实际质量,采用默认质量1.0,同时也忽略系统的实际帧频间隔,采用默认间隔1.0,即f•1.0=1.0•v即可得v1=f=10.0,即刚体每帧沿X轴移动距离为10米,从而可得刚体每秒的速度为v2=(1/0.02)*v1=500m/s。

二、velocity

https://docs.unity.cn/cn/2019.4/ScriptReference/Rigidbody-velocity.html
刚体的速度矢量。它表示刚体位置的变化率。

在大多数情况下,不应该直接修改速度,因为这可能导致行为失真 - 改用 AddForce

请勿在每个物理步骤中设置对象的速度,这将导致不真实的物理模拟。 需要更改速度的一个典型用法是第一人称射击游戏中的跳跃动作设计,因为此时需要立即更改速度。

1.点击空格键,角色会跳跃。而有时会跳的比之前高很多(使用Rigidbody.AddForce)

酷游戏的一些bug总结(滥用FixedUpdate的坑)
Unity3D中Rigidbody.velocity和Addforce的区别
假设我们想要做一个2D的跳跃游戏,在这个游戏里我希望我按下跳跃键的时候,游戏物体的跳跃高度是恒定的。

那么,如果此时我使用的是addForce显然不会满足我的效果,因为经过测试,每按一下跳跃键,它会被施加一个恒定的力,它跳跃的初始速度会越变越大,每次跳跃的高度和前一次相较变得越来越大(在连续跳跃的情况下),也就是可以理解成,我现在被施加了一个大小为50的力,在重力作用下我的力的效果在减小,在正向速度还没有完全消失的情况下,此时我又按了一下跳跃键,那么就会在这个力的基础上再施加一次大小为50的力,物体会越跳越快,越跳越高。

而此时如果我们使用的是velocity方法改变它的初始速度到我们希望的值和方向,那么当我们按下跳跃键的时候,无论此时物体减速到何种情况,也最多只会提升到我们规定的速度以及朝向我们规定的方向。初始速度不变的情况下,跳跃高度也是恒定的。

解决:
AddForce之前应该清一下速率,因为是射线检测是否碰到地面,而跳跃后不会立刻离地。如果不清,后面几帧会累加AddForce。清除速率保证离地的一瞬间肯定是正常Force,而非累加Force。

2.velocity

参考【Unity】Rigidbody.velocity 的陷阱,这里原文比较长,做了详细的测试,本文转载结论:

本场景中使用MovePosition()作为【仅移动】变换的函数,事实上transform.Translate(), transform.RotateAround(), rigidbody.MovePosition(), Vector3.MoveTowards() 等等亦能产生相同的结果,这里不再重复实验。

我们常在Unity开发中直接使用Rigidbody.velocity属性来获取刚体的当前速度,这在大多数情况下是没有问题的。但在某些情况下这么做就可能得不到我们想要的结果。比如通过transform.Translate(), transform.RotateAround(), rigidbody.MovePosition(), Vector3.MoveTowards() 等方法 “强制” 改变刚体的运动状态时,此时物体速度的改变并不会引起Rigidbody.velocity的改变。

  • 在【仅移动】的脚本中,MovePosition(transform.position + Vector3.forward * Time.deltaTime)这一语句使红色球在deltaTime的时间内移动 Vector3.forward * Time.deltaTime的距离,即真实速率为1,这与该脚本在Console中的输出一致。但与此同时,它的Rigidbody.velocity却一直显示为0
  • 在小球【仅受力】的作用时,Rigidbody.velocity能和真实速率保持一致
  • 当小球既受力又做MovePosition变换时, 真实速率是同一帧【仅移动】和【仅受力】中真实速率的和,Rigidbody.velocity和【仅受力】一致。

而当我们把所有球的刚体组件中的Is Kinematic属性勾选上后,我们再来看看运行结果:


image.png

OMG!【仅移动】小球的Rigidbody.velocity居然又和真实速率一致了!

我并不了解Rigidbody.velocity这个属性在内部是如何被定义的,官方文档没有相关的说明,网上也没有找到相关的资料,我个人只能根据这些现象做如下的一些推测。

当刚体的Is Kinematic没有被勾选时,刚体的运动就被Unity的物理引擎所掌控,物体的运动和状态都会遵循真实世界的物理定律。我们知道,在牛顿力学中,要改变一个物体的运动状态必须要对其施加力,Unity也为我们提供了AddForce()方法。然而像MovePosition()这样的方法似乎可以让物体的运动随心所欲,能够以任意速度到达任意位置,可以让物体瞬间加到一个非常大的速度。显而易见,这种对运动状态的 “ 强制 ” 改变必定不能通过加力的方式实现,这就已经脱离了真实世界的物理定律了。被物理引擎控制的物体擅自进行了不按套路的操作,Rigidbody.velocity就不会记录这种 “非法” 操作带来的速度改变,或者将这种非法操作对velocity的改变视为0。

反之,当刚体的Is Kinematic被勾选时,刚体的运动就脱离了Unity的物理引擎控制。风水轮流转,天道好轮回,这种情况下MovePosition()成了合法操作,AddForce()成了非法操作了。想要报仇雪恨的MovePosition()积攒了多年的怨气,对非法操作的限制变得更为严格,之前的情况还允许非法操作对物体运动状态的改变,这次已经完全屏蔽了AddForce()的作用。从上一张截图就可看出,这次即便加力物体也始终保持静止。此时此刻MovePosition()终于作为合法操作被Rigidbody.velocity认可,使其能够反映物体真实速率。

总结
通过以上案例,我的想法就是最好不要对未勾选Is Kinematic的刚体使用transform.Translate(), transform.RotateAround(),rigidbody.MovePosition(),Vector3.MoveTowards()等等这些方法,毕竟这些非常规操作必定会对物理模拟的真实性产生影响。如果你不得不使用时,也请注意Rigidbody.velocity并不是物体在场景和游戏视图中的真实速度,不要滥用这些方法和这个属性而不小心掉入它的 “ 陷阱 ”。

煮粥侠_99:虽然文章很久远了,但是想说明一点:原理其实unity的手册有解释,看这里 https://docs.unity3d.com/2019.3/Documentation/Manual/class-Rigidbody2D.html。博主的分析结果是对的,其原理,根据手册总计起来主要就是 1.用刚体的对象不要使用transform改变位置,因为这会覆盖刚体进行的位移。2. Kinematic类型的刚体不接受力学。3.Dynamic类型的刚体不建议使用rigidbody.MovePosition()方法,这个方法就是为Kinematic类型刚体准备的。所以就是要根据使用的刚体类型,选择合适的位移方法。说是Velocity的陷阱有点吓人了,其实velocity是无辜的

三、恒定力

https://docs.unity.cn/cn/2019.4/Manual/class-ConstantForce.html
恒定力 (Constant Force) 可用于快速向刚体添加恒定力。如果不希望某些一次性对象以较大的速度开始而是逐渐加速(比如火箭),则很适合使用恒定力。

要制作一个向前加速的火箭,请将 Relative Force 设定为沿正 z 轴。然后,使用刚体的 Drag 属性使其不超过某个最大速度(阻力越高,最大速度越低)。在刚体中,还要确保关闭重力,以便火箭始终保持在其路径上。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 194,524评论 5 460
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 81,869评论 2 371
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 141,813评论 0 320
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 52,210评论 1 263
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 61,085评论 4 355
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 46,117评论 1 272
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 36,533评论 3 381
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 35,219评论 0 253
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 39,487评论 1 290
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 34,582评论 2 309
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 36,362评论 1 326
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,218评论 3 312
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 37,589评论 3 299
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 28,899评论 0 17
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,176评论 1 250
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 41,503评论 2 341
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 40,707评论 2 335

推荐阅读更多精彩内容

  • 参考Cocos 3.x 3D物理系统 射线检测[https://www.jianshu.com/p/4bf973b...
    合肥黑阅读 3,601评论 0 3
  • Unity 3D物理引擎使用的是已经开源的PhysX。下面是这几天学习的笔记。 碰撞[#]1.1. 参与碰撞的对象...
    green_tea阅读 949评论 0 0
  • 一、引言 物理引擎是一个很大的标题,在这里,我只记录一些我们较为常用的一些东西,其他的一些深入的东西,随着我们的开...
    SimanX阅读 2,024评论 0 3
  • 参考Cocos Creator 3D 物理模块介绍[https://zhuanlan.zhihu.com/p/89...
    合肥黑阅读 3,012评论 0 3
  • 一、Unity简介 1. Unity界面 Shift + Space : 放大界面 Scene界面按钮渲染模式2D...
    MYves阅读 8,149评论 0 22