2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

高校生がUnityでゲーム制作に挑戦してみた。

Last updated at Posted at 2025-06-04

はじめに

学校の中間テストが終わり(二つの意味で)、少し落ち着いてきましたので記事を書こうと思います。
校内順位が低すぎたため、予備校に入ろうかどうか迷っています('_')

前置きはこのくらいにして、本記事は簡単で分かりやすくまとめました。
少しでも目を通していただければ幸いです!

※ このゲームは初めて外部公開した作品です。
クオリティはまだまだですが、これからさらに良いゲームを作れるよう日々精進していきます!
Easy 3D Zombie


🎮 ゲーム概要

今回作成した 3Dタワーディフェンス風ゲーム は、以下の4点で簡潔にまとめられます。

  1. フェーズ制でのゾンビ襲来

    • 大量のゾンビが四方からランダムに攻めてくる
  2. 配置フェーズ

    • ゾンビ誘導&足止め用の壁迎撃用タレット を自由に配置可能
  3. タレットによる攻撃

    • タレットが自動でゾンビを狙い撃ちする
  4. 勝敗条件

    • 中央の基地を 5フェーズ 守り切れば勝ち
    • 一定回数基地がゾンビに触れられたら敗北

🔧 各要素の実装と苦労した点

1️⃣ フェーズ制で大量のゾンビ襲来

苦労度: ★★⭐︎⭐︎⭐︎

3Dゲームとして NavMesh を活用し、ゾンビに中央基地までの最短ルートをたどらせました。
NavMesh には Bake 機能があり、どの地形を通るかを定義できますが、タレットなどの建築物を配置した際、Bake を更新しなければゾンビがタレットの位置を認識できず、詰まる問題が発生しました。

解決策:
フェーズ開始直前に Bake を更新 することで、正しい経路が確保されるようにしました。


2️⃣ 壁とタレットの自由配置機能

苦労度: ★★★★⭐︎

この機能では、特定のキーを押すと プレイヤーの視線先に壁やタレット(以下「建築物」)を配置 できるようにしています。
ただし、配置前にどこにどう置かれるかが分からないと不便なので、
フォートナイト の建築のように 半透明プレビュー を表示する仕組みを実装しました。

🏗 実装の流れ

  1. Ray をプレイヤーの視線先から発射
  2. Ray が床に当たった座標を取得
  3. 半透明の建築物をその座標に表示
  4. Ray の座標を追従しつつ設置可能か判断
  5. 設置可能なら実物を配置

🚧 主な苦労と解決策

  • 問題①: Ray が目的の座標ではなく、Player や半透明プレビューの座標を取得してしまう
    → ✅ 解決: レイヤーマスクを使用し、Player や半透明の建築物のレイヤーを除外

  • 問題②: 建築物のコードが見づらい
    → ✅ 解決: 以下の方法で整理

    1. Ray で取得した視線先に Empty オブジェクトを追加し追尾
    2. Y座標を若干高く設定し、地面へのめり込みを防止
    3. Trigger をアタッチし、箱型に変更して接触判定
    4. Empty に配置可否の判断コードを組み込み
    5. 設置スクリプトには可否情報のみを伝達し、冗長性を削減

この方法により、スパゲッティ気味だったコードの整理が進み、管理しやすいコード設計が実現しました。


3️⃣ タレットがゾンビを打ちまくる

苦労度: ★★★★★

タレットは設置するだけで 自動索敵&最適な敵を狙撃 します。
ただし、大量のゾンビがいる状況でのパフォーマンス最適化が難題でした。

🎯 実装のポイント

  • 敵の座標を全探索せず 【射線が通っている】条件でフィルタ し、
    ユークリッド距離の計算負荷を削減 してパフォーマンス向上。

  • 具体的なコード例:

    foreach (GameObject enemy in enemies)
    {
        Vector3 directionToEnemy = (enemy.transform.position - firePoint.position).normalized;
    
        if (Physics.Raycast(firePoint.position, directionToEnemy, out RaycastHit hit, Mathf.Infinity))
        {
            if (hit.collider.gameObject == enemy)
            {
                float distance = Vector3.Distance(transform.position, enemy.transform.position);
    
                if (distance < minDistance)
                {
                    minDistance = distance;
                    closestEnemy = enemy;
                }
            }
        }
    }
    
  • 後悔ポイント:
    偏差射撃の実装は、敵の進行方向・速度、弾速、発射タイミングなど、膨大な計算が必要だったため断念。


🎭 UX向上のための演出追加

💥 爆発エフェクトの改善

タレットが撃った弾が 壁に当たると爆発 する演出を追加しました。
爆発時の光が 瞬間的に発生し、徐々に消える ことで、よりリアルな表現に。


🎞 エンドロールの実装

ゲームを最後までプレイしてくれた方へ 感謝の気持ちを込めてエンドロール を追加。
ワンクリックで即終了ではなく、クリア画面からエンドロールへ遷移 でき、途中スキップも可能にしました。


🔚 結び

このゲーム制作を通じて、
ゲーム内のオブジェクトが密に連携するシステムの奥深さ を実感しました。

培ったノウハウを 次回作に活かしていきたい と思います。
最後まで読んでいただき、ありがとうございました!

📌 ゲームはこちら

🖼 没になったサムネイルを供養…
Thumbnail

2
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?