Unity3d 在Update中使用MovePosition位移出现的问题

学习Unity开发过程中在Update中调用ridigbody.MovePosition编写移动逻辑,发现实际移动速度异常。

private Rigidbody2D ballRid;
void Start()
{
    ballRid = transform.GetComponent<Rigidbody2D>();
}

void Update()
{
    Move();
}
/// <summary>
/// 通过设置Rigidbody2D.MovePosition来移动
/// </summary>
void Move()
{
    Vector3 dir = new Vector3(Input.GetAxisRaw("Horizontal") * moveSpeed, 0, 0);
    ballRid.MovePosition(transform.position + dir * Time.deltaTime);
}

虽然是在Update中调用,但是乘了Time.deltaTime后效果应该和在FixedUpdate中一致,但实际效果是游戏低帧率时移动正常,高帧率时移动缓慢。

刚体组件的MovePosition方法与修改transform.position不同,方法执行后不会立即造成位移的更改(可以通过在方法前后Debug物体的transform检测,具体可见https://www.jianshu.com/p/6dbe71cde6f2),无论是在Update中还是FixedUpdate中。

经测试,在Update中调用MovePosition,在大于30帧的时候的实际执行次数是小于每秒30次的,同时随着帧数的增长实际执行次数会非线性增加并逼近50次每秒(fixedupdate的执行频率)。

推测是调用MovePosition方法后会在下一次fixedupdate中更新位移,当帧率较低时,update的调用次数无法填满fixedupdate的执行次数,实际移动次数会少于50次(此时如果位移距离乘了Time.deltaTime则会达到和 transform.position += 位移距离 *Time.deltaTime 相近的效果;如果乘的是Time.fixedDeltaTime则会因为Time.fixedDeltaTime在低于50帧的时候数值小于Time.deltaTime导致位移速度小于transform.position += 位移距离 * Time.deltaTime);帧率高于50后,MovePosition的每秒位移次数接近50次(但由于帧率波动或其他原因不能像fixedupdate一样稳定每秒执行50次),此时如果还是用位移距离乘Time.deltaTime则会导致实际速度慢于transform.position += 位移距离 *Time.deltaTime的方式,如果乘的是Time.fixedDeltaTime会达到类似在fixedupdate中调用的效果,但因为执行次数不稳定,可能出现抖动或停顿。

因此导致了无论乘Time.deltaTime还是Time.fixedDeltaTime,在Update中的调用都会受到帧率影响,应该在FixedUpdate中调用以在不同帧率下保持同速度。

测试代码如下:

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

public class AboutMovePosition : MonoBehaviour
{
    private Rigidbody2D ballRid;
    public float moveSpeed = 2f;
    private float timer = 10f;    //计时器,移动几秒后停止
    public int count = 0;    //Update的执行次数
    public int countf = 0;    //FixedUpdate的执行次数
    public float rate = 0;    //MovePosition的位移次数和FixedUpdate的执行次数之比
    // Start is called before the first frame update
    void Start()
    {
        ballRid = transform.GetComponent<Rigidbody2D>();
        //Application.targetFrameRate = 50;    //限制帧率测试不同帧率下的执行次数
    }
    private void FixedUpdate()
    {
        if (timer > 0)
        {
            ++countf;
        }
        rate = transform.position.x / countf;
    }
    // Update is called once per frame
    void Update()
    {
        if (timer > 0)
        {
            Move();
            ++count;
        }
        timer -= Time.deltaTime;
    }

    void Move()
    {
        ballRid.MovePosition(transform.position + Vector3.right );    
        //每次向x轴正向移动1,x坐标即为执行次数(x初始设为0)
    }
}

 测试用Unity版本为2022.3.29fc1

个人学习记录使用,如有错漏欢迎指正。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值