Unity で 3D ゲームを作る:5 ステージ・1 プロジェクト
Unity でゲームを作りたいのですが、何から始めますか?
Knight・Mage・Archer が同じアリーナで戦う 3D アクションゲームを、5 ステージで空のプロジェクトから実機の APK まで作り切ります。コードの前提は不要。各ステージの終わりに押して試せるものが残るので、やり直しではなく完成に向かいます。
これが通しルートです。片方の端は空の Unity プロジェクト、もう一方の端には 3D アクションゲーム —— アリーナ 1 つで Knight・Mage・Archer が戦う —— が自分のスマホに入っています。ステージは 5 つ、プロジェクトは最初から最後まで 1 つ。始める前にコードを知っている必要はありません。各ステージの終わりには、見て押せるものが必ず残るので、「本当に動いてるのかな」と曖昧になる瞬間がありません。
最初のゲームが終わらない理由は、難しさであることはほとんどありません。画面のプロジェクトが自分が欲しいものと少し違うので、やり直し始めるからです —— エンジンを乗り換え、もっと大きなアイデアを掲げ、誰も最後まで辿り着けないチュートリアルシリーズの 3 本目へ。作り切ったプロジェクト 1 つは、放り出した 10 個より多くを教えます。理由は単純です —— 面倒な「尾部」、ビルド設定、誰も試していない解像度、敵が 3 体出た瞬間に 30 へ落ちるフレームを通過させられるのは、完成させたときだけだからです。
準備は 60 秒
- 1
Unity Hub > Installs > Install Unity で Unity 6 LTS を選びます。モジュール一覧で Android Build Support と Microsoft Visual Studio Community にチェックを付けてください。Hub がエディタと IDE をまとめて入れるので、Visual Studio を個別に設定する工程はそもそも存在しません。
- 2
New project でテンプレートは Universal 3D、SSD 上に置いて、名前は短くスペースなし。Android モジュールはここで入れてください —— 5 ステージ後に を開き直すのは実質入れ直しで、ステージ 5 は見落としたことに気づく場所としては最悪です。
- 3
エディタを初めて開くとログインを求められるので、無料の Unity ID でサインインします。有効になるのは Personal ライセンスで、5 ステージすべてそれで足ります —— 購入も追加インストールもありません。サインインが終わるまで Unity は起動しませんので、これは脚注ではなく 3 番目の手順です。
地図:5 つのステージ、シーンは一つ
各ステージはコースのタブ 1 つに対応し、下の名前をクリックするとそのタブのレッスン一覧へ飛びます。レッスン数と時間はカリキュラムそのままなので、ここで古くなることはありません。
ステージ 1 · 基礎とアリーナ — 11 課、100 分
マテリアルを貼った床と、マウスではなくコードで生成したブロックの格子 —— だから後で別の並びに置き換えられます。
Knight・Mage・Archer の 3 体を 1・2・3 で切り替え、音楽付きのイントロ画面からアリーナを読み込めます。
ステージ 2 · 主人公と敵 — 9 課、114 分
Knight に体が与えられます:CharacterController、重力、ステージ 1 のブロックに着地するジャンプ、そして動作に追従するアニメーション。
Q/E/R の 3 スキルはクールダウン付き、弾はプールから再利用、敵は追ってきてダメージを受けて倒れます。
ステージ 3 · カメラと入力 — 6 課、67 分
三人称カメラはアリーナの壁を突き抜けずに旋回し、攻撃が当たれば揺れます —— ただしその前に追従カメラを自分で一度書いたので、パッケージが何をやってくれているか分かった上で使えます。
キーボード・パッド・画面のスティックへ同じインプットマップを配るので、同じ戦闘を親指 1 本で遊べます。
ステージ 4 · 世界と敵の波 — 7 課、83 分
灰色の箱が場所になります:地形、ベイクしたライトとスカイボックス・フォグ、1×1 m モジュールのセットで組む小物、足音とミキサー —— しかもその間にフレームレートを落とさない方法まで含めて。
デモがゲームになります:4 つのスポーンポイントから敵の波、勝利パネルと敗北パネル、アプリを閉じずにやり直せるリスタート。
ステージ 5 · スマホへ書き出す — 7 課、83 分
出荷できる Player Settings:package name、IL2CPP と ARM64、keystore、そして人に渡せばそのままインストールしてもらえる APK。
アプリを閉じても残るセーブデータ、エディタではなくスマホ向けに調整した URP、そして手元のデバイスでの 60 FPS。
ステージ 1:床、ブロック、そして 3 体
ステージ 1 は意図的に小さく見えますが、準備運動ではありません。コースの残り全部が上で展開されるアリーナそのものです。終わると、床、2 重ループが生成したブロックの格子、歩いて操れる 3 体、そして戦闘シーンを読み込む音楽付きイントロ画面が揃っています。見た目が良くなる前に、すべてがそこにあるのです。
並び順は狙ってあります。短い C# の課を 4 つ、それからエディタ、最後にシーン。プログラミングを教えるためではなく、Unity のスクリプトを読めるようにするためです。変数が何を持つのか、Update がなぜ 1 フレームごとに走るのか、Inspector に並んでいるのを見たあとで class が何なのか、最初のゲームに if と for と List がどれだけ必要か —— 思うより少ない、ということ。その後に出ていく 5 つのウィンドウ、その最後に床へのオブジェクト。C# が Unity より前、Unity がゲームより前で、各ステップは 1 か月ではなく、席について 1 回で終わる規模です。
using UnityEngine;
public class ArenaBuilder : MonoBehaviour
{
public GameObject block;
public Vector2Int size = new Vector2Int(6, 6);
public float spacing = 2f;
void Start()
{
for (int x = 0; x < size.x; x++)
{
for (int z = 0; z < size.y; z++)
{
Vector3 pos = transform.position + new Vector3(x * spacing, 0f, z * spacing);
// The fourth argument makes the block a child of this object.
Instantiate(block, pos, Quaternion.identity, transform);
}
}
}
}ループの中にループを置いて、ブロック 36 個。これが「配置」ではなく「生成」にする理由です。ステージ 4 でアリーナを広くしたくなったら、数字 1 つで格子が変わり、誰も Cube を二度とドラッグしません。
ステージ 2・3・4:最初の攻撃と、カメラと、戦いの場
ステージ 2:元を取れるメカニクス
キャラクターは CharacterController、重力、ステージ 1 のブロックにちゃんと着地するジャンプを得ます。続いて Animator のステートマシンが 足をスクリプトから引き継ぎ、idle・run・jump・attack は 1 つのブレンドツリーと、移動コードが既に書き 込んでいる変数で動く遷移から出てきます。声に出して覚えてほしいのがスキルです:スキル 1 つにつき、 クールダウン・ダメージ・弾を保持した ScriptableObject アセットが 1 つ。
using UnityEngine;
[CreateAssetMenu(menuName = "Game/Skill")]
public class SkillData : ScriptableObject
{
public string skillName;
public float cooldown = 1f;
public int damage = 10;
public GameObject projectile;
}
// The caster keeps one gate per slot; the asset only supplies the numbers.
public class SkillCaster : MonoBehaviour
{
public SkillData[] skills;
float[] nextReadyAt;
void Awake() => nextReadyAt = new float[skills.Length];
public bool TryCast(int slot)
{
if (Time.time < nextReadyAt[slot]) return false;
nextReadyAt[slot] = Time.time + skills[slot].cooldown;
return true;
}
}この分離が後になって効いてきます。調整したくなる数値は、弾のロジックと同じクラスの中ではなく Inspector に置かれるので、Slash のバランスをいじってもそれを撃つ仕組みを壊せません。4 つ目のスキルは「フォルダに新しいアセット + 既存の配列の要素 1 つ」で、1 週間の if の連なりより ScriptableObject との 1 時間の方が価値があるのはそのためです。
ステージ 3:人が飛ばしがちな部分
ステージ 3 は、あなた以外に遊べる人がいるかどうかを決めます。追従カメラは一度自分で書きます —— LateUpdate 内でオフセットへ Lerp —— その上で Cinemachine に会うので、仮想カメラとその Brain が何をやってくれているのか、視界が壁を抜けたときに何を疑えばいいのかを、正確に理解できます。続いて Input System のアクションマップ 1 つがプロジェクト中のキー判定を置き換えます:名前付きの Move アクションに、キーボード、パッドのスティック、そして Canvas 上の仮想スティックがバインドされるのです。最後のバインドが、Unity プロジェクトとスマホのゲームを分けます。
ステージ 4:デモからゲームへ
ステージ 4 は同じ Arena.unity を使って二つのことをします。まず着飾ります —— 地形、ベイクしたディレクショナルライトにスカイボックスとフォグ、1×1 m のモジュールキットとプレハブバリアントによる小物、足音とミキサー —— そして LOD グループ、バッチング、オクルージョンで見た目の良いシーンを軽いまま保ちます。20 FPS のきれいなアリーナは遊べないからです。次に GameDirector がそれをゲームにします:4 つのスポーンポイントから敵の波、勝利パネル、敗北パネル、リスタート。そこに一から発明するものは何もなく、ステージ 1〜3 の仕組みを互いに繋いだだけ —— 繋いだ、その部分が人々がゲームループと呼ぶものです。
ダメージは「殴られた相手への参照」ではなく CharacterStats のイベントを通ります。だから体力バーもダメージ数値も白いフラッシュも、同じ事実を購読するだけです。ステージの残り全体がこのパターンに支えられています。
敵は手で書いた追跡ではなく、ベイクした NavMesh を歩きます。残り 15 分を正直に使うならこちらです —— Scene ビューで見える経路で、ステージ 4 が岩を動かしたらベイクし直すだけですから。
ステージ 5:実機のスマホへ
最後のステージは設定に数時間、そしてコース全体への報酬となる 1 瞬です:あなたのパソコンではないデバイスでゲームが動きます。ビルド対象を Android に切り、scene を登録し、package name・IL2CPP・ARM64 を設定して Build。それだけでテスト用の APK が手に入り、USB で入れるか、人に送れば相手が自分でインストールします。Google Play へのアップロードは AAB が要りますが、同じウィンドウのチェックボックス 1 つで作れます。
- 1
プラットフォームを切り替えるとテクスチャが Android 向けに再インポートされるので、先に実行してコーヒーを淹れに行ってください。続けて で Add Open Scenes。その一覧に無い scene はゲーム側に存在しません —— ビルドが黒画面で開く原因の第一位です。
- 2
デバッグビルドは自動で署名されるため、テストに keystore は不要です。Google Play が受け取るのは署名済みリリースビルドのほう。keystore とそのパスワードは手元に置いてください —— 失うのは設定画面ではなく、アプリのアイデンティティそのものです。
- 3
実機で何か変なことが起きたら、adb logcat がスマホの側の会話を聞かせてくれます。フィルタ付きの 1 コマンドで、ゲームが自己終了した理由が画面に出ます —— ビルド編の記事にそのコマンドと、起動落ちの大半を引き起こす IL2CPP のストリッピングが載っています。
- 4
フレームレートが最後のボスです。Application.targetFrameRate はすべてのスマホで 60 になるわけではなく、エディタの FPS は実機の話を何も伝えません。対策は性能の課でやった地道な方 —— テクスチャの圧縮、ドローコール削減、小物への LOD、ビルトインではなく URP —— そして計るのはスマホ本体であって、その近くではありません。
最初のゲームを終えさせない 5 つの間違い
スコープ。最初のアイデアは必ず大きすぎます。自分が一番よく知っているアイデアだからです。オープンワールドのサバイバルなら 100 個のシステムが要りますが、アリーナ 1 つにキャラクター 3 体と波のループ 1 個なら 10 個ほど —— そしてその 10 個はあらゆるゲームに共通して必要な 10 個です。計画が少し恥ずかしくなるまで削ってください。あのくらいがちょうどいいサイズです。
プロジェクトの途中でエンジンを乗り換える。向こうの草が緑なのは、自分がまだ踏んでいないからです。どのエンジンにも 2 か月目あたりに壁があり、移動しても壁は越えられません —— カウントが 0 からやり直しになるだけです。今持っているもので、まず 1 つを作り切ってください。
公開しない。誰も遊ばないビルドはすべての判断を宙に浮かせておくので、どれが間違いだったかを答えずに済みます。公開だけが本当に効くテストです —— あなたではない人がスマホを持ち、あなたが見ていないところで戸惑う。不快ですが、その不快さそのものが成果物です。
アートを待つ。グレーボックス期は「見栄えが悪いから飛ばそう」期間ではなく、ゲームが面白くなければならない期間です。カプセルとキューブだけの部屋が面白くなければ、美しいキャラクターに差し替えても面白くならず、変更費だけ増えます。まずキューブのジャンプの手触りを決め、そのあとコードに手を触れずにモデルを載せてください。
ぐるぐると学ぶ。CharacterController について 9 本目のチュートリアルは進歩のように感じますが、何も進みません —— 10 番目に知らないことは、9 番目で詰まって初めて顔を出すからです。リファレンスを読むのは勉強で、カプセルを床に落ち込ませずにブロックを越えさせるのは工作です。後の方をして、プロジェクトが要求したときに調べてください。
「終わった」と呼べる条件
- ✓ゲームはメニューから始まり、敵の波を 1 ウェーブ遊べて、負けることもある —— そしてアプリを閉じずにボタン 1 つでやり直せます。
- ✓ビルドがスマホに入ってエディタは閉じている —— コンピュータにつながないままゲームが動きます。
- ✓プロジェクトを一度も見たことがない人が、何を押せばいいか訊かずに 2 分遊べます。
- ✓あのデバイスで 60 FPS を保つか、落ちる箇所と理由を具体的に言えます。
- ✓アプリを閉じて開き直すと進捗が戻ります —— セーブデータも、変更した設定も生き残ります。
- ✓まだ足りないものが何かを、1 文で言えます。その文が次のプロジェクトで最初に直すもの —— ここが要点です。今回を作り切ったので、次はもっと速く始められます。
次にすることは 1 ページ分です。まず最初のタブ 基礎とアリーナ を開いて、1 課から始めてください。 コードを書いたことがない前提で進み、終わりころにはあなたの scene に床ができて、その上に 3 体が立っています。
これを作るレッスン
60 秒で分かる C#:変数
この記事はそれだけで完結するレシピです。コースでは同じものを、5 つのタブを貫くひとつのプロジェクトの一部として作ります — 基礎 のレッスン 01。