【Unity】HingeJointって便利なんよ…野球盤みたいにバット振り回してみた


概要

こちらの記事ではHingeJointについて紹介していきます。
サンプルコードをコピペすれば誰でも簡単に実装することができるので、初心者の方でも最悪理解しなくても使えるようにします!
できるだけ解説も入れていきますが、個人的な解釈が多いので参考程度にお願いします☺️

動作環境

MacOS : Catalina 10.15.7
Unity : 2019.4.16f1

HingeJointで野球盤のバットを作ってみる

下準備

バッティングセンターをイメージして作っていきます。
バッター(ただ棒)、ピッチャー(ボールを生成するスポナー)を用意しましょう。


今回はCubeで棒を作成し、Create Emptyでボールを生成するオブジェクトを用意しました(実態を持たないので画像の矢印がスポナーです)。

HingeJoint使っていくよ

それでは早速HingeJointを入れていきます。
HingeJointはComponentなので、棒のオブジェクトにあるAdd Componentから、「Physics=>Hinge Joint」を選んでHingeJointを付与しましょう!

HingeJointを無事付与できたら次は設定を行なっていきます。
Use Springのチェックをつけます。これにチェックをつけないとスイングしてくれません。

続いてAnchorとAxisの説明をします。
こちらはスイングする回転軸を設定することができます。
HingeJointをつけたオブジェクトに近づいて確認してみると、実は新しい矢印が一つ小さく追加されています(以下の画像の茶色いやつ)。

この茶色い矢印を軸に回転するのでこのままだと棒はバットを振るようなスイングにはなりません。
ので、まずはAxisをいじって回転軸の向きを変えます。
今回はxy平面に対してスイングさせていくので、Axisのx,yには0を、zには1を入れます(おそらく奥を向いてくれてるはず)。

続いて、このままだと棒の真ん中を支点に回転してしまうので、その支点位置を変更します。
Anchorの値をいじって棒の左側に矢印がくるように調整しましょう。
以下の画像のように矢印が移動して向きが変わっていればOKです。
(自分の場合、棒の左端に寄せています。)

早速実装していきます!

ピッチャーの方のコードも載せますが、今回はHingeJointの説明をしたいので割愛させていただきます🙏
以下ボールを生成するスクリプトになります。スポナーにアタッチしましょう。

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

public class PicherScript : MonoBehaviour
{
    float lancherTimer;
    public GameObject ball;

    void Update()
    {
        lancherTimer += Time.deltaTime;
        BallLancher();
    }

    void BallLancher()
    {
        if (lancherTimer > 3)
        {
            Instantiate(ball, this.gameObject.transform.position, Quaternion.identity);
            lancherTimer = 0;
        }
    }
}

今回のballは、Sphereをそのまま用いています。SphereをPrefabにしてそれを生成元にしましょう。
一応仕様を話すと、lancherTimerが0になったらBallを生成するようになっています。
ので、lancherTimerの数字をいじれば生成頻度をいじることができます👍
また、Ballには以下のスクリプトをアタッチしておきましょう。

BallMoveScript

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

public class BallMoveScript : MonoBehaviour
{
    [SerializeField] float speed = 5.0f;

    private Rigidbody rb;

    void Start()
    {
        rb = this.gameObject.GetComponent<Rigidbody>();
    }

    void Update()
    {
        Move();
        Destroy(this.gameObject, 4.0f);
        Debug.Log(rb.velocity);
    }

    void Move()
    {
        rb.velocity += new Vector3(0, -speed * Time.deltaTime, 0);
    }
}

速度を与えてバットに向かって飛んでくるようになっています。
speedをいじって飛んでくる速さを調整しましょう!
最後に本命のバットです。コードを書いて棒のオブジェクトにアタッチしてください。

SwingScript.cs
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class SwingBatScript : MonoBehaviour
{

    public float spring = 40000;
    public float damper = 1000;
    public float openAngle = 75;
    public float closeAngle = -90;

    HingeJoint hj;

    JointSpring spr;

    void Start()
    {
        hj = GetComponent<HingeJoint>();
        spr = hj.spring;
        spr.targetPosition = closeAngle;
    }

    void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            openBat();
        }

        if (Input.GetMouseButtonUp(0))
        {
            closeBat();
        }
    }

    public void openBat()
    {
        spr.spring = spring;
        spr.damper = damper;
        spr.targetPosition = openAngle;
        hj.spring = spr;
    }

    public void closeBat()
    {
        spr.spring = spring;
        spr.damper = damper;
        spr.targetPosition = closeAngle;
        hj.spring = spr;
    }
}

コードの解説

SwingScriptの解説を行なっていきます。
Update()内からいきます。

SwingScript.cs

    public float spring = 40000;
    public float damper = 1000;
    public float openAngle = 75;
    public float closeAngle = -90;

    HingeJoint hj;

    JointSpring spr;

HingeJointはtargetPositionという角度が存在し、その角度に向かって先ほどの茶色い矢印を軸にオブジェクトを回転してくれます。
なのでtargetPositionがどの角度なのか、どれくらいの速度でそのtargetPositionに向かってくれるのか、を設定する必要があるので、上記のような変数宣言を行っています。

「spring」=>この値を大きくすればするほどtargetPositionに向かう速さが速くなる。
「damper」=>この値を大きくするほどtargetPostionに向かう速さが遅くなる(正しくは角速度の値を調整しています)。
「openAngle」,「closeAngle」=>それぞれバットを振った後の角度、振るまえの角度を想定して設定しています。

続いてStart()のなかをみていきます。

SwingScript.cs

    void Start()
    {
        hj = GetComponent<HingeJoint>();
        spr = hj.spring;
        spr.targetPosition = closeAngle;
    }

変数宣言のところでHingeJointの情報をいれるための変数「hj」を用意したのでまずGetComponentで取得します。
springの中にtargetPositionと呼ばれる目標角度を初期設定するために最初に予めcloseAngleを代入しています。

続いてUpdate()内をみていきます。

SwingScript

void Update()
    {
        if (Input.GetMouseButtonDown(0))
        {
            openBat();
        }

        if (Input.GetMouseButtonUp(0))
        {
            closeBat();
        }
    }

左クリックを押したらバットを振り、クリックの指を離したらバットを戻すようにトリガーの設定をしています。

続いてopneBat()とcloseBat()の中身を見ていきます。

SwingScript

public void openBat()
    {
        spr.spring = spring;
        spr.damper = damper;
        spr.targetPosition = openAngle;
        hj.spring = spr;
    }

    public void closeBat()
    {
        spr.spring = spring;
        spr.damper = damper;
        spr.targetPosition = closeAngle;
        hj.spring = spr;
    }

先ほどの変数宣言で用意した値を代入しています。

プレビューして確認してみよう!

実際にクリックするとopenAngle(75度)に向かって棒が回転したり、クリックを離すとcloseAngle(-90度)に向かって棒が戻っているのが確認できましたか?
実際にボールを打てるとめっちゃ気持ちいですよね!

以上で終わります!ここまでお疲れ様でしたー!
またどこかで〜👋