ゲームエンジン基礎⑪(2025/09/05)

●Rigidbody
…重なっているものを「弾く」性質がある。
 止まっているもの同士の接触や重なりには反応しない。
 片方が動いていれば判定はされる。

●弾を動かすときー
①Rigidbodyで加速度をつける or ②Positionをいじる
①の方が簡単。とりあえずこの例を作ってみる。

using Unity.Collections;
using UnityEngine;

public class Player : MonoBehaviour
{
    [Header("---Bullet Settings---")]
    public GameObject bulletPrefab;
    public float shotPower = 10f;
    [HideInInspector] public Rigidbody2D bulletRb; // Rigidbodyの参照

    void Update()
    {
        if (Input.GetKeyDown(KeyCode.Space))
        {
            GameObject bullet = Instantiate(bulletPrefab, new Vector3(0, 0, 0), Quaternion.identity);//複製されたオブジェクトをbulletで受ける
            bulletRb = bullet.GetComponent<Rigidbody2D>(); // Rigidbody2Dを取得してbulletRbに代入

            //AddForce(飛ばす方向と力、飛ばすときのモード指定)
            bulletRb.AddForce(new Vector2(0, 1)*shotPower, ForceMode2D.Impulse); // Rigidbody2Dに力を加える
        }
    }
}

AddForceの第二引数
⇒ForceMode:徐々に力を加える
⇒ImpulseMode:一気に力を加える

GameObjectを追加(Square)して、Enemyにリネーム。
BoxCollider2DとRigidbody2Dをアタッチ。GravityScaleを0に。

Enemy.csスクリプトを作成。
OnCollisionEnter2Dを追加。

using UnityEngine;

public class Enemy : MonoBehaviour
{
    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {

    }

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

    }

    //Collider同士が接触した”瞬間(フレーム)”に実行される関数
    void OnCollisionEnter2D(Collision2D collision)
    {
                Debug.Log($"HIT!...");
    }
}

OnCollisionEnter2D:Collider同士が接触した瞬間(フレーム)だけに実行
OnCollisonStay2D:Collider同士が接触している(フレーム)の間実行し続ける
OnCollisionExit2D:Collider同士が”離れた瞬間(フレーム)”実行される。

上記スクリプトをEnemyオブジェクトにアタッチして、弾を当ててみる。

Consoleに”HIT”が表示された。

using UnityEngine;

public class Enemy : MonoBehaviour
{
    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {

    }

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

    }

    //Collider同士が接触した”瞬間(フレーム)”に実行される関数
    void OnCollisionEnter2D(Collision2D collision)
    {
        //OnCollisionEnter2D内の引数であるcollisionには、衝突したオブジェクトの情報(Collision2D)が入る
        Debug.Log($"HIT!...{collision.transform.name}");
        Destroy(gameObject);//接触で削除される
    Destroy(collision.gameObject);//接触した相手のオブジェクトも削除する
    }
}

このようにcollisionで、衝突した相手の情報を引いてきて、様々な処理を行うのがゲーム制作の基本。

ゲームパッドを使いたい場合、InputSystemーInputAcctionで検索してみる。

using Unity.Collections;
using UnityEngine;

public class Player : MonoBehaviour
{
    [Header("---Bullet Settings---")]
    public GameObject bulletPrefab;
    public float shotPower = 10f;
    [HideInInspector] public Rigidbody2D bulletRb; // Rigidbodyの参照

    void Update()
    {
        if (Input.GetKey(KeyCode.LeftArrow)|Input.GetKey(KeyCode.A))
        {
            transform.Translate(-1, 0, 0);
        }
        if (Input.GetKey(KeyCode.RightArrow)|Input.GetKey(KeyCode.D))
        {
            transform.Translate(1, 0, 0);
        }

        if (Input.GetKeyDown(KeyCode.Space))
            {
                GameObject bullet = Instantiate(bulletPrefab, new Vector3(0, 0, 0), Quaternion.identity);
                bulletRb = bullet.GetComponent<Rigidbody2D>(); // Rigidbody2Dを取得してbulletRbに代入

                //AddForce(飛ばす方向と力、飛ばすときのモード指定)
                bulletRb.AddForce(new Vector2(0, 1) * shotPower, ForceMode2D.Impulse); // Rigidbody2Dに力を加える
            }
    }
}

上のコードでは、単位がフレーム/mなので、1フレームで1m動くことになる。
Time.deltaTimeを掛けることで時間の単位を1秒に変えることができる。

using Unity.Collections;
using UnityEngine;

public class Player : MonoBehaviour
{
    [Header("---Base Parameter")]
    public float moveSpeed = 5.0f;

    [Header("---Bullet Settings---")]
    public GameObject bulletPrefab;
    public float shotPower = 10f;
    [HideInInspector] public Rigidbody2D bulletRb; // Rigidbodyの参照

    void Update()
    {
        if (Input.GetKey(KeyCode.LeftArrow)|Input.GetKey(KeyCode.A))
        {
            transform.Translate(moveSpeed*Time.deltaTime, 0, 0);
        }
        if (Input.GetKey(KeyCode.RightArrow)|Input.GetKey(KeyCode.D))
        {
            transform.Translate(moveSpeed*Time.deltaTime, 0, 0);
        }

        if (Input.GetKeyDown(KeyCode.Space))
            {
                GameObject bullet = Instantiate(bulletPrefab, new Vector3(0, 0, 0), Quaternion.identity);
                bulletRb = bullet.GetComponent<Rigidbody2D>(); // Rigidbody2Dを取得してbulletRbに代入

                //AddForce(飛ばす方向と力、飛ばすときのモード指定)
                bulletRb.AddForce(new Vector2(0, 1) * shotPower, ForceMode2D.Impulse); // Rigidbody2Dに力を加える
            }
    }
}

これで左右に動ける…が、プレイヤーが動いても同じ位置から発射される。
Instantiateの場所をプレイヤーの座標に変更する。

(Player.cs)

using Unity.Collections;
using Unity.VisualScripting;
using UnityEngine;

public class Player : MonoBehaviour
{
    [Header("---Base Parameter")]
    public float moveSpeed = 5.0f;

    [Header("---Bullet Settings---")]
    public GameObject bulletPrefab;
    public float shotPower = 10f;
    [HideInInspector] public Rigidbody2D bulletRb; // Rigidbodyの参照

    void Update()
    {
        if (Input.GetKey(KeyCode.LeftArrow)|Input.GetKey(KeyCode.A))
        {
            transform.Translate(-moveSpeed*Time.deltaTime, 0, 0);
        }
        if (Input.GetKey(KeyCode.RightArrow)|Input.GetKey(KeyCode.D))
        {
            transform.Translate(moveSpeed*Time.deltaTime, 0, 0);
        }

        if (Input.GetKeyDown(KeyCode.Space))
            {
                GameObject bullet = Instantiate(bulletPrefab, this.transform.position, Quaternion.identity);
                bulletRb = bullet.GetComponent<Rigidbody2D>(); // Rigidbody2Dを取得してbulletRbに代入

                //AddForce(飛ばす方向と力、飛ばすときのモード指定)
                bulletRb.AddForce(new Vector2(0, 1) * shotPower, ForceMode2D.Impulse); // Rigidbody2Dに力を加える
            }
    }
}

なお、”This”は省略可能で、省略した場合には、自分がアタッチされているオブジェクトのコンポーネントを参照する。

「プレイヤーが動く」
「弾を撃つ」
「弾に当たったら敵が止まる」
この要素がシューティングの骨格。これを改造していく。

次は、敵を増やしていく。

using UnityEditor.VersionControl;
using UnityEngine;

public class Spawner : MonoBehaviour
{
    [Header("---Spawn Setting---")]
    public GameObject enemyPrefab;

    [Header("---Spawn Timer")]
    public float timeLimit = 1.0f;
    public float timer = 0.0f;

    // Start is called once before the first execution of Update after the MonoBehaviour is created
    void Start()
    {

    }

    // Update is called once per frame
    void Update()
    {
        timer += Time.deltaTime;//一秒で一加算。
        if (timer >= timeLimit)
        {
            Instantiate(enemyPrefab, transform.position, Quaternion.identity);
      timer = 0.0f;
        }
    }
}

Unityでは、fpsが一定ではないので、Time.deltaTimeを使って、時間で管理するのが普通。

SpawnerオブジェクトにSpawner.csをアタッチして、InspectorにEnemy.Prefabをアタッチするのも忘れずに。

コメント

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