Unity 6.3 LTS|3D的当てゲームを作ろう⑥ Robot Sphereで敵をモデル化しよう

Robot Sphereを敵モデルとして配置したUnityの3D的当てゲーム Unity

第6回では、球体だった敵の見た目を無料アセット「Robot Sphere」へ変更します。これまで作った攻撃、移動、スコアは残し、Robot本体で射撃の当たり判定を取れるようにします。

STEP 1

Robot SphereをMy Assetsへ追加しよう

Robot SphereのUnity Asset Storeページを開き、Add to My Assetsを押します。

Unity Asset StoreのRobot Sphereページ
Robot Sphereは無料のロボットモデルです。今回は敵の見た目として使います。

Asset Storeは、Unityで使えるモデルや音などを入手できる場所です。

STEP 2

Package Managerからインポートしよう

UnityでWindow → Package Management → My Assetsを開き、Robot Sphereを選びます。Downloadの後にImport 1.3 to projectを押します。

Package ManagerのMy AssetsでRobot Sphereを選択した画面
My Assetsには、自分のUnityアカウントへ追加したアセットが表示されます。

Import Unity Packageでは、すべてにチェックが入った状態でImportを押します。

Robot SphereのImport Unity Package画面
インポート後はAssets/RobotSphereフォルダーが作られます。
STEP 3

ピンク色のマテリアルを直そう

Robot Sphereは古いUnity向けのアセットなので、Unity 6のURPではPrefabがピンク色になることがあります。これはモデルが壊れたのではなく、Shaderが現在の描画方式に合っていない状態です。

URP非対応のマテリアルによってピンク色に表示されたRobot Sphere Prefab
ピンク色は、MaterialのShaderを確認する合図です。

Assets/RobotSphere/Assets/Models/Materialsを開き、次の3つのMaterialを選びます。

  • body_diff.mat
  • eye_matAi.mat
  • visor_matAi.mat

それぞれのShaderをUniversal Render Pipeline/Litへ変更します。body_diff.matのBase MapへBody_diff画像を設定すると、白とオレンジの模様が戻ります。

URP Litへ変更して正しい色に戻ったRobot Sphereの3つのマテリアル
Materialが白、青、灰色で表示されれば変換できています。
POINT|画像のTexture Type

Body_diff画像のTexture TypeはDefaultのまま使います。色や模様の画像なので、Normal mapへ変更する必要はありません。

STEP 4

現在の敵へRobotを取り付けよう

Assets/RobotSphere/Assets/Prefab/robotSphere.prefabを、Hierarchyにある各敵のSphereへドラッグして子にします。

Mato
└─ Sphere  ← Targetタグ、EnemyAttack、MovingTarget
   └─ robotSphere  ← 見た目と当たり判定

子のRobotはPositionで床の位置まで下げ、Scaleで大きさを調整します。親のSphereではMesh Rendererを無効にします。親のGameObject自体は無効にしません。

Sphereの子としてRobot Sphereを4体配置したUnityのHierarchyとSceneビュー
親にはこれまでのゲーム処理を残し、子のRobotを新しい見た目として使います。

RobotのAnimatorにあるApply Root Motionはオフにします。アニメーションでRobot全体が設定位置から移動することを防ぎます。

STEP 5

Robot本体へColliderを付けよう

子のrobotSphereへSphere Colliderを追加します。Edit Colliderを押し、Robotの胴体を囲むようにCenterとRadiusを調整します。

Robot Sphereに追加したSphere Colliderの設定
Scaleが大きい場合、ColliderのRadiusには小さな値を使います。Sceneビューの枠を見ながら合わせます。

親SphereのSphere Colliderは無効にします。これで、画面には見えない古い球ではなく、Robot側のColliderがRaycastを受け取ります。

STEP 6

子に当たったら親のTargetを探そう

RobotのColliderに当たると、hit.colliderは子のrobotSphereを表します。Targetタグとゲーム用スクリプトは親Sphereにあるため、whileで親を順番に調べます。

ShootCheck.csを次のコードへ更新します。

ShootCheck.cs全体を確認する
using UnityEngine;
using UnityEngine.InputSystem;
using TMPro;

public class ShootCheck : MonoBehaviour
{
    Camera cameraComponent;

    public TMP_Text scoreText;
    public TMP_Text timerText;
    public float timeLimit = 30f;

    int score = 0;
    int remainingTargets;
    float timeRemaining;
    bool gameEnded;

    void Start()
    {
        cameraComponent = GetComponent<Camera>();
        scoreText.text = "SCORE: " + score;

        remainingTargets =
            GameObject.FindGameObjectsWithTag("Target").Length;

        timeRemaining = timeLimit;
        timerText.text =
            "TIME: " + Mathf.CeilToInt(timeRemaining);
    }

    void Update()
    {
        if (gameEnded)
        {
            return;
        }

        timeRemaining -= Time.deltaTime;

        if (timeRemaining <= 0f)
        {
            timeRemaining = 0f;
            timerText.text = "TIME: 0";
            scoreText.text = "TIME UP!\nSCORE: " + score;
            gameEnded = true;
            return;
        }

        timerText.text =
            "TIME: " + Mathf.CeilToInt(timeRemaining);

        if (Mouse.current == null ||
            !Mouse.current.leftButton.wasPressedThisFrame)
        {
            return;
        }

        Ray ray = cameraComponent.ViewportPointToRay(
            new Vector3(0.5f, 0.5f, 0f));

        if (!Physics.Raycast(ray, out RaycastHit hit))
        {
            return;
        }

        Debug.Log(hit.collider.gameObject.name);

        Transform target = hit.collider.transform;

        while (target != null &&
               !target.CompareTag("Target"))
        {
            target = target.parent;
        }

        if (target == null)
        {
            return;
        }

        MovingTarget movingTarget =
            target.GetComponent<MovingTarget>();

        if (movingTarget != null)
        {
            score += movingTarget.scoreValue;
        }
        else
        {
            score++;
        }

        remainingTargets--;

        if (remainingTargets == 0)
        {
            gameEnded = true;
            scoreText.text = "CLEAR!\nSCORE: " + score;
        }
        else
        {
            scoreText.text = "SCORE: " + score;
        }

        Destroy(target.gameObject);
    }
}
hit.collider.transformRaycastが当たったRobotから探索を始めます。
target = target.parent1つ上の親オブジェクトへ移動します。
Destroy(target.gameObject)見た目、攻撃、移動を含む敵全体を消します。
STEP 7

古い入力スクリプトのエラーを直そう

PlayするとUnityEngine.Input.GetKeyのエラーが表示される場合があります。これは、付属のRobot Free Animが古い入力方式を使っているためです。

Robot Free Animが旧Input APIを使用して発生したInvalidOperationException
教材のプロジェクトでは新しいInput Systemを使っているため、旧Input APIを読む付属スクリプトがエラーになります。

今回は付属スクリプトから操作しないため、RobotのRobot Free Anim (Script)をRemove Componentで削除します。AnimatorとSphere Colliderは残します。

注意

Input設定を変更する必要はありません。自分で作ったMouseLook、PlayerMove、ShootCheckは、これまでどおり新しいInput Systemを使います。

STEP 8

Robotを撃って確認しよう

Robot Sphereを敵モデルとして配置した3D的当てゲームのGameビュー
球体の的がRobot Sphereへ変わりました。見た目が変わっても、敵の攻撃、HP、タイマー、スコアは引き続き動きます。
MISSION
  • Robotの胴体を撃つと、敵全体が消える。
  • 撃ったときにスコアが増える。
  • 倒した敵から弾が発射されなくなる。
  • Consoleに赤いエラーが出ない。
Robotを撃っても反応しないとき

Robot側のSphere Colliderが有効か、親SphereのTagがTargetか、更新したShootCheckがMain Cameraに付いているかを確認しよう。

次回予告

次回はRobotのアニメーションをゲームの動きに合わせ、敵らしい演出を追加します。

コメント

タイトルとURLをコピーしました