U
タブ 01基礎11 レッスン — タップで開く
10 / 11 · 16 分
基礎

画面、パネル、そして GameManager

ここまでのプロジェクト

Assets/

Scenes/

Arena.unity

GameManagerKnightMain CameraCanvasHudPanelPausePanel
Intro.unity

Scripts/

CharacterSwitcher.csIntroScreen.csGameManager.cs

Audio/

arena music (.ogg)click (.wav)

すでにあるものこのレッスンで追加

どんなゲームにも、世界の一部ではないオブジェクトがひとつあります。あなたが見ているものと、スピーカーから出てくるものを決める存在です。それを書く前に、二つの言葉をもう混同しないでください——Unity ではまったく別のものなので。

Screen と panel は別の言葉

✓ Screen

SceneManager.LoadScene("Arena")

Unity のシーンそのもので、各自の .unity ファイルを持ちます。読み込むと今のシーンの中身はすべて破棄され、新しいシーンをディスクから組み立てます。まっさらにやり直したいときに使う方法です。

✓ Panel

pausePanel.SetActive(true)

今いるシーンの内側にある GameObject。切り替えても他は何も変わりません——床もブロックも Knight も、あった場所にそのまま残ります。ゲームの上に載せるものはすべてこちらを使います。
  • 場所も世界も違う → screen。イントロはアリーナではないので、専用のシーンファイルを持ちます。

  • 同じ場所で、何かを上に乗せる → panel。一時停止はアリーナの中で起きることなので、アリーナの中の GameObject です。

  • シーン切り替えをまたいで何かを残しておくのに DontDestroyOnLoad が必要なら、ほぼ確実にあなたが必要としていたのは panel です。

アニメーション図

screen は二つ、それぞれがシーンファイル。panel は二つで、どちらも二つ目のシーンの中に住んでいます。下のアリーナは動きません。

ステップ 1 — イントロの screen、専用のシーン

全コースを通じて、二つ目のシーンを作る価値がある唯一の場所です。イントロには床もキャラも物理もないので、一瞬で読み込まれ、離れた瞬間に残しておくものは何ひとつありません。

  1. 1

    File▸New Scene → Basic (URP) を選び、続けて File▸Save As → Assets/Scenes/Intro.unity。

  2. 2

    GameObject▸UI▸Canvas を追加し、ゲーム名を書いた Text と、PLAY と表記した UI▸Button を置きます。

  3. 3

    空のオブジェクトに Intro と名前を付け、IntroScreen.cs をアタッチし、ボタンの On Click () を LoadArena に向けます。

IntroScreen.cs — the entire intro screen
using UnityEngine;
using UnityEngine.SceneManagement;

public class IntroScreen : MonoBehaviour
{
    public void LoadArena()
    {
        SceneManager.LoadScene("Arena");
    }
}

ステップ 2 — アリーナ全体から見える manager

Arena.unity に戻ります。ボタンは manager に一時停止を伝え、Knight に付けたスクリプトは攻撃が当たった音を出したい、となります。どちらも manager を持ってはいません。使うたびに FindObjectOfType で探しに行くのは遅いし間違いやすい。static フィールドひとつで片付きます。

GameManager.cs — attach to the GameManager object you made last lesson
using UnityEngine;
using UnityEngine.SceneManagement;

// Panels, not screens: both of these live inside Arena.unity.
public enum GamePanel { Hud, Pause }

public class GameManager : MonoBehaviour
{
    // The whole arena reaches the manager through this one field.
    public static GameManager I;

    void Awake()
    {
        I = this;
    }
}

ステップ 3 — アリーナの中の二つの panel

  1. 1

    GameObject▸UI▸Canvas。Unity がその隣に EventSystem を自動で追加します——触らないでください。ボタンがクリックできるのはこれのおかげです。

  2. 2

    Canvas の中に空のオブジェクトを二つ作ります:HudPanel と PausePanel。どちらもただの入れ物です。

  3. 3

    HudPanel には再生中に見せたいものを入れます——0 と書かれた Text で十分です。PausePanel には全屏の暗い Image、PAUSED の文字、RESUME ボタン、MENU ボタンを入れます。

GameManager.cs — add these to the class
[Header("Panels")]
public GameObject hudPanel;
public GameObject pausePanel;

public GamePanel current { get; private set; }

void Start()
{
    ShowPanel(GamePanel.Hud);   // the arena starts playable
}

public void ShowPanel(GamePanel next)
{
    current = next;
    hudPanel.SetActive(next == GamePanel.Hud);
    pausePanel.SetActive(next == GamePanel.Pause);

    // A pause panel that does not stop time is just a picture.
    Time.timeScale = next == GamePanel.Pause ? 0f : 1f;
}

void Update()
{
    if (Input.GetKeyDown(KeyCode.Escape))
        ShowPanel(current == GamePanel.Pause ? GamePanel.Hud : GamePanel.Pause);
}

// Leaving the arena is a screen change, so it goes through SceneManager.
public void BackToIntro()
{
    Time.timeScale = 1f;
    SceneManager.LoadScene("Intro");
}
  • panel につき一行、比較が判定してくれます。三つ目の panel を足すときも一行追加するだけで、if の連鎖をもう一つ書く必要はありません。

  • SetActive(false) はその panel の Update も止めるので、隠れている panel にフレームごとのコストはかかりません。

  • RESUME ボタンは ShowPanel に、MENU ボタンは BackToIntro に向けます。片方は panel の切り替え、もう片方は screen の読み込み——同じメニューの中の、まったく違う二種類の移動です。

ステップ 4 — ループする音楽、しないクリック音

同じ GameManager オブジェクトに AudioSource を二つ置きます。片方は Loop にチェックを入れて音楽を鳴らし、もう片方は何も持たず、必要なときに一度だけ音を発します。

GameManager.cs — the sound half
[Header("Sound")]
public AudioSource musicSource;   // tick Loop on this one
public AudioSource sfxSource;
public AudioClip arenaMusic;
public AudioClip clickClip;

public void PlayMusic(AudioClip track)
{
    // Asking for the track that is already playing must not restart it.
    if (musicSource.clip == track && musicSource.isPlaying) return;

    musicSource.clip = track;
    musicSource.Play();
}

public void PlaySfx(AudioClip clip)
{
    if (clip != null) sfxSource.PlayOneShot(clip);
}

音が実際に出ていく場所

  • AudioListener は耳の役割で、シーンに必ず一つあるべきものです。レッスン 06 で Unity が Main Camera に関連付けました——そのままにして、Intro.unity にも自分専用の AudioListener があることを覚えておいてください。

  • 音楽は screen の切り替えを生き残りません。Intro を読み込むとアリーナの AudioSource はシーンのほかのすべてと一緒に破棄されます。これが screen の代償であり、安易に作らない理由です。

  • clip は Assets/Audio に入れます——レッスン 05 で作ったフォルダです。音楽は .ogg、短い効果音は .wav。

  • 両方の source で Play On Awake のチェックを外してください。音がいつ始まるかを決めるのは Inspector ではなく manager です。

ステップ 5 — つなぎ込む

  1. 1

    GameManager を選んで Audio Source を二つ追加します。一つ目に Loop をチェックし、両方の Play On Awake のチェックを外してください。

  2. 2

    Inspector で HudPanel と PausePanel をそれぞれのスロットに、二つの Audio Source を Music Source と Sfx Source に、音声を Arena Music と Click Clip にドラッグします。

  3. 3

    ShowPanel の直後、Start() に PlayMusic(arenaMusic); を追加します。アリーナが開いた時点で音楽がもう鳴っている状態になります。

  4. 4

    アリーナからではなく、Intro.unity を開いてそこから Play を押してください。プレイヤーが出会う順番はその通りで、Build Settings のリストが壊れているのに気づける唯一の方法でもあります。

  • ✓Intro.unity から再生し、PLAY で音楽の鳴っているアリーナに移る。
  • ✓Escape で PausePanel が出て Knight が動きを止め、もう一度 Escape で再開する。
  • ✓panel を切り替えている間、床・ブロック・三人のキャラは一切動かない。
  • ✓MENU でイントロに戻り、着いた先のイントロが固まっていない。