Bootstrap

【Unity】[帮助文档] AddForce函数详解,参数ForceMode(Acceleration、Force、Impulse 和 VelocityChange)的选择

背景

经常忘,经常查,倒不如我自己写一篇给自己方便参考,毕竟每次都在某N站查出来的都是不知道互抄到哪一年的机翻文章。

本文涉及代码与测试参考unity版本为2021.3,
在这里插入图片描述

AddForce

用于对rigidbody组件对象添加力的作用。
其参数决定了添加力的作用方式,因此参数不同,其获得的效果(动量、动能)也不同。
另外unity重力加速度默认为9.81左右,随着物体的状况会有改变。使用Debug.Log("Gravity: " + Physics.gravity);查看重力加速度(重力加速度也有方向!所以也是Vector3)。

要点

你需要了解并理解以下内容

  • 力是矢量,有方向,因此调用时的第一个参数是Vector3类型

  • 无论选什么参数施力,力都不会自动应用于后续帧。它只会在您调用AddForce函数的那一刻应用。区别仅在于它如何计算要施加多少力,而不在于它如何施加力。 https://answers.unity.com/questions/696068/difference-between-forcemodeforceaccelerationimpul.html

  • 使用 AddForce 时,不用手动使用 Time.deltaTime 或
    fixedDeltaTime,其内部的物理函数会自动将时间纳入计算。
    https://answers.unity.com/questions/1752181/does-addforce-with-forcemodeforce-use-timedeltatim.html

  • 物理相关的代码最好在fixUpdate函数而不是update内进行,因为fixupdate的时间间隔是固定的,update的时间间隔取决于帧率,且每次都不确定。

  • 持续的力(fixUpdate内的持续调用)使用Force、Acceleration参数,单次的力使用Impulse参数,对速度的改变使用VelocityChange参数

ForceMode

Force(力):

通过 AddForce 函数添加力,单位为 N。如果我们在FixUpdate内持续调用AddForce(Vector3.up *100,ForceMode.Force),那一秒内的50次调用(默认情况下FixUpdate 0.02秒调用一次)即为对该物体产生一个向上的100N的力持续一秒。
这两行代码是一样的

 rigidbody.AddForce(Vector3.forward*1.0f,ForceMode.Force);
 
 rigidbody.velocity += Vector3.forward*1.0f * Time.fixedDeltaTime / (rigidbody.mass);

Impulse(冲量):

通过 AddForce 函数添加冲量,单位为 N /s(牛顿每秒)。冲量是一个在一瞬间产生的力,AddForce(Vector3.up *100,ForceMode.Impulse)调用1次与AddForce(Vector3.up *100,ForceMode.Force) 调用50次(一秒)的总力一样。
这两行代码是一样的

 rigidbody.AddForce(Vector3.forward*1.0f,ForceMode.Impulse);
 
 rigidbody.velocity += Vector3.forward*1.0f / rigidbody.mass;

Acceleration(加速度):

通过 AddForce 函数添加加速度。忽略对象的质量,AddForce(Vector3.left*100,ForceMode.Acceleration)在fixupdate内执行一秒(默认50次),即视作一秒内物体保持了一个向左的100的加速度,静止的物体会在一秒后速度变为100.
这两行代码是一样的

 rigidbody.AddForce(Vector3.forward*1.0f,ForceMode.Acceleration);
 
 rigidbody.velocity += Vector3.forward*1.0f * Time.fixedDeltaTime;

VelocityChange(变速):

通过 AddForce 函数添加的速度变化,单位为 m/s。忽略对象的质量,速度变化是一个直接改变物体速度的量,它可以在一次调用后立即影响物体的运动状态。
这两行代码是一样的

rigidbody.AddForce(Vector3.forward*1.0f,ForceMode.VelocityChange);
 
rigidbody.velocity += Vector3.forward*1.0f;

参考:

https://answers.unity.com/questions/802181/trying-to-understand-rigidbody-forcemode-derivatio.html?childToView=802667#answer-802667

是否与质量有关

参数质量有关
Force
Impulse
Acceleration
VelocityChange

为了深化理解,做点实验

VelocityChange

用一个左平抛运动的物体举例,物体在(0,0,0)生成。初速为0,有重力加速度,所以我们只用关注x轴向速度。

private void FixedUpdate()
    {
        rb.AddForce(Vector3.left * 10, ForceMode.VelocityChange);
        //当对象y坐标小于0,摧毁该对象,并输出当前坐标
        if (transform.position.y < 0)
        {
            Destroy(gameObject);
            Debug.LogWarning("Position: " + transform.position);
        }

        //输出物体当前速度
        Debug.Log("Velocity: " + rb.velocity);
    }

在这里插入图片描述
每次调用使得x轴向速度增加10。相当于

rigidbody.velocity += Vector3.left*10f;

Acceleration 和Force

用一个左平抛运动的物体举例,物体在(0,0,0)生成。初速为0,有重力加速度,所以我们只用关注x轴向速度。

    private void FixedUpdate()
    {
        rb.AddForce(Vector3.left * 10, ForceMode.Acceleration);
        //当对象y坐标小于0,摧毁该对象,并输出当前坐标
        if (transform.position.y < 0)
        {
            Destroy(gameObject);
            Debug.LogWarning("Position: " + transform.position);
        }

        //输出物体当前速度
        Debug.Log("Velocity: " + rb.velocity);
        
       
    }

在这里插入图片描述
一次调用使得x方向速度改变0.2(即一秒调用使x方向速度变为10,与代码中Vector3.left * 10一致)

Acceleration可以理解为 ,函数内部的执行效果相当于,参数为Force的力的大小自动乘以了对象的质量,即以下俩代码效果相同

rb.AddForce(Vector3.left * 10 * rb.mass, ForceMode.Acceleration);
rb.AddForce(Vector3.left * 10, ForceMode.Force);

即当物体质量为1的时候,参数为Acceleration或Force的函数调用,使得对象获得相同的效果。验证如下

  • Acceleration
    在这里插入图片描述
    private void FixedUpdate()
    {
        rb.AddForce(Vector3.left * 10 * rb.mass, ForceMode.Acceleration);
        //当对象y坐标小于0,摧毁该对象,并输出当前坐标
        if (transform.position.y < 0)
        {
            Destroy(gameObject);
            Debug.LogWarning("Position: " + transform.position);
        }

        //输出物体当前速度
        Debug.Log("Velocity: " + rb.velocity);
    }
  • Force

在这里插入图片描述

    private void FixedUpdate()
    {
        rb.AddForce(Vector3.left * 10, ForceMode.Force);
        //当对象y坐标小于0,摧毁该对象,并输出当前坐标
        if (transform.position.y < 0)
        {
            Destroy(gameObject);
            Debug.LogWarning("Position: " + transform.position);
        }

        //输出物体当前速度
        Debug.Log("Velocity: " + rb.velocity);
    }

参考:

我自己

后记

一篇文章查资料做实验写了一晚上,学到了很多,但是有用的都是英文的资料,中文的没怎么搜到,所以也想分享给同是学unity的在中文互联网上查资料的你,求点点赞,点点收藏,谢谢你了。

;