3Dモグラ撃ちゲームを作る #1

投稿者: | 2019-12-16

地面からモグラを出現させて、前の記事の方法で玉を当てるFPSミニゲームを作りました。→3Dモグラ撃ちゲーム

シーンの床の下にカプセルを配置して、アニメーションを付けます。

Add PropertyでPositionを追加して、タイムライン上の一番最後の時間に白い縦線を動かして、録画ボタンを押し、カプセルを動かします。

もう一度録画ボタンを押して確定します。デフォルトの位置からこの位置までシームレスに動くアニメーションが付きました。

再生ボタンで確認できます。

プロジェクトにアニメーションのファイルが作られています。

クリックしてインスペクタを見ます。

Loop Timeのチェックが付いているとアニメーションが繰り返させるので、チェックを外します。

カプセルにはコライダーの他に新しいスクリプトが付いています。

スクリプトで、モグラにボールが当たるとアニメーションが止まるようにします。

private void OnCollisionEnter(Collision collision)
{
    if (collision.rigidbody.CompareTag("Ball"))
    {
        moleAnimator.speed = 0f; // アニメーションを止める        
    }
}

アニメーションを付けると、アニメーターコントローラーにオレンジ色のステートが追加されます。

Create New Clipで新しいアニメーションを作ります。

今度は設定した位置からデフォルトの位置へ戻るアニメーションを付けます。

するとコントローラーに灰色のステートが追加されています。

オレンジのステート上で右クリックしてMake Transitionをクリックすると矢印が出るので、灰色のステートをクリックして2つのステートをつなげます。

Boolのパラメーターを作ります。

オレンジと灰色のステートをつなぐ矢印をクリックすると、インスペクタ上でステートの遷移の条件を設定できます。

+をクリックしてパラメータを追加します。「hide」パラメータがtrueになると潜るアニメーションに切り替わります。Has Exit Timeのチェックを外して、アニメーションが条件を満たすと直ちに遷移するようにします。

private IEnumerator Hide()
{
    yield return new WaitForSeconds(5.0f); // 5秒待つ

    moleAnimator.SetBool("hide", true); // hideパラメータをtrueにする

    yield return new WaitForSeconds(2.0f); // 2秒待つ

    Destroy(gameObject); // オブジェクトを破壊する
}

private IEnumerator Hit()
{
    yield return new WaitForSeconds(2.0f); // 2秒待つ

    Destroy(gameObject); // オブジェクトを破壊する
}

private void OnCollisionEnter(Collision collision)
{
    if (collision.rigidbody.CompareTag("Ball"))
    {
        GetComponent<Renderer>().material.color = Color.red; // モグラの色を変える

        moleAnimator.speed = 0f; // アニメーションを止める
        StopCoroutine("Hide"); // Hideコルーチンを止める
        StartCoroutine("Hit"); // Hitコルーチンをスタートする
    }
}

モグラが生成されると、地面から出てくるアニメーションが始まって、Hideコルーチンがスタートします。Hideコルーチンでは5秒後にhideパラメータがtrueになって、潜るアニメーションに遷移して、2秒後にモグラが破壊されます。

その間にもしモグラがBallにあたったら、モグラが赤くなり、アニメーションが止まって、2秒後にモグラが破壊されるようにしています。

このモグラのオブジェクトをプロジェクトにドラッグアンドドロップしてプレハブにして、ランダムの位置にランダムの間隔で出現するようにします。

すると、同じところに生成されてしまいます。

これは、この位置でアニメーションを作ったからだと思います。モグラの位置がアニメーションで固定されています。

モグラのプレハブのAnimatorコンポーネントでApply Root Motionのチェックを入れると、モグラが生成した位置から動くようになります。

でも、モグラの動きがモグラのScaleに掛け合わされてしまって、その分モグラが大きく動くようになりました。
モグラのScaleを考慮して、アニメーションの値を調節しました。

(プレイヤーのカメラに付けたスクリプト)

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.SceneManagement;

public class fpsScript : MonoBehaviour
{
    public GameObject ball;
    Rigidbody rb_ball;
    public float thrust = 100f;

    public GameObject mole;
    Vector3 moleRight;

    AudioSource[] playerAudio;

    public Text scoreText;
    public Text timeText;
    public Text resultText;

    public int timeLimit = 60;

    public AudioClip[] audio;

    GameObject moleIns;

    public int passingMark = 50;

    // Start is called before the first frame update
    void Start()
    {
        StartCoroutine("GenerateMole");
        playerAudio = GetComponents<AudioSource>();

        scoreText.text = "";
        resultText.text = "";
        timeText.text = timeLimit.ToString();

        StartCoroutine("timer");

        playerAudio[0].clip = audio[0];
        playerAudio[0].Play();

        MoleScript.score = 0;

    }

    // Update is called once per frame
    void Update()
    {

        scoreText.text = MoleScript.score.ToString();

        if (Input.GetMouseButtonDown(0)) // マウスの左クリックをしたとき
        {
            playerAudio[1].Play();

            rb_ball = Instantiate(ball, transform.position, transform.rotation).GetComponent<Rigidbody>(); // 玉を生成
            rb_ball.AddForce(transform.forward * thrust, ForceMode.Impulse); // カーソルの方向に力を一度加える
        }

        if (Input.GetKeyDown(KeyCode.R))
        {
            SceneManager.LoadScene("FPSShooting");
        }
    }

    private IEnumerator GenerateMole()
    {

        while (true)
        {


            yield return new WaitForSeconds(Random.Range(0.2f, 2.0f));

            moleIns = Instantiate(mole, new Vector3(Random.Range(-30f, 30f), -4.0f, Random.Range(-30f, 30f)), Quaternion.Euler(0f,0f,0f)); // モグラを生成
            moleRight = transform.position - moleIns.transform.position; // モグラからプレイヤーの方向
           
            moleRight.y = 0f; // Y座標を0に固定

            moleIns.transform.rotation = Quaternion.FromToRotation(moleIns.transform.right, moleRight); // モグラの顔をプレイヤーの方に向ける
        }
       
    }

    private IEnumerator timer()
    {

        while (timeLimit > 0) // カウントダウン
        {
            yield return new WaitForSeconds(1f);
            timeLimit -= 1;
            timeText.text = timeLimit.ToString();
        }

        // 0秒になると
        if (MoleScript.score >= passingMark) // スコアが合格点以上
        {
            playerAudio[0].clip = audio[1];
            playerAudio[0].Play();
            timeText.text = "";
            resultText.text = "Passed";

        }
        else // スコアが合格点未満
        { 

            playerAudio[0].clip = audio[2];
            playerAudio[0].Play();
            timeText.text = "";

            resultText.text = "Failed";
        }

    }
}

(モグラのプレハブに付けたスクリプト)

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

public class MoleScript : MonoBehaviour
{

    Animator moleAnimator;
    bool fainted = false;

    public AudioClip[] audio;
    AudioSource moleAudioSource;

    public static int score;


    // Start is called before the first frame update
    void Start()
    {
        moleAnimator = GetComponent<Animator>();
        StartCoroutine("Hide");

        moleAudioSource = GetComponent<AudioSource>();
    }

    // Update is called once per frame
    void Update()
    {
        
    }

    private IEnumerator Hide()
    {
        yield return new WaitForSeconds(5.0f);

        moleAnimator.SetBool("hide", true);

        yield return new WaitForSeconds(2.0f);

        Destroy(gameObject);

    }

    private IEnumerator Hit()
    {
        yield return new WaitForSeconds(2.0f);

        Destroy(gameObject);

    }

    private void OnCollisionEnter(Collision collision)
    {
        if (collision.rigidbody.CompareTag("Ball"))
        {
            if (fainted)
            {
                score -= 1;
                moleAudioSource.clip = audio[0];
                moleAudioSource.Play();
            }
            else
            {
                score += 1;

                moleAudioSource.clip = audio[1];
                moleAudioSource.Play();

                fainted = true;
                GetComponent<Renderer>().materials[0].color = Color.red;
                GetComponent<Renderer>().materials[1].color = Color.red;

                moleAnimator.speed = 0f; // アニメーションを止める
                StopCoroutine("Hide");
                StartCoroutine("Hit");                
            }
        }

    }

}

(ボールのプレハブに付けたスクリプト)

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

public class ballScript : MonoBehaviour
{
    // Start is called before the first frame update
    void Start()
    {
        
    }

    // Update is called once per frame
    void Update()
    {
        if (transform.position.y < -10f)
        {
            Destroy(gameObject);
        }
    }
}

モデルに付いている複数のマテリアルの色を変える

Blenderでかわいいモグラを作りました。

このモグラにはマテリアルが2つ付いています。

GetConponentsと同様に、GetComponent().materials にマテリアルの配列が入っているので、インデックスを指定して、個々のマテリアルを操作できます。

モグラの向き

プレイヤーの方を向いた状態でモグラを生成させています。transform.position – moleIns.transform.position としてモグラからプレイヤー方向を示す座標を得て、Y座標を0にすることで、上下の向きを無効にしています。

これをQuaternion.FromToRotation() の中で使っています。すると、Vector3の引数を2つ入れますが、1つ目の座標が示す向きが、2つ目の座標が示す向きになるようにオブジェクトを回転します。

コメントを残す

メールアドレスが公開されることはありません。