Developer

【Unity実践】#11 プロトタイプ編 ~ ゴール・トラップの作成 ~【Boxゲーム】
2021.02.05
Lv2

【Unity実践】#11 プロトタイプ編 ~ ゴール・トラップの作成 ~【Boxゲーム】

今回の内容

今回はゴールとトラップを作成します。
これが完成すると前回まで使用していたデバッグ機能が不要となります。

※初めての方はこちらから
【第1回記事】この連載について

ゴールの作成

シーンにCubeを配置して名前を「Goal」としましょう。

Position と Scale を以下の様に設定して、ステージの左下に配置します。

床と見分けがつかないので、マテリアルを作成して色分けしましょう。
Assets > Materials 以下に新規 Material を追加して、名前を「Green_Material」とします。

Albedo の値を調整して、緑っぽくしましょう。(好みでOKです。)

先ほど作成した、Goalオブジェクトに適用しましょう。

以下の様になります。

Goalオブジェクトの中央を踏んだ時に、ゴールとなるようにします。
元々 Goalオブジェクト(あるいは Cube )には、形状に合わせた BoxCollider が設定されています。
今回はこれとは別で、Trigger に設定したコライダーを使用します。

Goal に Add Component で BoxCollider を追加し、以下の設定として下さい。

↓シーンビューで見るとこんな感じになります。

見た目はとりあえずできたので、スクリプトを作成します。
新規スクリプトを Assets > Scripts 以下に作成して、名前は ClearScript としてください。

以下を記述しましょう。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class ClearScript : MonoBehaviour
{
    private void OnTriggerEnter(Collider other)
    {
        if (other.isTrigger)
        {
            return;
        }

        if (other.gameObject.tag == "Player")
        {
            StageControllerScript.isClear = true;
        }
    }
}

これを Goal にアタッチします。

先ほど追加した Trigger の BoxCollider にプレイヤーが接触すると、上記の OnTriggerEnter が実行されます。
シーンを再生して、プレイヤーが Goal を踏んだ時にクリア画面が表示されれば成功です。

動画を再生するには、videoタグをサポートしたブラウザが必要です。

(コリジョン関連記事)
【Unity連載】当たり判定の取り方②(ぶつからない編)

プレイヤーのクリアの制御

クリア後もプレイヤーが動き続けてしまうので、動きを制御します。
以下の3つを対応します。

・クリア時のアニメの再生(PlayerScript, PlayerAnimController)
・移動を停止(PlayerScript)
・正面を向くように(PlayerScript)

まずはプレイヤーのアニメを追加します。
Assets > Animations > PlayerAnimController を Animatorビューで開きましょう。
「Clear」ステートを作成して、Any State からの遷移を作成しましょう。

Clearステートのアニメには、
UnityChan > SD_unitychan > SD_unitychan_motion_humanoid > JumpToTop
を設定します。

Trigger型のパラメータ、「Clear」を追加しましょう。

遷移の設定を以下にします。

次にPlayerScriptに、クリア時の処理を追加します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerScript : MonoBehaviour
{
    Animator charaAnim;

    public bool isMove;

    void Start()
    {
        charaAnim = GetComponent<Animator>();
    }

    void FixedUpdate()
    {
        if (isMove)
        {
            transform.position += transform.forward * 0.03f;
        }
    }

    void Update()
    {
        if (StageControllerScript.isClear)
        {
            isMove = false;
            enabled = false;

            // 正面(画面手前を向く)
            transform.rotation = Quaternion.Euler(0, 180, 0);

            charaAnim.SetTrigger("Clear");
        }

        charaAnim.SetBool("isRunning", isMove);
    }

    private void OnCollisionStay(Collision collision)
    {
        switch (collision.gameObject.tag)
        {
            case "Wall":
                if (isMove) turn();
                break;
        }
    }

    // プレイヤーの向きを反転
    public void turn()
    {
        transform.Rotate(new Vector3(0, 180, 0));
    }

    // プレイヤーを左に向ける
    public void TurnLeft()
    {
        transform.rotation = Quaternion.Euler(0, -90, 0);
    }

    // プレイヤーを右に向ける
    public void TurnRight()
    {
        transform.rotation = Quaternion.Euler(0, 90, 0);
    }

    // 左に走る
    public void MoveLeft()
    {
        TurnLeft();
        isMove = true;
    }

    // 右に走る
    public void MoveRight()
    {
        TurnRight();
        isMove = true;
    }
}

シーンを再生して、Goal を踏んだ時にプレイヤーが移動を停止し、
正面を向いて飛び上がれば成功です。

Goal はプレハブ化しておきましょう。

ステージの追加

ここで一つステージを追加しましょう。
GameScene1 を複製して GameScene2 を作成しましょう。
複製は、GameScene1 を選択して「Ctrl + D」で可能です。

位置や配置物を調整して、以下の様にします。

・既存の Box を削除
・Box_Wall を追加で1つ配置
・各パラメータを以下の通り設定する

↓ プレイヤーの設定

↓ 真ん中の床の設定

↓ 左の箱の設定

↓ 右の箱の設定

また、StageControllerScript で、GAME_SCENE_COUNT を 2 にしておきましょう。

public class StageControllerScript : MonoBehaviour
{
    public const string GAME_SCENE_NAME = "GameScene"; // シーン名のプレフィクス
    public const int GAME_SCENE_COUNT = 2;             // シーンの数

さらに、Build Settings で Scenes in Build に「GameScene1」「GameScene2」を追加しておきましょう。
ここに読み込みたいシーンを追加しておかないと、シーンの切り替えに失敗します。

これで、Nextボタンによるシーンの切り替えができます。

動画を再生するには、videoタグをサポートしたブラウザが必要です。

<関連記事>
【Unity】シーンを切り替える方法

トラップの作成

Goal の時と同様に進めます。
GameScene2 に Cube を配置して、名前を「Trap」としましょう。

Position と Scale は以下の様にして、ステージの右下に配置します。

新規マテリアル「Red_Material」を Assets > Materials 以下に作成しましょう。

Albedo を調整して、以下の様に赤っぽくしておきます。

Trapに適用すると、以下の様になります。

Trap は元々ついている BoxCollider に接触したときに処理を実行することとします。
実行する処理は、プレイヤーにダメージを与える処理です。
Assets > Script 以下に、TrapScript を作成してください。

以下を記述しましょう。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class TrapScript : MonoBehaviour
{
    private void OnCollisionEnter(Collision other)
    {
        if (other.gameObject.tag == "Player")
        {
            other.gameObject.GetComponent<PlayerScript>().isDamaged = true;
        }
    }
}

PlayerScript の isDameged (11行目)でコンパイルエラーが出ますが、この後追加しますので今は問題ありません。

スクリプトを Trap にアタッチして、プレハブ化しておきましょう。

(コリジョン関連記事)
【Unity連載】当たり判定の取り方①(ぶつかる編)

プレイヤーのダメージ時の制御

まずはプレイヤーがダメージを受けた時のアニメを追加します。

↓Damagedステートを追加して

アニメには、
UnityChan > SD_unitychan > SD_unitychan_motion_humanoid > GoDown
を設定します。

新たに Trigger型のパラメータ Damaged を追加しましょう。

最後に、遷移を以下の通り設定して、アニメーターの変更は完了です。

PlayerScript に 以下を追加します。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class PlayerScript : MonoBehaviour
{
    Animator charaAnim;

    public bool isMove;
    public bool isDamaged;

    void Start()
    {
        isDamaged = false;
        charaAnim = GetComponent<Animator>();
    }

    void FixedUpdate()
    {
        if (isMove)
        {
            transform.position += transform.forward * 0.03f;
        }
    }

    void Update()
    {
        if (StageControllerScript.isClear)
        {
            isMove = false;
            enabled = false;

            // 正面(画面手前を向く)
            transform.rotation = Quaternion.Euler(0, 180, 0);

            charaAnim.SetTrigger("Clear");
        }else if(isDamaged){
            isMove = false;
            enabled = false;
 
            charaAnim.SetTrigger("Damaged");
 
            StageControllerScript.isGameOver = true;
        }

        charaAnim.SetBool("isRunning", isMove);
    }

    private void OnCollisionStay(Collision collision)
    {
        switch (collision.gameObject.tag)
        {
            case "Wall":
                if (isMove) turn();
                break;
        }
    }

    // プレイヤーの向きを反転
    public void turn()
    {
        transform.Rotate(new Vector3(0, 180, 0));
    }

    // プレイヤーを左に向ける
    public void TurnLeft()
    {
        transform.rotation = Quaternion.Euler(0, -90, 0);
    }

    // プレイヤーを右に向ける
    public void TurnRight()
    {
        transform.rotation = Quaternion.Euler(0, 90, 0);
    }

    // 左に走る
    public void MoveLeft()
    {
        TurnLeft();
        isMove = true;
    }

    // 右に走る
    public void MoveRight()
    {
        TurnRight();
        isMove = true;
    }
}

シーンを再生して、右の箱を壊して Trap を踏むと、ゲームオーバー画面となれば成功です。

これでクリア、ゲームオーバーの基本的な仕組みが完成しました。
気になる点がいくつかあり、
・ゲームオーバー後も箱を壊せる
・倒れてから、リトライ画面を出したい(アニメが再生し終わってから)
・開発用に、現在のシーンを再生する仕組みが欲しい(PlayerPrefsに依存しない設定)

この辺は今後どこかのタイミングで調整して行きたいと思います。

おわりに

プロトタイプ編もだいぶ終盤まで来ました。
次回はプロトタイプ編の最後として、ドラゴンのギミックのプロトを作ろうと思いますのでお楽しみに!

 
 

連載目次リンク

実践Unityゲームプログラミング 連載目次
 

関連する連載リンク

「初心者のための」Unityゲーム制作 目次
 

© Unity Technologies Japan/UCL