ゲームプレイ中に「一時停止」機能を提供することは、現代のゲーム開発において不可欠な要素です。プレイヤーがゲームを中断したり、設定を調整したり、必要に応じて終了したりできるようにすることで、ユーザーエクスペリエンスが大幅に向上します。
この記事では、Unityでプロフェッショナルなポーズメニューを実装する方法を、ステップバイステップで解説します。ESCキーでの一時停止、再開ボタン、終了機能を備えた基本的なポーズシステムの構築から始め、さらに発展的な機能についても触れていきます。
Unityでゲームを一時停止するための基本的なメカニズムは、Time.timeScale
プロパティを操作することです。このプロパティは、ゲーム内時間の進行速度を制御します:
Time.timeScale = 1.0f
- 通常速度(デフォルト)Time.timeScale = 0.0f
- 完全停止(ポーズ状態)Time.timeScale = 0.5f
- 半分の速度(スローモーション)ポーズ状態では、物理演算、アニメーション、時間ベースの処理が停止しますが、入力検出やUIの操作は引き続き機能します。これにより、ポーズメニューのボタンを操作して、ゲームを再開したり終了したりすることが可能になります。
まず、ポーズメニュー用のUIを作成します:
ポーズメニューのCanvasは初期状態で非アクティブ(非表示)にしておきます。
次に、ポーズ機能を管理するC#スクリプトを作成します:
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;
public class PauseMenu : MonoBehaviour
{
[SerializeField] private GameObject pauseMenuUI; // ポーズメニューのUIパネル
[SerializeField] private Button resumeButton; // 再開ボタン
[SerializeField] private Button quitButton; // 終了ボタン
private bool isPaused = false;
private void Start()
{
// パネルを初期状態で非表示に
pauseMenuUI.SetActive(false);
// ボタンにリスナーを追加
resumeButton.onClick.AddListener(ResumeGame);
quitButton.onClick.AddListener(QuitGame);
}
private void Update()
{
// ESCキーでポーズ切り替え
if (Input.GetKeyDown(KeyCode.Escape))
{
TogglePause();
}
}
public void TogglePause()
{
if (isPaused)
{
ResumeGame();
}
else
{
PauseGame();
}
}
private void PauseGame()
{
// ゲーム時間を停止
Time.timeScale = 0f;
// UIを表示
pauseMenuUI.SetActive(true);
// ポーズ状態を更新
isPaused = true;
}
public void ResumeGame()
{
// ゲーム時間を通常に戻す
Time.timeScale = 1f;
// UIを非表示
pauseMenuUI.SetActive(false);
// ポーズ状態を更新
isPaused = false;
}
public void QuitGame()
{
// ゲーム時間を元に戻す
Time.timeScale = 1f;
// アプリケーション終了(エディタでは動作しない)
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
}
// シーンをロードする機能も追加可能
public void LoadMainMenu()
{
Time.timeScale = 1f;
SceneManager.LoadScene("MainMenu"); // メインメニューシーンの名前を指定
}
}
このメソッドは、現在の状態(ポーズ中か通常プレイ中か)を切り替えます。ESCキーが押されたときに呼び出されます。
ゲームを一時停止する主要な処理を行います:
Time.timeScale = 0f
でゲーム内時間を停止ゲームを再開する処理を行います:
Time.timeScale = 1f
でゲーム内時間を通常に戻すゲームを終了する処理を行います:
効果的なポーズメニューを設計するためのヒント:
基本機能を実装したら、以下の機能を追加してポーズメニューを強化することができます:
ポーズメニューに設定パネルを追加し、音量調整、グラフィック設定などのオプションを提供します。
[SerializeField] private Slider volumeSlider;
private void Start()
{
// 既存のコード...
// ボリュームスライダーの初期値設定
volumeSlider.value = AudioListener.volume;
volumeSlider.onValueChanged.AddListener(SetVolume);
}
private void SetVolume(float volume)
{
AudioListener.volume = volume;
}
ポーズメニューからゲームの進行状況を保存できる機能も便利です:
public void SaveGame()
{
// セーブゲーム処理
Debug.Log("ゲームを保存しました");
// 任意: 保存確認メッセージを表示
ShowSaveConfirmation();
}
UIパネルの背景だけでなく、ポーズ中はゲーム画面全体をぼかす効果を追加すると、没入感が高まります。これはポストプロセッシングエフェクト(Blur)を使用して実現できます。
問題: Time.timeScale = 0f
を設定しても、すべてのスクリプト処理が自動的に停止するわけではありません。
解決策1: シングルトンパターンを使用したグローバルなポーズ状態の管理
// PauseManager.cs - シングルトンとして実装
public class PauseManager : MonoBehaviour
{
public static PauseManager Instance { get; private set; }
public bool IsPaused { get; private set; }
private void Awake()
{
if (Instance == null)
{
Instance = this;
DontDestroyOnLoad(gameObject);
}
else
{
Destroy(gameObject);
}
}
public void SetPauseState(bool paused)
{
IsPaused = paused;
Time.timeScale = paused ? 0f : 1f;
}
}
// 他のスクリプトでの使用例
public class EnemyController : MonoBehaviour
{
private void Update()
{
// ポーズ中は処理をスキップ
if (PauseManager.Instance.IsPaused)
return;
// 通常の処理
MoveEnemy();
CheckCollisions();
}
}
解決策2: インターフェースを使用した統一的な一時停止機能
// IPausable.cs - 一時停止可能なオブジェクト用インターフェース
public interface IPausable
{
void OnGamePaused();
void OnGameResumed();
}
// PauseMenu.cs - ポーズ処理の一部を変更
public class PauseMenu : MonoBehaviour
{
// 既存のコード...
private void PauseGame()
{
Time.timeScale = 0f;
pauseMenuUI.SetActive(true);
isPaused = true;
// シーン内のすべてのIPausable実装オブジェクトを検索して通知
IPausable[] pausableObjects = FindObjectsOfType<MonoBehaviour>().OfType<IPausable>().ToArray();
foreach (IPausable obj in pausableObjects)
{
obj.OnGamePaused();
}
}
public void ResumeGame()
{
Time.timeScale = 1f;
pauseMenuUI.SetActive(false);
isPaused = false;
// シーン内のすべてのIPausable実装オブジェクトを検索して通知
IPausable[] pausableObjects = FindObjectsOfType<MonoBehaviour>().OfType<IPausable>().ToArray();
foreach (IPausable obj in pausableObjects)
{
obj.OnGameResumed();
}
}
}
// 実装例
public class EnemyAI : MonoBehaviour, IPausable
{
private bool isPaused = false;
private void Update()
{
if (isPaused)
return;
// 通常のAI処理
}
public void OnGamePaused()
{
isPaused = true;
// 必要に応じて追加の一時停止処理
}
public void OnGameResumed()
{
isPaused = false;
// 必要に応じて追加の再開処理
}
}
解決策3: イベントシステムを使用した方法
// PauseEvents.cs
public static class PauseEvents
{
public static event Action OnGamePaused;
public static event Action OnGameResumed;
public static void TriggerPause()
{
OnGamePaused?.Invoke();
}
public static void TriggerResume()
{
OnGameResumed?.Invoke();
}
}
// PauseMenu.cs内で
private void PauseGame()
{
Time.timeScale = 0f;
pauseMenuUI.SetActive(true);
isPaused = true;
// イベント発行
PauseEvents.TriggerPause();
}
// 各スクリプトで
private void Awake()
{
PauseEvents.OnGamePaused += HandleGamePaused;
PauseEvents.OnGameResumed += HandleGameResumed;
}
private void OnDestroy()
{
PauseEvents.OnGamePaused -= HandleGamePaused;
PauseEvents.OnGameResumed -= HandleGameResumed;
}
private void HandleGamePaused()
{
// 一時停止時の処理
enabled = false; // Monobehaviourを無効化する方法もある
}
private void HandleGameResumed()
{
// ゲーム再開時の処理
enabled = true;
}
問題: Time.timeScale = 0f
を設定しても特定のアニメーションが停止しない。
解決策: Animatorコンポーネントで「Update Mode」を「Normal」から「AnimatePhysics」に変更します。これにより、アニメーションがtime scaleの影響を受けるようになります。
問題: ゲームを一時停止してもBGMや効果音が鳴り続ける。
解決策: Time.timeScaleはオーディオには自動的に影響しないため、明示的に一時停止する必要があります:
[SerializeField] private AudioSource[] sourcesToPause;
private void PauseGame()
{
// 既存のコード...
// すべてのオーディオソースを一時停止
foreach (var source in sourcesToPause)
{
source.Pause();
}
}
private void ResumeGame()
{
// 既存のコード...
// すべてのオーディオソースを再開
foreach (var source in sourcesToPause)
{
source.UnPause();
}
}
問題: モバイルゲームではESCキーが使えない。
解決策: UI上に専用のポーズボタンを追加し、それをタップできるようにします:
[SerializeField] private Button pauseButton;
private void Start()
{
// 既存のコード...
// ポーズボタンのリスナー追加
pauseButton.onClick.AddListener(PauseGame);
}
プロフェッショナルなポーズメニューは、ゲームプレイ体験を大きく向上させる重要な要素です。基本的な実装は比較的シンプルですが、細部にこだわることで、ユーザーフレンドリーで直感的なポーズシステムを構築することができます。
この記事で紹介した手法を基本として、自分のゲームに最適なポーズ機能をカスタマイズしてください。ゲームのジャンルや対象プラットフォームによって、ポーズメニューに必要な機能は変わってくるでしょう。プレイヤーの視点に立ち、使いやすさを優先したデザインを心がけることが成功の鍵です。
この記事は、Unity 2022.3以降のバージョンを前提に作成されています。新しいバージョンでは仕様が変更されている可能性があるため、適宜公式ドキュメントを参照してください。