Update 関数を使用すると、定期的にスクリプトからの入力やその他のイベントをモニターして、適切な処置を取ることができます。たとえば、“forward” キーが押された場合、キャラクターを動かすかもしれません。このような時系列のアクションを取り扱う場合、ゲームのフレームレートおよびアップデート関数を呼び出す間隔の時間はどちらも一定ではないという重要なことを覚えておいてください。
これの一例として、1つのフレームごとに、前方に徐々にオブジェクトを動かす作業を検討してください。最初は、各フレームで一定の距離にオブジェクトを移したように見えるかもしれません。
//C# の例
using UnityEngine;
using System.Collections;
public class ExampleScript : MonoBehaviour {
public float distancePerFrame;
void Update() {
transform.Translate(0, 0, distancePerFrame);
}
}
//JS の例
var distancePerFrame: float;
function Update() {
transform.Translate(0, 0, distancePerFrame);
}
しかし、フレーム時間が一定でないとすると、オブジェクトは不規則な速度で移動しているように見えます。フレーム時間が 10 ミリ秒なら、オブジェクトは distancePerFrame によって100分の1秒前進します。しかし、フレーム時間が 25 ミリ秒に増加した場合(CPU 負荷のため)、それは1秒につき40回前進することになり、より少ない距離をカバーするだけです。その解決方法は、Time.deltaTime プロパティーから読み取ったフレーム時間によって移動の大きさをスケーリングすることです。
//C# の例
using UnityEngine;
using System.Collections;
public class ExampleScript : MonoBehaviour {
public float distancePerSecond;
void Update() {
transform.Translate(0, 0, distancePerSecond * Time.deltaTime);
}
}
//JS の例
var distancePerSecond: float;
function Update() {
transform.Translate(0, 0, distancePerSecond * Time.deltaTime);
}
移動は現在、distancePerSecond ではなく distancePerFrame として与えられていることに注意してください。フレームレートが変化すると、移動ステップの大きさはそれに応じて変わりますので、オブジェクトの速度は一定になります。
メインフレームアップデートとは異なり、Unity のフィジクスシステム does は、固定タイムステップに働きます。それはシミュレーションの正確さと一貫性にとって重要です。フィジクスのアップデート開始時に、Unity は最後のフィジクスの更新が終わったときの固定タイムステップ値を加算して“alarm”を設定しておきます。フィジクスシステムは、アラームが消えるまで計算を実行します。
あなたは Time Manager から固定タイムステップのサイズを変更することができます。スクリプトが使用する Time.fixedDeltaTime プロパティーからそれを読むことができます。タイムステップのための低い値は、より頻繁にフィジクスのアップデートがかかることに注意してください。より正確なシミュレーションは、より大きな CPU 負荷のコストがかかります。フィジクスエンジンに高い要求をしない限り、デフォルトの固定タイムステップを変更する必要はありません。
固定タイムステップは、リアルタイムで物理シミュレーションの正確さを保持します。しかし、ゲームでフィジクスを多用する場合、場合によっては問題を引き起こす可能性があり、ゲームプレイ時のフレームレートも低くなってしまいます(ゲームのオブジェクト数が多いため)。主なフレーム・アップデート処理は、通常のフィジクスアップデートの間に“詰め込む”必要があります。実行する処理がたくさんある場合は、いくつかのフィジクスアップデートは、ひとつのフレームの間に行うことができます。フレームが始まるとき、オブジェクトの位置や他の特性がフレームの開始時に凍結され、頻繁に更新されるフィジクスの同期から抜け出すことができます。
CPU には十分な処理能力が有りますが、 Unity には、フレーム処理が追いつくよう効果的にフィジクスの時間を遅らせるオプションがあります。 Maximum Allowed Timestep (Time Managerの中にあります)設定は、Unity が処理するフィジクスの消費時間に制限をかけ、与えられたフレームアップデートの間に FixedUpdate をコールします。フレームアップデートの処理が Maximum Allowed Timestep よりも長くかかる場合は、フィジクスエンジンは、“stop time”し、フレーム処理が追いつけるようにします。フレームアップデートが完了すると、フィジクスは、停止直後の状態から再開されます。結果的には、リジッドボディはその時だけ少し遅れてしまい、完全にリアルタイムでは動きません。ですが、フィジクス“クロック”は、遅延時間を省いて、それらを追跡しています。フィジクスの時間の遅延は通常は目立たず、ゲームプレイのパフォーマンスに対して許容できるトレードオフです。
“bullet-time”などのような特殊効果のために、アニメーションやスクリプトの応答の低下が起きたとき、ゲームの時間の経過を遅くすると便利な場合が時々あります。さらに、あなたは時々ゲームを中断したときのように、完全にゲーム時間を凍結したいかもしれません。Unity は、ゲーム時間がリアルタイムと比較してどのように進行するかについて制御する time Scale プロパティーを持っています。スケールが1.0に設定されている場合、ゲームの時間は実際のリアルタイムに一致します。0.5の値がゲームプレイを半分の速度まで遅くする一方、2.0の値は Unity で二倍の速さで時間を経過させることができます(つまり、アクションは、高速化されます)。0 の値は時間を完全に“停止”させます。タイムスケールで遅い実行を実際に行いませんが、Time.deltaTime と Time.fixedDeltaTime を経由して Update と FixedUpdate 関数に報告される時間ステップを変更することに注意してください。Update 関数は、ゲーム時間が遅くなるとき通常より頻繁に呼び出される可能性が高いですが、deltaTime ステップを伝えることでおのおののフレームは、簡単に減少されます。ゲームが中断されるとき、たとえば、正常なインタラクションで GUI を示すことができるように、他のスクリプトの機能はタイムスケールに影響を受けません。
Time Manager は、グローバルにタイムスケールを設定できるようにするプロパティーを持っていますが、一般的に、Time.timeScale プロパティーを使用するスクリプトから値を設定すると、より便利です。
//C#の例
using UnityEngine;
using System.Collections;
public class ExampleScript : MonoBehaviour {
void Pause() {
Time.timeScale = 0;
}
void Resume() {
Time.timeScale = 1;
}
}
//JS の例
function Pause() {
Time.timeScale = 0;
}
function Resume() {
Time.timeScale = 1;
}
タイムマネジメントの非常に特別なケースは、あなたがゲームプレイをビデオとして記録したいケースです。スクリーンイメージを保存する作業は、かなりの時間がかかるため、通常のゲームプレイ中にこれを行おうとすると、ゲームの通常のフレームレートが大幅に削減されてしまいます。これではゲームの真の性能を反映していない動画になってしまいます。
幸いなことに、Unity はこの問題を回避することができるCapture Framerateプロパティーを提供しています。プロパティーの値が 0 以外の値に設定されている場合、ゲームタイムは遅くなります。そして、フレームアップデートは、正確な一定の間隔で発行されます。フレーム間の間隔は、1/(Time.captureFramerate) に等しく、5.0に値が設定されて場合、更新が1/5秒ごとに発生します。フレームレートを効果的に減らす要求では、スクリーンショットを保存する Update 関数や、他の操作を実行する時間が与えられます。
//C# の例
using UnityEngine;
using System.Collections;
public class ExampleScript : MonoBehaviour {
//スクリーンショットシーケンスとしてフレームをキャプチャ。
//画像はPNGファイルとしてフォルダーに格納。これらの画像は
// 画像ユーティリティソフトウェア (QuickTime Pro など) で動画と統合されます。
// スクリーンショットを格納するフォルダー。
// フォルダーが既存の場合、数を加え空のフォルダーを作ります。
string folder = "ScreenshotFolder";
int frameRate = 25;
void Start () {
// 再生のフレームレートを設定 (これ以降は、実際の時間はゲームの時間と関連しません)
Time.captureFramerate = frameRate;
// フォルダーを作成
System.IO.Directory.CreateDirectory(folder);
}
void Update () {
// ファイル名をフォルダー名に追加 (形式は "0005 shot.png")
string name = string.Format("{0}/{1:D04} shot.png", folder, Time.frameCount );
// 指定したファイルにスクリーンショットをキャプチャ
Application.CaptureScreenshot(name);
}
}
//JS の例
//スクリーンショットシーケンスとしてフレームをキャプチャ
//画像はPNGファイルとしてフォルダーに格納。これらの画像は
// 画像ユーティリティソフトウェア (QuickTime Pro など) で動画と統合されます。
// スクリーンショットを格納するフォルダー。
// フォルダーが既存の場合、数を加え空のフォルダーを作ります。
var folder = "ScreenshotFolder";
var frameRate = 25;
function Start () {
// // 再生のフレームレートを設定 (これ以降は、実際の時間はゲームの時間と関連しません)
Time.captureFramerate = frameRate;
// フォルダーを作成
System.IO.Directory.CreateDirectory(folder);
}
function Update () {
// ファイル名をフォルダー名に追加 (形式は "0005 shot.png")
var name = String.Format("{0}/{1:D04} shot.png", folder, Time.frameCount );
// 指定したファイルにスクリーンショットをキャプチャ
Application.CaptureScreenshot(name);
}
一般的にこの技術を使用してビデオを記録するのは非常によさそうですが、遅くなってくると、ゲームをプレイすることが劇的に難しくなってきます。あなたは、テストプレーヤーの仕事を過度に難しくすることなく十分なレコーディング時間を可能にするために Time.captureFramerate 値を試してみる必要があるかもしれません。