最近跟着做了几个小Demo,2D游戏的移动大部分都是利用物理的刚体。

首先得到设备的输入:float horizontalInput= Input.GetAxisRaw(“Horizontal");//-1~1

然后用向量改变物体使物体移动:rb.velocity = new Vector2(horizontalInput * speed, rb.velocity.y

其实用起来还是可以的。

如果移动不放在FixedUpda中,而是放在Update()中会导致在不同的机器中,帧有时会因为Update()的刷新频率不一样,而导致有的单位时间Update刷新帧率60帧,有的单位时间只有10帧;而由于每一帧的移动距离都是10米,这就导致我们的感官上移动速度产生了变化。

void Update()
{
        transform.Translate(0, 0, 10); //物体沿着自身Z轴方向,每帧物体移动10米
}
 为了解决这个问题,引入Time.delaTime
/// <summary>
   /// 每帧刷新
   /// </summary>
   void Update()
    {
        transform.Translate(0, 0, Time.deltaTime * 10); //物体沿着自身Z轴方向,每秒物体移动10米
    }

首先基于物理的函数我们都要放在FixedUpdate()函数中执行,常见的刚体运动,物理处理都需要放到fixedupdate里,可以防止因设备帧率不同导致效果不同。

对非物理游戏而言在Update()内用Time.deltaTime会更好。因为FixedUpdate()不是渲染帧。配置高会很舒服,动作类游戏。

如果做物理型游戏用到Unity物理组件,以及用到了大量的碰撞。就在FixedUpdate()里用Rb.velocity = new Vector2(horizontalInput * speed, rb.velocity.y;

说到这里就要说一下FixedUpdate()函数了

可以看这个:https://blog.51cto.com/u_15162069/2879975写的贼好。

Time.realtimeSinceStartup函数

了解一下函数:Time.realtimeSinceStartup表示的是从程序开始以来的真实时间。

Time.time,或者Time.deltaTime,又或者使用粒子或者动画系统,它们是依赖于游戏时间的。当我们加速游戏的时候,那么就会变更。

那么有一个需求就是如何让某些东西不依赖于时间缩放呢?比如UI上,即使游戏速度再慢,但是总不能影响我的UI吧。所以这个时候就需要写一个类,来完成不受时间速度的功能。比如说ngui上有一个就是不受时间速度影响的itweener的ignoreTimeScale属性。

timeScale只会影响FixedUpdate的速度
设置 Time.timeScale = 0;即可让游戏暂停。 其实我们暂停的主要是 人物动画,还有技能特效,比如一个火球打了一半。UI方面往往我们不希望暂停,比如暂停界面 有一些UI位移动画或者帧动画, 或者最起码要有个“取消暂停的按钮” 吧。 总不能游戏暂停了我点击按钮 按钮的点击动画 或者特效也暂停了吧。

帧率

帧率是Unity单位时间内刷新的次数。

帧率=帧数/单位时间

using System.Collections;
 using System.Collections.Generic;
 using UnityEngine;
 using UnityEngine.UI;
 [RequireComponent(typeof(Text))]
 public class Test : MonoBehaviour {
  
     const float fpsMeasurePeriod = 0.5f;//固定时间为0.5s
     private int m_FpsAccumulator = 0;
     private float m_FpsNextPeriod = 0;
     private int m_CurrentFps;
     const string display = "{0} FPS";//输出格式
     private Text mText;
     private void Start()
     {
         //Time.realtimeSinceStartup  游戏开始的真实时间
         m_FpsNextPeriod = Time.realtimeSinceStartup + fpsMeasurePeriod;//下一次刷新时间
         mText=this.GetComponent<Text>();
     }
     private void Update()
     {
         // measure average frames per second
         //计算每秒的平均帧数
         m_FpsAccumulator++;
         if (Time.realtimeSinceStartup > m_FpsNextPeriod)
         {
             m_CurrentFps = (int)(m_FpsAccumulator / fpsMeasurePeriod);
             m_FpsAccumulator = 0;
             m_FpsNextPeriod += fpsMeasurePeriod;
             mText.text = string.Format(display, m_CurrentFps);
         }
     }
  
 }

 FixedUpdate()

默认情况下FixedUpdate的更新频率是50FPS(0.02s),如果当游戏的更新频率较大时——例如60FPS——那么FixedUpdate有固定的更新频率还稍微可以理解,但是如果游戏本身的更新频率就很低——例如30FPS——那么是怎么保证FixUpdate的更新频率呢?

而Unity的主要逻辑是单线程的(参见Aras的回答),所以也不存在有不同的逻辑循环可能,换句话说Update和FixedUpdate是在同一个线程上调用的。

如果我们来重复一下各位测试FixedUpdate时经常采用的方式:打印两次调用之间的时间间隔,或者是计算每次调用的累积时间,但区别在于我直接使用了真实的时间:

void FixedUpdate() { Debug.Log("FixedUpdate realTime: " + Time.realtimeSinceStartup); }
void Update() { Debug.LogError("Update realTime: " + Time.realtimeSinceStartup); }

为了以示区别,正常的Log是FixedUpdate,LogError是Update,并且设定整个游戏的更新频率为30FPS。

unity中怎么实现物体逐渐消失 unity物体移动速度怎么设置_unity中怎么实现物体逐渐消失

通过上图可以发现,FixedUpdate并不是间隔0.02s才调用一次,相反,它有可能在Update之前调用多次。

例如刚启动时,在某次Update之前连续调用了11次FixedUpdate,而之后每次Update调用之前都会调用1~2次FixedUpdate方法,这也很好理解,因为FixedUpdate的频率是50FPS,而我们设定的更新频率为30FPS,FixedUpdate的调用次数势必要多于Update。

所以,FixedUpdate除了用来处理物理逻辑之外并不适合处理其他模块的逻辑,尤其是当大家的潜意识里都笃定它的更新频率是固定的时候。因为这很危险,比如一个需要状态同步的游戏要求按照固定的频率向目标同步状态,如果贸然采用FixedUpdate方法,就会出现上图那样可能在短时间内多次调用的问题。所以最好只在物理逻辑的处理中使用FixedUpdate,而不要滥用。而由于FixedUpdate主要是用于物理逻辑的,因此下文的讨论也主要围绕物理逻辑。

当机器十分快时,引擎可能通过线程休眠来保证固定的FPS。

所以看上去整个游戏保证一个大致的更新频率似乎不难。但是现在问题的关键在于每次更新时的时间增量无法保证相同。而在物理模拟中,保证一个固定的增量时间是十分重要的。这是因为在游戏引擎进行物理模拟时要使用数值积分,而作为最简单的数值积分方法——欧拉法在游戏引擎中大量使用。

unity中怎么实现物体逐渐消失 unity物体移动速度怎么设置_unity中怎么实现物体逐渐消失_02

上面就是一个欧拉法的简单例子。可以看到增量时间是很重要的。而在游戏引擎的物理模拟中,一个不稳定的增量时间可能导致很多和预期相悖的结果。

由于此时计算的是真实的时间,而真实的增量时间无法保证固定,那换一个思路,我们把参与物理模拟的增量时间当做一个常量可以吗?换句话说,不论游戏的更新频率如何,参与物理模拟的增量时间是一个常数。

一个最简单的固定增量时间的实现,显然就是将固定的增量时间作为一个常量参数传递给物理模拟模块,这样我们就能够保证物理模拟的增量时间固定,同时还能将物理模拟的更新频率和游戏引擎的更新频率进行解耦——物理的模拟不受引擎的更新频率影响,无论游戏的更新频率是多少,传递给物理模拟的增量时间都是一个常量。

这里还拿Unity引擎来举例子,默认情况下项目的Fixed Timestep的值为0.02s。也就是说物理模拟的频率是50FPS,假设我们的游戏的更新频率是25FPS,那么会发生什么呢?没错,游戏每1次Update时,物理模拟都要推进2次,也就是之前我们看到的在Update之前多次调用了FixedUpdate。那么如果我们的游戏更新频率是100FPS呢?这次就变成了每2次Update调用1次FixedUpdate。

这也就解释了为何有的朋友在做相关的小测试的时候,在每次FixedUpdate内打印Time.deltaTime时输出的都是0.02了,因为Time.deltaTime并非两次调用FixedUpdate之间真实的时间间隔,而是来自我们在项目的Time设置内设置的值——它是一个与真实时间无关的常量。

那么这种固定增量时间的逻辑如何用代码表示呢?很简单,只需要在主循环的内部,再来一个二级循环。

double simulationTime = 0; double fixedTime = 20;
while (!quit()){
double realTime = Timer.GetTime();
while (simulationTime < realTime){
simulationTime += fixedTime;
UpdateWorld(fixedTime); }
RenderWorld();
}

-----------------------------------
Unity 生命周期-fixedupdate为啥能维持固定帧率
https://blog.51cto.com/u_15162069/2879975