探索Unity 施加力的方式

  • Post author:
  • Post category:其他




前言

unity 中对物体添加

Rigidbody

组件就可以对物体施加力,本篇文章主要探索unity施加力的方式



自由落体运动

设置刚体组件的参数

useGravity = true

,此时物体就会受到重力的影响。unity中重力加速度

g

默认是

10



设置固定帧为0.02秒每帧:

Time.fixedDeltaTime = 0.02f;


在场景中放一个球体附件刚体组件勾选

UseGravity

,设置空气阻力为0,设置位置为(0,10,0)

在FixedUPdate中每帧输出物体的y坐标和速度

Debug.Log($"P:{transform.position.y.ToString("f3")},V:{rig.velocity}");


结果如下:

在这里插入图片描述



分析

这个结果有点出乎意料。按照物理常识,初熟度为0的物体做匀加速直线运动



S

=

a

t

2

/

2

S=at^2/2






S




=








a



t










2









/


2





,那么第二帧的y坐标应该是



10

10

0.02

0.02

/

2

=

0.998

10 – 10 * 0.02*0.02/2 = 0.998






1


0













1


0













0


.


0


2













0


.


0


2


/


2




=








0


.


9


9


8





,但实际上是

0.996,淦



通过一系列的分析,我用另外一种方式说服了自己。可以理解为再第一帧开始的时候物体受到一个瞬间的动量,而这个动量的大小为



m

g

t

m*g*t






m













g













t





,m是物体发的质量,t是

Time.fixedDeltaTime

,根据动量守恒定理



m

g

t

=

m

v

1

m

v

0

v

0

=

0

mgt = mv1 – mv0,v0 = 0






m


g


t




=








m


v


1













m


v


0





v


0




=








0





可得



v

1

=

0.2

m

/

s

v1 = 0.2m/s






v


1




=








0


.


2


m


/


s





,所以可以理解为,在这一帧内,物体以

0.2m/s

的速度向y轴负方向运动。同样的道理,下一帧的速度应该为0.4m/s,那么下一帧的移动距离应该为



0.4

0.02

=

0.008

m

9.996

0.008

=

9.988

0.4 * 0.02 = 0.008m,9.996 – 0.008 = 9.988






0


.


4













0


.


0


2




=








0


.


0


0


8


m





9


.


9


9


6













0


.


0


0


8




=








9


.


9


8


8





,对应上面的输出。这样就说的通了。

如果按照上面的分析,可以发现一个隐藏的问题,如果我们将

Time.fixedDeltaTime = 0.01f;

,按照上面分析的计算方式经过0.02秒后物体的y坐标是



10

0.1

0.01

0.2

0.01

=

9.997

10 – 0.1*0.01-0.2*0.01 = 9.997






1


0













0


.


1













0


.


0


1













0


.


2













0


.


0


1




=








9


.


9


9


7





,也就是说相同的时间,相同的重力,不同的帧率会导致物体的运动距离不一样,





实际测试一下,结果如我所料。

在这里插入图片描述


所以,在unity的物理运动中设置固定帧率真的是非常重要的一环。



unity中的Rigidbody.AddForce()

unity中AddForce()的方式有四种,测试代码如下。

public class RigidbodyTest : MonoBehaviour
{
    Rigidbody rig;
    public float MyF = 200;
    int moveT = -1;
    void Start()
    {
        rig = GetComponent<Rigidbody>();
        Time.fixedDeltaTime = 0.02f;
    }

    // Update is called once per frame
    private void Update()
    {
        if (Input.GetKeyDown(KeyCode.Q))
        {
            moveT = 0; 
        }
        if (Input.GetKeyDown(KeyCode.W))
        {
            moveT = 1;    
        }
        if (Input.GetKeyDown(KeyCode.E))
        {
            moveT = 2;  
        }
        if (Input.GetKeyDown(KeyCode.R))
        {
            moveT = 3;
        }
    }
    bool flag = false;
    private void FixedUpdate()
    {
        if (flag)
        {
            Debug.Log($"P:{transform.position.y.ToString("f3")},V:{rig.velocity}");
            flag = false;
        }
        switch (moveT)
        {
            case 0:
                rig.AddForce(transform.up * MyF, ForceMode.Acceleration);
                Debug.Log(transform.position.y.ToString("f3"));
                flag = true;
                moveT = -1;
                break;
            case 1:
                rig.AddForce(transform.up * MyF, ForceMode.Force);
                Debug.Log(transform.position.y.ToString("f3"));
                flag = true;
                moveT = -1;
                break;
            case 2:
                rig.AddForce(transform.up * MyF * 0.1f, ForceMode.Impulse);
                Debug.Log(transform.position.y.ToString("f3"));
                flag = true;
                moveT = -1;
                break;
            case 3:
                rig.AddForce(transform.up * MyF * 0.1f, ForceMode.VelocityChange);
                Debug.Log(transform.position.y.ToString("f3"));
                flag = true;
                moveT = -1;
                break;
            default:
                break;
        }
    }
}



结论

以下是不同ForceMode速度计算公式其中t = Time.fixedDeltaTime,m是质量,g是重力加速度,F是合力,v0是初速度,v1是末速度(注意,速度v和合力F具有大小和方向)

  1. ForceMode.Acceleration:



    F

    t

    =

    v

    1

    v

    0

    v

    1

    =

    F

    t

    +

    v

    0

    F*t = v1 – v0,v1 = F*t + v0






    F













    t




    =








    v


    1













    v


    0





    v


    1




    =








    F













    t




    +








    v


    0





    (质量总是为1)

  2. ForceMode.Force:



    F

    t

    =

    m

    v

    1

    m

    v

    0

    v

    1

    =

    (

    F

    t

    +

    m

    v

    0

    )

    /

    m

    F*t = m*v1 – m*v0,v1 = (F*t +m* v0)/m






    F













    t




    =








    m













    v


    1













    m













    v


    0





    v


    1




    =








    (


    F













    t




    +








    m













    v


    0


    )


    /


    m




  3. ForceMode.Impulse:



    F

    =

    m

    v

    1

    m

    v

    0

    v

    1

    =

    (

    F

    +

    m

    v

    0

    )

    /

    m

    F = m*v1 – m*v0,v1 = (F +m* v0)/m






    F




    =








    m













    v


    1













    m













    v


    0





    v


    1




    =








    (


    F




    +








    m













    v


    0


    )


    /


    m





    (冲量计算时间总是为1)

  4. ForceMode.VelocityChange:



    F

    =

    v

    1

    v

    0

    v

    1

    =

    F

    +

    v

    0

    F = v1 – v0,v1 = F +v0






    F




    =








    v


    1













    v


    0





    v


    1




    =








    F




    +








    v


    0





    (质量总是为1,冲量计算时间总是为1)



版权声明:本文为zhangliff原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。