【Unity】移動している的にボールをくっつける

的にボールが衝突したタイミングで、IsKinematicを有効にして物理的な作用を止め、くっついたイメージとしている場合、的を移動しているとその場にボールが止まるといった不自然な状態になります

動作の違い

動画でイメージを確認してみましょう

ボールがその場に止まっている

的とともにボールも移動

仕様の追加

的を左右に動かす仕様と、ボールが的に止まる状態となる仕様を追加します

移動のためにスクリプト

まず、的の移動が必要ですね

このスクリプトでは、オブジェクトはx軸方向にsin関数によって往復します。振幅(amplitude)と周波数(frequency)を調整することで、動きの特性を調整できます。このスクリプトをオブジェクトにアタッチし、振幅と周波数を調整して試してみてください

スクリプトは的に追加でアタッチします

using UnityEngine;

public class SinMovement : MonoBehaviour
{
    [Tooltip("オブジェクトの振幅")]
    public float amplitude = 1.0f;

    [Tooltip("オブジェクトの周波数")]
    public float frequency = 1.0f;

    // オブジェクトの初期位置
    private Vector3 initialPosition;

    private void Start()
    {
        // オブジェクトの初期位置を保存
        initialPosition = transform.position;
    }

    private void Update()
    {
        // sin関数を使ってオブジェクトを往復させる
        float time = Time.time;
        // x軸方向の変異を計算
        float xOffset = amplitude * Mathf.Sin(frequency * time);
        // 新しい位置を設定
        transform.position = initialPosition + new Vector3(xOffset, 0, 0);
    }
}
float xOffset = Mathf.PingPong(time, amplitude);

的とともに移動するボール

的にボールが当たると、そのタイミングで的の子オブジェクトにする方法を使ってみましょう

親オブジェクト(この場合、的)の子オブジェクト(この場合、ボール)にするには、次のコードを利用します

// 親を指定する
transform.parent = 親ゲームオブジェクトのTransformコンポーネント

.parent は、Transform コンポーネントの親オブジェクトを表します。親オブジェクトは、このゲームオブジェクトを包む親階層のオブジェクトです

具体的には次のようになります

transform.parent = GameObject.Find("target").transform;

ボールのコントローラに次のように1行追加します

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

public class IgaguriController : MonoBehaviour
{
    public void Shoot(Vector3 dir)
    {
        GetComponent<Rigidbody>().AddForce(dir);
    }

    void OnCollisionEnter(Collision collision)
    {
        GetComponent<Rigidbody>().isKinematic = true;
        GetComponent<ParticleSystem>().Play();

        // 的の子オブジェクトにする
        transform.parent = GameObject.Find("target").transform;
    }

    void Start()
    {
        Application.targetFrameRate = 60;
        // Shoot(new Vector3(0, 200, 2000));
    }
}

複数の的に対応

的が1つの場合、これでもいいのですが、複数の的となると、衝突した的ごとに親を指定する必要があります
OnCollisionEnterの引数に衝突した相手の情報がありますので、それを使うといいでしょう

上記の追加行を次のように変更します

transform.parent = collision.gameObject.transform;
// または、参考に記しているように直接transformを取得することもできます
transform.parent = collision.transform;

参考

Collisionクラスで得られる情報

変数

ArticulationBody」は、Unity 2020.1から利用できる新しい関節コンポーネントです。多くの関節を繋げても、正確で安定した動きを実現できるのが特徴になります。ロボットアームなど多関節ロボットの作成に適しています

articulationBodyGameObjectが衝突するコライダのArticulationBody(読み取り専用)
bodyコンポーネントが衝突するコライダのRigidbodyまたはArticulationBody(読み取り専用)
colliderヒットした Collider 情報を返します(読み取り専用)
contactCountこの衝突のコンタクト数を取得する.
contacts物理エンジンによって生成された接触点。これはメモリ・ガーベージを生成するため、使用を避けるべきである。代わりにGetContactまたはGetContactsを使用してください.
gameObject衝突しているコライダーを持つGameObject。(読み取り専用)
impulse衝突を解消するために互いの接触に適用される合計のインパルス
relativeVelocity衝突した 2 つのオブジェクトの相対的な速度(読み取り専用)
rigidbodyヒットした Rigidbody (読み取り専用)
ヒットしたオブジェクトに Rigidbody がアタッチされていない場合、null を返します。
transformヒットした Transform 情報を返します。(読み取り専用)

Public 関数

GetContact指定したインデックスの接点を取得します
GetContactsこの衝突のすべての接点を取得します

マウスをホバーした時のヒント表示

ToolTipと呼ばれています
次のような効果があります

表示の見え方

コード

[Tooltip("オブジェクトの振幅")]
public float amplitude = 1.0f;

[Tooltip("オブジェクトの周波数")]
public float frequency = 1.0f;

インスペクターでの初期化の方法

コード中で初期値として代入された値とインスペクターの値が違う時、インスペクターの値が使われます
コード中の初期値の値は、最初にアタッチされた時と初期化した時に使われます

Sin波の説明リンク

往復運動の他の方法

PingPong関数を使った方法などがあります

Collider,Unity,学習

Posted by hidepon