しっぽを追いかけて

ぐるぐるしながら考えています

Unity と猫の話題が中心   掲載内容は個人の私見であり、所属組織の見解ではありません

Unity でひっぱり操作を使ってボールを飛ばす

※ これは 2018/10/20 Unity 2018.3.0b6 時点の情報です

最新版では動作が異なる可能性がありますのでご注意ください

前々回に Unity でボールを弾き飛ばしてみました

今回はこれをさらに発展させて、飛ばす方向をマウスドラッグのひっぱる操作で指定するようにしてみます

f:id:matatabi_ux:20181020140458p:plain

まずは飛ばす方向の表示用に Hierarchy ビューで Ball を選択後、右クリックメニューの CreateEmpty で GameObject を追加します

f:id:matatabi_ux:20181020135735p:plain

名前は Direction に改名し、LineRenderer をアタッチ

f:id:matatabi_ux:20181020135810p:plain

Receive Shadow ははずし、Material には新しく追加した Direction (Particle/Standard Unlit)を指定

Positions は2座標とも Ball の初期位置に合わせ、Width は 0.02、Color は黄色→赤色のグラデーションを設定しました

さらに Ball.cs を次の通り変更

using UnityEngine;

[RequireComponent(typeof(Rigidbody))]
public class Ball : MonoBehaviour
{
    /// <summary>
    /// 物理剛体
    /// </summary>
    private Rigidbody physics = null;

    /// <summary>
    /// 発射方向
    /// </summary>
    [SerializeField]
    private LineRenderer direction = null;

    /// <summary>
    /// 最大付与力量
    /// </summary>
    private const float MaxMagnitude = 2f;

    /// <summary>
    /// 発射方向の力
    /// </summary>
    private Vector3 currentForce = Vector3.zero;

    /// <summary>
    /// メインカメラ
    /// </summary>
    private Camera mainCamera = null;

    /// <summary>
    /// メインカメラ座標
    /// </summary>
    private Transform mainCameraTransform = null;

    /// <summary>
    /// ドラッグ開始点
    /// </summary>
    private Vector3 dragStart = Vector3.zero;

    /// <summary>
    /// 初期化処理
    /// </summary>
    public void Awake()
    {
        this.physics = this.GetComponent<Rigidbody>();
        this.mainCamera = Camera.main;
        this.mainCameraTransform = this.mainCamera.transform;
    }

    /// <summary>
    /// マウス座標をワールド座標に変換して取得
    /// </summary>
    /// <returns></returns>
    private Vector3 GetMousePosition()
    {
        // マウスから取得できないZ座標を補完する
        var position = Input.mousePosition;
        position.z = this.mainCameraTransform.position.z;
        position = this.mainCamera.ScreenToWorldPoint(position);
        position.z = 0;

        return position;
    }

    /// <summary>
    /// ドラック開始イベントハンドラ
    /// </summary>
    public void OnMouseDown()
    {
        this.dragStart = this.GetMousePosition();

        this.direction.enabled = true;
        this.direction.SetPosition(0, this.physics.position);
        this.direction.SetPosition(1, this.physics.position);
    }

    /// <summary>
    /// ドラッグ中イベントハンドラ
    /// </summary>
    public void OnMouseDrag()
    {
        var position = this.GetMousePosition();
[f:id:matatabi_ux:20181020141708g:plain]
        this.currentForce = position - this.dragStart;
        if (this.currentForce.magnitude > MaxMagnitude * MaxMagnitude)
        {
            this.currentForce *= MaxMagnitude / this.currentForce.magnitude;
        }

        this.direction.SetPosition(0, this.physics.position);
        this.direction.SetPosition(1, this.physics.position + this.currentForce);
    }

    /// <summary>
    /// ドラッグ終了イベントハンドラ
    /// </summary>
    public void OnMouseUp()
    {
        this.direction.enabled = false;
        this.Flip(this.currentForce * 6f);
    }

    /// <summary>
    /// ボールをはじく
    /// </summary>
    /// <param name="force"></param>
    public void Flip(Vector3 force)
    {
        // 瞬間的に力を加えてはじく
        this.physics.AddForce(force, ForceMode.Impulse);
    }
}

マウス押下時に固定力量で弾いていたところを、ドラッグによって発射方向を描画し、マウスボタンから手をはなしたときに発射するようにしました

マウスのドラッグ座標を Camera を利用して画面座標からワールド座標に変換しているところがポイントです

コード修正が終わったら、UnityEditor に戻り Ctrl +R で変更反映後、Direction を Ball.cs の Direction プロパティにドラッグ指定で設定します

f:id:matatabi_ux:20181020140951p:plain

ここまで終わったらお試し

f:id:matatabi_ux:20181020141708g:plain

サクッとできました