Unityで3Dミニゲームを作る #2

投稿者: | 2019-12-01

障害物となる玉をプレイヤーに向かって飛ばしてみます。

Sphereオブジェクトを新規作成して Ballと名前を付けました。

プロジェクトウィンドウのどこかのフォルダにドラッグアンドドロップしてプレハブ化します。

これで Ballが一つのオブジェクトではなく、オブジェクトの雛形になります。この雛形を使ってBallオブジェクトを作れます。
似たようなオブジェクトをたくさん生成したいときにプレハブが便利です。各オブジェクトの値を一括で変更したり、あるプロパティには各オブジェクトに別々の値を設定することもできます。

プレハブを編集するときは、そのプレハブを選択して、インスペクタでOpen Prefabをクリックします。

まずはAdd ComponentからRigidbodyを追加します。

落下しないように、Use Gravityをオフにします。

Ballオブジェクトを生成して、プレイヤーに向かって飛ばす

Playerに付けたスクリプトを編集します。

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

public class playerScript : MonoBehaviour
{
    Rigidbody rb;

    Rigidbody rb_ball;
    public Rigidbody ball;


    // Start is called before the first frame update
    void Start()
    {
        rb = GetComponent<Rigidbody>();
        StartCoroutine("ThrowTheBall"); // コルーチンを開始
    }

    // Update is called once per frame
    void Update()
    {
        if (Input.GetMouseButtonDown(0)) // マウスの左クリックをしたとき
        {
            float turn = Input.GetAxis("Horizontal"); // 左右キー入力
            rb.AddForce(new Vector3(-turn/2, 1f, 0) * 5f, ForceMode.Impulse); // プレイヤーを動かす
        }

        if (transform.position.x > 9f || transform.position.x < -9f || transform.position.y > 5.5f || transform.position.y < -5f)
        {
            SceneManager.LoadScene("flyingCube"); // プレイヤーが枠から出るとシーンを再読み込み

        }

    }

    private IEnumerator ThrowTheBall() // Ballを生成して飛ばすコルーチン
    {
        while (true)
        {
            rb_ball = Instantiate(ball, new Vector3(0, 0, -30f), transform.rotation) as Rigidbody;
            rb_ball.AddForce(Vector3.forward * 10f, ForceMode.Impulse);

            yield return new WaitForSeconds (1.0f); 
        }       
    }
}

コルーチンを追加しました。

private IEnumerator ThrowTheBall()
{
    while (true)
    {

        yield return new WaitForSeconds (1.0f); 
    }       
}

コルーチン ThrowTheBall() の中にwhile文を使って、無限ループを作っています。yield return new WaitForSeconds (); のところで設定した秒数だけ ThrowTheBall()の処理が一時停止します。
ここでは1秒ごとにwhile文の中の処理を繰り返すことになります。
コルーチンを使うことで、Update()等とは別に、時間を指定した処理を書けます。

シーンが開始されたときに、StartCoroutine(“ThrowTheBall”); によってコルーチンがスタートします。

BallのプレハブをplayerScriptにアタッチしています。

これを Instantiate() の中で使うことで、Ballオブジェクトが1秒毎に生成されます。 Instantiate()には、オブジェクトを作るのに使うプレハブの他に、生成する場所と回転を設定します。
参考:https://docs.unity3d.com/ja/2017.4/ScriptReference/Object.Instantiate.html

生成するポジションを探すには、まず適当にオブジェクトを作ります。

シーンビューでとりあえずプレイヤーの正面に移動します。

この時のこのオブジェクトのPositionを使います。

使わないときは無効化できます。

回転は、適当にプレイヤーの回転値を使っています。

Instantiate()にプレハブのRigidbodyを設定して、as Rigidbodyを付けているので、rb_ballには生成されたオブジェクトのRigidbodyが代入されます。
このRigidbodyのAddForceメソッドを使って、生成した直後にプレイヤーの方に向かって力を加えています。

Z軸方向にプレイヤーがあるので、Vector3.forwardを使っています。

Ballオブジェクトをランダムの位置に生成する

Ballオブジェクトが生成される位置をある範囲内でランダムにするために、コルーチンを少し書き換えます。

    private IEnumerator ThrowTheBall() // Ballを生成して飛ばすコルーチン
    {
        while (true)
        {
            rb_ball = Instantiate(ball, new Vector3(Random.Range(-9f, 9f), Random.Range(-5f, 5.5f), -30f), transform.rotation) as Rigidbody;
            rb_ball.AddForce(Vector3.forward * 10f, ForceMode.Impulse);

            yield return new WaitForSeconds(Random.Range(0.1f, 1f));
        }       
    }

Random.Range(min, max) を使うと、設定した最小値と最大値の範囲内の値をランダムで設定できます。
これは、WaitForSeconds() の中でも使えます。

通り過ぎたBallオブジェクトを破壊する

このままではBallオブジェクトが増え続けて、動作が重くなってしまいます。

なので通り過ぎたBallを破壊するようにします。

Sphereをアクティブにしてシーンビューで移動させ、プレイヤーの後ろでカメラから見えなくなるところのポジションを確認します。

PositionのZ軸の値がこれより大きくなったBallオブジェクトをスクリプトで破壊します。
Ballのプレハブに、Add Componentから新しいスクリプトを付けます。

New script -> Create and Addをクリックします。

このスクリプトをダブルクリックして編集します。

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.z > 6f)
        {
            Destroy(gameObject);
        }
    }
}


Ballオブジェクトが増えすぎなくなりました。

コメントを残す

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