【Unity】扉をノックして勢いよく開ける

投稿者: | 2020-10-02

キー入力でドアをノックして勢いよく開きます。

まずCubeで簡単にドアを作って、Hinge Jointとスクリプト、オーディオソースコンポーネントを付けました。RigidbodyとBoxコライダーは元々付いています。

Hinge Jointは軸をドアの側面で上下方向に向くようにして、ドアを開けるときのためのSpringを設定します。そして、ドアが閉まっている状態から全開の状態までの制限をかけます。

軸や回転の制限の状態はEdit Angular Limitsをクリックして、シーンビューで確認できます。

オーディオソースは、Play On Awake とLoopのチェックを外しておきました。

ドアのスクリプトではまず今のLimitsの値を保存しておきます。

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

public class DoorScript2 : MonoBehaviour
{
    HingeJoint hj;
    JointLimits defaultLimits;
    Rigidbody rb;
    AudioSource audioSource;
    [SerializeField] AudioClip[] audioClips;

    private void Awake()
    {
        hj = GetComponent<HingeJoint>();
        defaultLimits = hj.limits;
        hj.useLimits = true;
        hj.useSpring = false;

        rb = GetComponent<Rigidbody>();
        audioSource = GetComponent<AudioSource>();
    }
    // Start is called before the first frame update
    void Start()
    {

    }

    public void Lock(bool b)
    {
        if (b)
        {
            JointLimits jl = hj.limits;
            jl.max = 3f;
            jl.min = -3f;
            jl.bounciness = 0.4f;
            hj.limits = jl;       
        }
        else {
            hj.limits = defaultLimits;
        }
    }

    public void Open()
    {
        Lock(false);

        hj.useSpring = true;

        audioSource.clip = audioClips[1];
        audioSource.Play();
    }

    public void Knock()
    {
        rb.AddForce(transform.forward * 10f, ForceMode.Impulse);

        audioSource.clip = audioClips[0];
        audioSource.Play();
    }

}

そして、ドアをロックする/開ける/ノックするためのメソッドを作りました。ロックするときは、Limitsの最大と最少の幅を小さくして、ドアが少ししか動かないようにします。Bouncinessを下げないと、ノックしたときに上下限で強くバウンドしてドアが激しく震えてしまいます。

ロックを解除するときは、デフォルトの制限値に戻します。

ドアを開くときは、ロックを排除して、Use Springをtrueにします。Hinge Jointコンポーネントで設定した、Target Positionの角度までSpringの力で動きます。Damperで速度を低下させます。

ノックするときは、Rigidbody.AddForceで瞬間的に力を加えます。力の方向は、ドアの広い面がZ軸(Local)を向いているのでtransform.forwardにしました。

public void Knock()
{
    rb.AddForce(transform.forward * 10f, ForceMode.Impulse);

    audioSource.clip = audioClips[0];
    audioSource.Play();
}

そして、キー入力を受けてドアのメソッドを呼ぶためのスクリプトを空のゲームオブジェクトに追加しました。

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

public class GameScript3 : MonoBehaviour
{
    [SerializeField] DoorScript2 doorScript;

    // Start is called before the first frame update
    void Start()
    {
        doorScript.Lock(true);
    }

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

        if (Input.GetKeyDown(KeyCode.E))
        {
            doorScript.Knock();

        }
        else if (Input.GetKeyDown(KeyCode.R))
        {
            doorScript.Open();
        }
    }
}

Start()でドアにロックをかけるメソッドを呼んでいます。このメソッドではドアのHinge Jointが入った変数を使っていますが、GetComponent()をドアのスクリプトのStart()でやると、ドアにロックをかけるときにエラーが出ることがあるので、GetComponent()はAwake()でやっています。

// ドアのスクリプト
HingeJoint hj;

// ...

private void Awake()
{
    hj = GetComponent<HingeJoint>();

    // ...
}
// Start is called before the first frame update
void Start()
{

}

public void Lock(bool b)
{
    if (b)
    {
        JointLimits jl = hj.limits;
        jl.max = 3f;
        jl.min = -3f;
        jl.bounciness = 0.4f;
        hj.limits = jl;       
    }
    else {
        hj.limits = defaultLimits;
    }
}

これでドアをノックして勢いよく開けられました。

コメントを残す

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