時間
このフレームの開始時刻(読み取り専用)。これは、ゲームの開始からの秒数です。
そして、私が知っているように、時間はフロートに保存されます。したがって、私の質問は、時間の価値が非常に大きくなったときに何が起こるかということです。あふれますか?精度が失われ、バグが発生しますか?ゲームはただクラッシュするのでしょうか?
時間
このフレームの開始時刻(読み取り専用)。これは、ゲームの開始からの秒数です。
そして、私が知っているように、時間はフロートに保存されます。したがって、私の質問は、時間の価値が非常に大きくなったときに何が起こるかということです。あふれますか?精度が失われ、バグが発生しますか?ゲームはただクラッシュするのでしょうか?
回答:
単精度のfloatを使用すると、時間の精度が失われる危険があります。
97日間、精度は最も近い秒まで維持されます。しかし、ゲームでは、フレームの長さのオーダーの精度を重視することがよくあります。
秒単位の単精度浮動小数点値は、約9時間後にミリ秒の精度を失い始めます。
これは、すでに1回のプレイセッションの可能性の範囲外ではありません。また、仕事や学校にいるときや寝ているときにゲームを「AFK」のままにしておくこともできます。(これは、ゲームをテストする一般的な方法が、夜間に実行し、午前中にまだ正しく再生されることを確認することである理由の1つです)
完全にシャットダウンするのではなく、プレイセッション間でゲームが中断および再開されることが多い現代のコンソールでは、ゲームの目から見た「シングルセッション」が短いバーストでプレイされても9時間を超えることは予想外ではありません。
Unity deltaTime
が別の答えのPeterの実験によって裏付けられたより高精度の時間ソースから計算されると仮定するとdeltaTime
、フレームスケールタイミングに依存することは比較的安全です(deltaTime
値を合計することで非常に長い期間を累積することに注意してください-大きな浮動小数点数は、精通したアルゴリズムで補正する場合でも、精度が低下する典型的なレシピです)。
fixedDeltaTime
フレームごとに動的に変更するのではなく、設定した値と同じ値を保持するため、FixedUpdateにタイミング依存の動作を設定して、一貫性をより強力に保証することもできます。deltaTime
これらのメソッドで適切な固定デルタを自動的に返します。固定更新とフレーム更新の間にビート周波数が存在する可能性がありますが、補間によりこれを滑らかにすることができます。
避けたいのは、あるタイムスタンプを別のタイムスタンプから差し引くことで期間を計算することです。数時間のプレイの後、これは壊滅的なキャンセルを引き起こす可能性があり、実行の初期に得られるよりもはるかに精度が低くなります。システムでタイムスタンプの比較が重要な場合は、のSystem.Diagnostics.Stopwatch
代わりに他の方法を使用して、独自の高解像度の時間値を生成できますTime.time
。
floatの最大値は3.40282347 * 10 ^ 38です。これは、秒単位で測定した場合は10 ^ 31年(ミリ秒単位で測定した場合は10 ^ 28年)です。私を信じて、それはあふれません。
表示される唯一のものは不正確です。ただし、単精度浮動小数点数の精度は10進数7〜8桁です。秒を測定するために使用する場合、約194日間正確です。ミリ秒単位で測定する場合、正確な時間はわずか4,5時間です。そのため、必要な精度に完全に依存しており、ミリ秒までの精度を必要とする場合は、別の方法を見つける必要があります(おそらくそうではありません)。
ゲームにはどれくらいの精度が必要ですか?
32ビットの浮動小数点の精度は24ビットです。つまり、時刻tでの精度は±2 -23 ×tです。(これは正確には正確ではありませんが、近いため、正確な詳細はそれほど面白くありません。)
1msの精度が必要な場合、1ms÷2 -23 = 8400 s = 2h 20mの後、32ビットの浮動小数点数は受け入れられなくなります。ほとんどのゲームでは1msの精度は必要ありませんが、音楽アプリケーションでは必要と考えられています。
ゲームが144 Hzモニターで実行され、フレーム精度のグラフィックが必要な場合、1÷144 Hz÷2 -23 = 58000 s = 16hの後に、32ビットの浮動小数点数は受け入れられなくなります。16hはゲームを実行するのに長い時間ですが、考えられないことではありません。私たちのかなりの割合が、一回のストレッチで16時間ゲームを実行したことは間違いないでしょう。その時点で、アニメーションと物理の更新は144Hz未満に削減されます。
Unity Time.deltaTime
が高精度のクロックから計算される場合、それを使用しても完全な精度を得ることができます。これが本当かどうかはわかりません。
Windowsのゲームやその他のプログラムはGetTickCount()
、時間を把握するためによく使用します。32ミリ秒の整数を使用してミリ秒をカウントするため、コンピューターを長時間放置した場合、約50日ごとにラップします。多くのゲームは、50日間の時点でプレイしていた場合、奇妙な方法でハング、クラッシュ、または不正な動作をすると思われます。
Windowsのような整数にGetTickCount()
はオーバーフローのリスクがありますが、UnityのようなフロートにはTime.time
精度が失われるリスクがあります。
他の答えは推測に過ぎないため、単純なUnityプロジェクトを作成し、しばらく実行させました。数時間後、これが結果です:
UnityEngine.Time.time
かなり早く精度を失います。予想どおり、ゲームを4時間実行した後、値は1ミリ秒ジャンプし、その後不正確さが増加します。UnityEngine.Time.deltaTime
Unityが何時間も実行された後でも、最初のミリ秒未満の精度を維持します。したがってdeltaTime
、プラットフォームに依存する高解像度カウンター(通常は10〜1000年後にオーバーフローする)から派生することが実質的に保証され ます。deltaTime
一部のプラットフォームでは、依然として精度を失う小さなリスクが残っています。時間の不正確さは、依存するすべての問題ですUnityEngine.Time.time
。特定の例の1つは、回転(例:風車の回転)UnityEngine.Mathf.Sin(UnityEngine.Time.time*rotationSpeed)
です。これは通常、に基づいています。さらに多くの問題は_Time
、シェーダーによってアニメーションに明示的に使用されることです。気づき始める前に、不正確さはどれほど高い必要がありますか?20〜30ミリ秒の精度(2日間)は、問題を認識し、細心の注意を払っている人々が気付くポイントです。50〜100ミリ秒(5〜10日)で、問題を知らない敏感な人が問題を理解し始めます。200〜300ミリ秒(20〜30日)から、問題は明らかです。
これまでのところ、私はの精度をテストしていない_SinTime
、_CosTime
とUnity_DeltaTime
私はこれらについてコメントすることはできませんので、。
これは、テストに使用したスクリプトです。UI.Text
要素にアタッチされ、プロジェクトのプレーヤー設定により、プロジェクトはバックグラウンドで実行でき、品質設定のVSyncは毎秒Vブランクに設定されます。
public class Time : UnityEngine.MonoBehaviour {
void Start () {
LastTime = (double)UnityEngine.Time.time;
StartTime = System.DateTime.Now;
LastPrintTime = System.DateTime.Now;
}
double LastTime;
System.DateTime StartTime;
System.DateTime LastPrintTime;
void Update () {
double deltaTimeError = (double)UnityEngine.Time.deltaTime - ((double)UnityEngine.Time.time - LastTime);
if (System.DateTime.Now - LastPrintTime > System.TimeSpan.FromMilliseconds(1000))
{
GetComponent<UnityEngine.UI.Text>().text = "StartTime: " + StartTime.ToLongTimeString()
+ "\nCurrentTime: " + System.DateTime.Now.ToLongTimeString()
+ "\n\nTime.deltaTime: " + UnityEngine.Time.deltaTime.ToString("0.000000")
+ "\nTime.time - LastTime: " + ((float)(UnityEngine.Time.time - LastTime)).ToString("0.000000")
+ "\nAbsolute Error: " + System.Math.Abs(deltaTimeError).ToString("0.000E0");
LastPrintTime = System.DateTime.Now;
}
LastTime = UnityEngine.Time.time;
}
}
あなたが0.033203
値について疑問に思っているなら、私は0.033203125
それが実際にであると確信しています。これはのバイナリ浮動小数点表現を持ってい00111101000010000000000000000000
ます。0
仮数部の多くのに注意してください。
回避策
ほとんどのジャンルは回避策を必要としません。ほとんどのプレイヤーは合計100時間もゲームをプレイしません。したがって、問題を解決するためにお金を投資することは、数日間の連続したプレイタイムが経済的に現実的でない場合にのみ気付くでしょう。残念ながら、重大な欠点を伴わずに問題全体を修正する単純な普遍的な回避策は思いつきません。