Unity は、ゲーム開発者にとって強力なツールを提供してきました。その中にはユニークな機能や概念が数多く存在し、これらを理解することがゲーム制作の成功につながります。本記事では、Unity に関連したクイズ10問を用意しました。クイズの内容は、Rigidbody の物理処理、スクリプトライフサイクル、ScriptableObject の活用、UI 設計、オブジェクトプーリング、ガベージコレクション、レイヤー管理、アニメーション遷移、アセット管理など、Unity の基本的な仕組みや設計思想を確認できる問題が中心です。Unity 初心者から上級者まで、幅広いスキルレベルの方に役立つ内容となっています。ゲーム制作に役立つ Unity の知識を深めるため、ぜひこのクイズに挑戦してみてください。
Q1 : Addressables と Resources.Load の違いで正しい説明はどれか? Addressables は Resources フォルダに配置する必要があり、Resources.Load と同じ扱いである Addressables はアドレッシング可能なアセット管理システムで、非同期ロードやメモリ管理、ビルド時のアセット分離をサポートするため大規模プロジェクトで有利である Resources.Load は非同期ロードをネイティブにサポートし、Addressables よりもメモリ管理が簡単である Addressables はエディタでのみ動作し、ビルドには影響を与えない
Addressables はアセットの参照とロードをより柔軟に管理するための公式システムで、アドレッシング可能なキーで非同期ロードを行い、依存関係の解決やキャッシュ、メモリの解放をサポートします。Resources.Load は簡便ですが Resources フォルダ内の全アセットがビルドに含まれ、ランタイムのメモリ管理やロード制御が難しくなるため大規模プロジェクトでは問題になりやすいです。Addressables はリモート配信やシーン分割、メモリ最適化が必要な場合に推奨されます。
Q2 : Awake と Start の呼び出しタイミングの違いとして正しいものはどれか? Awake は Start の後に呼ばれる Awake はスクリプトインスタンスが読み込まれた時に呼ばれ、Start は最初のフレームの前に一度だけ呼ばれる(Awake の後) Start はコンポーネントが無効でも必ず呼ばれる Awake はシーンの全オブジェクトの Start が終わった後に呼ばれる
Awake はスクリプトインスタンスがロードされたタイミングで呼ばれ、依存する参照の初期化に使われます。Start はそのオブジェクトが有効になっている場合に最初のフレームが始まる直前に一度だけ呼ばれ、Awake の後に呼ばれます。Start はコンポーネントが無効だと呼ばれない点に注意が必要です(有効化された時点で呼ばれます)。また Awake は他のオブジェクトの Awake と順序は保証されないため、厳密な初期化順序が必要なら Script Execution Order を使うか遅延初期化を検討します。
Q3 : Unity の Coroutine で yield return new WaitForSeconds(1f) を使した場合の挙動として正しいものはどれか? WaitForSeconds は Time.timeScale に影響されず常に実時間で待機する WaitForSecondsRealtime は Time.timeScale に依存する WaitForSeconds は Time.timeScale の影響を受けるため、timeScale を 0 にすると待機が停止する(ポーズ可能) yield return null は指定秒数待つのに使用される
WaitForSeconds は Unity のゲーム時間(Time.timeScale に依存する)を基準に待機します。つまり Time.timeScale を 0 にすると通常の WaitForSeconds は進行を停止して実質的に待機が止まり、ゲームがポーズ中の処理に使えます。逆に実時間で待ちたい場合は WaitForSecondsRealtime を使います。yield return null は次フレームまで待つことを意味し、秒数指定の待機には使えません。タイムスケールとリアルタイムの違いを理解して適切な待機方法を選ぶことが重要です。
Q4 : ScriptableObject の適切な用途として最も適切なのはどれか? MonoBehaviour の代替としてシーン上に配置してゲームロジックを処理すること ランタイム中にのみ存在し、シーンをまたいで共有できないデータを持つこと ScriptableObject はシリアライズできないため設定を保存できないこと データコンテナとしてアセット化して複数のオブジェクト間で共有したり、設定をエディタ上で保持したりすること
ScriptableObject は軽量なデータコンテナとして設計されており、アセットとして保存してプロジェクト内で共有できます。ゲーム設定やアイテムデータ、ステートマシンの設定など、複数のインスタンスで共有したい不変的なデータを格納するのに適しています。MonoBehaviour のようにシーンにアタッチして振る舞いを持たせるのではなく、メモリ効率が良くエディタで編集可能なアセットとして使える点が利点です。シリアライズ可能であり、ランタイムにインスタンス化することも可能です。
Q5 : Unity UI の Canvas の Render Mode について、Screen Space - Overlay の特徴として正しいものはどれか? UI が常に画面上に直接描画されカメラの影響を受けない UI は指定したカメラの前に配置され、カメラの視錐台に従う UI がワールド空間に配置され 3D オブジェクトと同じ空間で相互作用する Screen Space - Overlay は Canvas を自動的にワールド空間に変換する
Screen Space - Overlay は Canvas を画面座標に固定して直接スクリーン上に描画するモードで、特定のカメラやワールド空間の影響を受けません。HUD や常に画面に固定したい UI に適しています。Screen Space - Camera は指定したカメラを通して描画され、カメラの位置やクリッピングに影響されます。World Space は 3D 空間に配置され、オブジェクトと重なったり物理的に配置したりできます。用途に応じてモードを選び、Canvas Scaler や描画順にも注意します。
Q6 : 大量のプレハブを頻繁に生成・破棄する場面でパフォーマンスを改善する一般的な手法はどれか? Instantiate と Destroy を直接多用すること オブジェクトプーリングを導入して再利用すること 生成を増やして GPU バッチを最大化すること 毎フレーム Resources.Load を使ってプレハブを読み込むこと
頻繁に Instantiate/Destroy を繰り返すとヒープの断片化や GC(ガベージコレクション)トリガー、生成コストが原因でフレームレート低下や一時的なスタッタが発生します。オブジェクトプーリングは生成済みオブジェクトを非表示にして再利用する手法で、生成/破棄のオーバーヘッドと GC 発生を抑えられるためゲームプレイ中のパフォーマンスが安定します。Resources.Load の多用はメモリ管理が難しく、Instantiate/Destroy の乱用は避けるべきです。
Q7 : Unity でランタイム中に大量の短命なマネージドオブジェクトを生成すると起きやすい問題は何か? GPU シェーダーのコンパイルエラーが発生する メモリリークで永続的にメモリが増え続ける(GC は発生しない) ガベージコレクション(GC)によるフレームスパイクやパフォーマンス低下が発生しやすくなる 物理エンジンが不安定になり衝突判定が誤動作する
C# のマネージドオブジェクトを大量に短時間で生成すると、不要になったオブジェクトがヒープに溜まり、定期的にガベージコレクション(GC)が走ります。GC は停止時間や断片化を生じる場合があり、特にメインスレッドで発生するとフレームスパイク(スタッタ)を引き起こし、ゲーム体験に悪影響を与えます。これを防ぐためにはアロケーションを減らす(構造体の活用、StringBuilder、配列再利用、オブジェクトプールなど)ことや、Profiler で割り当てを監視することが重要です。
Q8 : レイヤーと衝突行列(Physics Collision Matrix)を使って特定のオブジェクト群同士の物理衝突を無効にする方法として正しいのはどれか? 各 GameObject のタグを変更して衝突判定を無効にする Physics.IgnoreCollision を使えばレイヤー全体の衝突設定を自動で行える Rigidbody を無効にするとレイヤーの衝突設定が自動で無視される Project Settings の Physics の Layer Collision Matrix を編集するか、スクリプトで Physics.IgnoreLayerCollision を使って制御する
特定レイヤー同士の衝突を制御するには、Project Settings → Physics にある Layer Collision Matrix を編集してレイヤー間の衝突を無効化できます。ランタイムで切り替えたい場合は Physics.IgnoreLayerCollision(int layer1, int layer2, bool ignore) を使う方法が一般的です。Physics.IgnoreCollision は個別の Collider 間で衝突を無視させるために使いますが、レイヤー単位の管理には Layer Collision Matrix や IgnoreLayerCollision を用いるのが効率的で管理もしやすいです。
Q9 : Animator のトランジションで 「Has Exit Time」にチェックを入れるとどうなるか? トランジションは即時に開始され、現在のアニメーション時間に関係なく切り替わる チェックを入れるとトランジションが無効化される トランジションは現在のステートの規格化された再生時間(normalized time)が指定値を超えるまで待機してから遷移が始まる Has Exit Time は AnimatorController では使用できないオプションである
Has Exit Time にチェックが入っていると、トランジションは現在のステートが指定された Exit Time に達するまで待機します。Exit Time は通常ステートの正規化時間(0 から 1 の範囲)で指定され、例えば 0.9 に設定すると現ステートが 90% 再生されるまでトランジションは開始されません。これによりアニメーションの途中で不自然に切り替わるのを防げます。一方チェックを外すと条件が満たされ次第即座にトランジションが開始されます。
Q10 : Rigidbody に力を加えて物理ベースで移動させる処理を毎フレーム行う場合、どのメソッドで行うのが推奨されるか? FixedUpdate Update LateUpdate OnGUI
物理演算(Rigidbody への力や速度の適用)は FixedUpdate 内で行うのが推奨されます。FixedUpdate は物理演算のタイムステップに合わせて一定間隔で呼ばれるため、力の適用や AddForce、Rigidbody.velocity の変更をここで行うと物理シミュレーションが安定します。Update は毎フレーム呼ばれ、フレームレートに依存するため物理処理を入れると挙動が不安定になりやすく、LateUpdate は主にカメラ追従などで使用します。OnGUI は GUI 描画用で物理処理には不適切です。FixedUpdate と物理ステップの関係を理解することが重要です。