
いよいよ最終回です。前回まででゲームの中身は完成しました。あとは、遊ぶ人が最初から最後まで迷わずに遊べる形にするだけです。タイトル画面から始まって、終わったら結果が出て、もう一度遊べる。そしてそれを友達に渡せるところまで持っていきます。今回はヴァンサバ風サバイバーゲームのシリーズの11回目(最終回)として、タイトル・リザルト・音を付けて、Windowsで遊べる形にビルドしてみたいと思います!
- シリーズの目次:ヴァンサバ風ゲームの作り方
- 前回:#10 時間で強くなる敵のウェーブを作ろう
今回作るもの
- タイトル画面(「はじめる」「おわる」)
- リザルト(生き延びた時間・とどいたレベル・「もう一度」「タイトルへ」)
- 効果音とBGM
- Windowsのゲーム(.exe)にして、zipで配れる形にする
作るスクリプトは3つ、消すスクリプトが2つです。
| スクリプト | 役割 | 付ける場所 |
|---|---|---|
| TitleView(新しく作る) | 「はじめる」でゲームへ、「おわる」で終了 | TitleのCanvas |
| ResultView(新しく作る) | やられたとき・クリアしたときの結果画面 | GameのCanvas |
| SoundPlayer(新しく作る) | 効果音とBGMを鳴らす | SoundPlayer |
| GameOverView・GameClearView(消す) | ResultViewにまとめます | — |
前回の続きから
- Unityのバージョンは6.3 LTS
- 記事作成時点では6000.3.22f1で確認しています
- #10の状態:時間で敵が強くなり、10分でクリアになる
シーンの切り替えは8-3 シーンの切り替え、音は12-1 音を鳴らそうで紹介しています。
リザルトを作ろう
先に結果画面から作ります。#9のゲームオーバーと#10のクリアは、出すパネルが違うだけのほとんど同じスクリプトでした。前回「違いがはっきりしたらまとめる」と書いたので、ここで1つにします。
SurvivorsLike/Scriptsに「ResultView」を作る
using System;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
// やられたとき・クリアしたときの結果画面
public class ResultView : MonoBehaviour
{
[SerializeField] private PlayerHealth playerHealth;
[SerializeField] private WaveManager waveManager;
[SerializeField] private PlayerLevel playerLevel;
[SerializeField] private GameObject panel;
[SerializeField] private TextMeshProUGUI titleText;
[SerializeField] private TextMeshProUGUI detailText;
[SerializeField] private Button retryButton;
[SerializeField] private Button titleButton;
private void OnEnable()
{
playerHealth.Died += ShowGameOver;
waveManager.Cleared += ShowClear;
retryButton.onClick.AddListener(Retry);
titleButton.onClick.AddListener(ToTitle);
}
private void OnDisable()
{
playerHealth.Died -= ShowGameOver;
waveManager.Cleared -= ShowClear;
retryButton.onClick.RemoveListener(Retry);
titleButton.onClick.RemoveListener(ToTitle);
}
private void ShowGameOver()
{
Show("GAME OVER", new Color(0.9f, 0.25f, 0.2f));
}
private void ShowClear()
{
Show("CLEAR!", new Color(1f, 0.85f, 0.2f));
}
private void Show(string message, Color color)
{
titleText.text = message;
titleText.color = color;
detailText.text = $"生き延びた時間 {TimeSpan.FromSeconds(waveManager.Elapsed):mm\\:ss}\n"
+ $"とどいたレベル {playerLevel.Level}";
panel.SetActive(true);
Time.timeScale = 0f;
}
private void Retry()
{
Time.timeScale = 1f;
SceneManager.LoadScene("Game");
}
private void ToTitle()
{
Time.timeScale = 1f;
SceneManager.LoadScene("Title");
}
}
- 2つの入口、1つの出口
DiedとClearedは別のイベントですが、どちらも「文字と色を変えてパネルを出す」だけです- 違うのは見出しの文字と色だけなので、
Showに渡す形にまとめました
- まとめる時期
- #9の時点でまとめようとしたら、「クリアのときは何を出す?」が決まっていないので、たぶん余計な作りになっていました
- 違いがはっきりしてからまとめると、こうして短く書けます
- 読み込むシーンは名前で指定
"Game"と"Title"は、SurvivorsLike/Scenesのシーンのファイル名です。名前を変えたときはここも直します
パネルを1つにする
- Hierarchyで
GameOverPanelを選び、名前を「ResultPanel」にする- 中の
GameOverTextを「ResultTitle」にリネーム - 中の
RetryButtonはそのまま ResultPanelの上で右クリック>UI>Text – TextMeshPro、名前を「ResultDetail」にする- Pos Y:0、Width:800、Height:160、Font Size:40、Alignment:中央・中央
RetryButtonをCtrl+Dで複製して「TitleButton」にする- Pos Y:-250、中のTextを「タイトルへ」にする
- 中の
ClearPanelは削除する- CanvasからGameOverViewとGameClearViewを削除し、Add Component>ResultView
- 8つの欄を入れる
- Player Health:Player、Wave Manager:WaveManager、Player Level:Player
- Panel:ResultPanel、Title Text:ResultTitle、Detail Text:ResultDetail
- Retry Button:RetryButton、Title Button:TitleButton
- 8つの欄を入れる
SurvivorsLike/ScriptsのGameOverViewとGameClearViewを削除する

タイトル画面を作ろう
シーンを作る
SurvivorsLike/Scenesで右クリック>Create>Scene、名前を「Title」にする- ダブルクリックで開いて、次を置く
- Hierarchyで右クリック>UI>Canvas(#6と同じ設定:Screen Space – Overlay、Scale With Screen Size、1920×1080)
- Canvasの上にUI>Text – TextMeshProを置き、名前を「TitleText」、Textを「スライムちゃんの\nおかしなサバイバー」、Font Size:90、Pos Y:200
- Width:1400、Height:320、Alignment:中央・中央、Color:こい茶色
- UI>Button – TextMeshProを2つ置き、「StartButton」(Text:はじめる、Pos Y:-80)と「QuitButton」(Text:おわる、Pos Y:-220)にする
- どちらもWidth:480、Height:120、中のTextのFont Size:44
- Main CameraのBackgroundを明るいクリーム色にしておくと、Gameシーンの工房の床と雰囲気がそろいます
- 一緒に作られたEventSystemは、#6と同じくInput System UI Input Moduleが付いていることを確かめる
スクリプト
SurvivorsLike/Scriptsに「TitleView」を作る
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;
// タイトル画面。ゲームを始める・終わる
public class TitleView : MonoBehaviour
{
[SerializeField] private Button startButton;
[SerializeField] private Button quitButton;
private void OnEnable()
{
startButton.onClick.AddListener(StartGame);
quitButton.onClick.AddListener(Quit);
}
private void OnDisable()
{
startButton.onClick.RemoveListener(StartGame);
quitButton.onClick.RemoveListener(Quit);
}
private void StartGame()
{
SceneManager.LoadScene("Game");
}
private void Quit()
{
// エディタでは再生が止まり、ビルドしたゲームでは本当に終了する
#if UNITY_EDITOR
UnityEditor.EditorApplication.isPlaying = false;
#else
Application.Quit();
#endif
}
}
- CanvasにTitleViewを付けて、2つのボタンを入れる
- Start Button:StartButton、Quit Button:QuitButton
シーンはScene Listに入れておかないと、SceneManager.LoadSceneで読み込めません
エディタで「はじめる」や「タイトルへ」を押して、couldn't be loaded because it has not been added to the build settingsのようなエラーが出たらこれです。File>Build ProfilesのScene Listに、ProjectウインドからTitleとGameをドラッグして入れておきます。並び順は、このあとの「Windowsのゲームにしよう」で整えます。
Application.Quit()は、エディタでは何も起きません
再生中に押しても止まらないので「効いていない」と思いがちですが、ビルドしたゲームでは正しく終了します。
#if UNITY_EDITORで囲んだ部分は、エディタでだけコンパイルされます。ここでは、エディタなら再生を止める処理に切り替えています。この書き方をしないと、UnityEditorはビルドに含まれないのでビルドのときにエラーになります。

効果音とBGMを付けよう
音は#1でダウンロードした配布素材のzipに入っていて、取り込んでいればSurvivorsLike/Audioにあります(se_levelup / se_damage / se_gameover / se_clear / bgm_battle)。見当たらないときは、zipの中のSurvivorsLike/Audioを同じ場所に入れてください。
- Gameシーンを開き直す
- Hierarchyで右クリック>Create Empty、名前を「SoundPlayer」にする
- Add Component>Audio Sourceを2つ付ける
- 1つ目(効果音用):Play On Awake のチェックを外す
- 2つ目(BGM用):Audio Resource:bgm_battle、Loop にチェック、Volume:0.4
SurvivorsLike/Scriptsに「SoundPlayer」を作る
using UnityEngine;
// ほかのスクリプトが出す「合図」を聞いて、音を鳴らす
public class SoundPlayer : MonoBehaviour
{
[SerializeField] private PlayerLevel playerLevel;
[SerializeField] private PlayerHealth playerHealth;
[SerializeField] private WaveManager waveManager;
[SerializeField] private AudioSource seSource;
[SerializeField] private AudioClip levelUpClip;
[SerializeField] private AudioClip damageClip;
[SerializeField] private AudioClip gameOverClip;
[SerializeField] private AudioClip clearClip;
private void OnEnable()
{
playerLevel.LevelUp += PlayLevelUp;
playerHealth.Damaged += PlayDamage;
playerHealth.Died += PlayGameOver;
waveManager.Cleared += PlayClear;
}
private void OnDisable()
{
playerLevel.LevelUp -= PlayLevelUp;
playerHealth.Damaged -= PlayDamage;
playerHealth.Died -= PlayGameOver;
waveManager.Cleared -= PlayClear;
}
private void PlayLevelUp()
{
seSource.PlayOneShot(levelUpClip);
}
private void PlayDamage()
{
seSource.PlayOneShot(damageClip);
}
private void PlayGameOver()
{
seSource.PlayOneShot(gameOverClip);
}
private void PlayClear()
{
seSource.PlayOneShot(clearClip);
}
}
- HierarchyでSoundPlayerを選び、欄を入れる
- Player Level・Player Health:Player、Wave Manager:WaveManager
- Se Source:1つ目(効果音用)のAudio Source
- 同じオブジェクトに2つあるので、Inspectorから上のAudio Sourceの見出しを欄にドラッグします
- Level Up Clip:se_levelup、Damage Clip:se_damage、Game Over Clip:se_gameover、Clear Clip:se_clear
このスクリプトを足すのに、ほかのスクリプトは1行も直していません。PlayerLevelもPlayerHealthもWaveManagerも、「レベルが上がった」「ダメージを受けた」と言っているだけで、誰が聞いているかを知らないからです。
もしPlayerHealthの中に直接audioSource.PlayOneShot(...)と書いていたら、HPの計算と音が混ざって、片方を直すたびにもう片方を壊す心配をすることになります。あとから機能を足しやすいかどうかは、こういう所で決まります。
スライム音が付いただけで、急にゲームっぽくなりました!



でしょ?音は最後に足すものだと思われがちだけど、足しやすい形にしておくのが本当の準備なんだよ
Windowsのゲームにしよう
ビルドの基本は10-1 ビルドの基本と10-2 はじめてのビルドにまとめてあるので、ここではこのゲームで必要なところだけ書きます。
- File>Build Profilesを開く
- Scene Listに2つのシーンを、Titleが上、Gameが下の順で並べる
- 一番上のシーンが、起動したときに最初に開くシーンです
- Player Settingsを開いて設定する
| 項目 | 値 |
|---|---|
| Product Name | スライムちゃんのおかしなサバイバー |
| Company Name | 自分の名前でOK |
| Default Icon | icon_whipperなど好きな絵 |
| Fullscreen Mode | Windowed |
| Default Screen Width / Height | 1280 / 720 |
| Resizable Window | チェックを入れる |
- 全画面ではなく、1280×720のウインドウで起動するようにしています。遊ぶ人の画面の大きさが分からないので、まずは小さめのウインドウが無難です
- Fullscreen Modeなどは、Player SettingsのResolution and Presentationの中にあります
- Buildを押して、空のフォルダを選ぶ(例:
Build/SlimeSurvivors)Assetsの中やプロジェクトのフォルダを選ぶと、ビルドの成果物がプロジェクトに混ざって大変なことになります。必ず新しいフォルダを作ってください
友達に配れる形にしよう
ビルドが終わると、選んだフォルダの中はこうなっています。
SlimeSurvivors/
├── SlimeSurvivors.exe ← これを起動する(保存するときに付けた名前)
├── UnityPlayer.dll
├── UnityCrashHandler64.exe
├── D3D12/
├── MonoBleedingEdge/
├── SlimeSurvivors_Data/ ← ゲームの中身が全部入っている
└── スライムちゃんのおかしなサバイバー_BurstDebugInformation_DoNotShip/ ← 配らない
.exeだけをコピーしても動きません。_DataフォルダとUnityPlayer.dllが必要です_BurstDebugInformation_DoNotShipは消してから配ります。名前のとおり「配らないで」というフォルダで、デバッグ用の情報が入っています- このフォルダだけ、
.exeではなくProduct Nameの名前が付きます。日本語の名前にしていると日本語のフォルダになります
- このフォルダだけ、
- 残りをフォルダごとZIPに圧縮して渡します。相手は展開して
.exeをダブルクリックするだけです



「DoNotShip」って書いてあると、うっかり配ったら怒られそうでドキッとしますね・・・
個人が作った.exeは署名が無いので、初めて起動するときにSmartScreenの警告が出ます。「詳細情報」>「実行」で起動できます。
渡すときに、この一言を添えておくと親切です。怪しいから出ているのではなく、「誰が作ったか証明されていない」から出ているだけです。


全部つながったか確認しよう
最後に、シリーズを通しての答え合わせです。ビルドしたゲームで確認してください。
全11回の答え合わせ
- #1 スライムちゃんが8方向に向きを変えて歩く
- #2 工房の外に出られない(見えない壁がある)
- #3 敵が画面の外から出てきて追いかけてくる。大量に出ても重くならない
- #4 一番近い敵に計量スプーンが自動で飛ぶ
- #5 ホイッパーが3秒回って3秒休む
- #6 倒した敵が金平糖を落とし、拾うとレベルが上がる
- #7 レベルアップでゲームが止まり、3択から選ぶと強くなる
- #8 攻撃が当たるとダメージの数字が出て、敵がのけぞる
- #9 敵に触れられるとHPが減り、0でゲームオーバー
- #10 時間で敵の種類と数が変わり、10分でクリア
- #11 タイトルから始まり、結果が出て、タイトルに戻れる
1つでも「あれ?」と思ったら、その回に戻ってみてください。どこで止まったかが分かれば、直す場所はだいたい1か所です。
シリーズのまとめ
| 回 | 作ったもの | 覚えた機能 |
|---|---|---|
| #1 | 動かす | Input System・8方向のアニメ・Cinemachine |
| #2 | 床と壁 | Tilemap・Collider |
| #3 | 敵 | ObjectPool・レイヤー |
| #4 | 自動で攻撃 | 当たり判定・最近接の探索 |
| #5 | 武器のデータ | ScriptableObject・継承 |
| #6 | 経験値 | プール・Canvas・ゲージ |
| #7 | 3択の強化 | 親クラスの活かし方・timeScale |
| #8 | 手応えの演出 | コルーチン |
| #9 | HPとゲームオーバー | 無敵時間・イベント |
| #10 | ウェーブ | データで難易度を作る |
| #11 | タイトルとビルド | シーン遷移・音・配布 |
次にやってみること
- 武器と強化を増やす。#5・#7の作りなら、クラスとアセットを1つ足すだけです
- ボスを出す。#10の「ボスを出したい人へ」に方針を書きました
- スマホ向けにする。画面を縦にして、移動をバーチャルパッドに変えます
- 絵を差し替える。配布素材は仮の絵なので、自分の絵にすると一気に自分のゲームになります
作り直すなら、ここから
Enemy.Spawnの引数が5つになったのが、このゲームでいちばん重くなった所でした。「敵に渡すもの」を1つのクラスにまとめると、これ以上増えてもSpawnの形を変えずに済みます。
実際に作り切ってから「ここが重かった」と分かるのが普通なので、最初から完璧な形を目指さなくて大丈夫です。
あとがき
全11回、おつかれさまでした!1本の動く2Dゲームを、最初から配れる形まで作り切れたと思います。このシリーズで使った機能は、どれも別のゲームでもそのまま使えるものばかりです。ぜひ次は、自分の好きなお菓子や自分の絵で、自分だけのサバイバーゲームを作ってみてください。感想や「ここで詰まった」があれば、ぜひ教えてもらえると嬉しいです!



完成したゲームは、ぜひ友達にも遊んでもらってね!
コメント