【Unity】ドアの開閉イベントを作る

投稿者: | 2020-12-15

レイの当たった場所を掴むで掴めるアイテムクラスを作ったので、これを継承してドアクラスを作ってみました。

ドアにはスクリプトとRigidbodyとヒンジジョイントを付けました。

ヒンジジョイントの軸はドアの右端で上下方向に設定しました。さらに、Use LimitsのチェックをいれてLimitsのMin、Maxでドアの開く範囲を設定します。

これはEdit Angular Limitsをクリックするとシーンビューでハンドルをドラッグして設定できます。

ドアクラスはアイテムクラスを継承しました。

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

public class Door : Item
{

    bool opened;
    HingeJoint hj;

    private void Start()
    {
        rb = GetComponent<Rigidbody>();
        hj = GetComponent<HingeJoint>();
    }

    private void Update()
    {
        if (operation != null) operation();

        // 開いているとき
        if(opened)
        {
            // 閉まっているへ
            if(Mathf.Abs(hj.angle) < 5f)
            {
                opened = false;
                ProgressManager2.GetInstance().DoorEvent(gameObject, new DoorEventArgs() { open = opened });
            }
        }
        // 閉まっているとき
        else
        {
            // 開いているへ
            if(Mathf.Abs(hj.angle) >= 5f)
            {
                opened = true;
                ProgressManager2.GetInstance().DoorEvent(gameObject, new DoorEventArgs() { open = opened });
            }

        }
       
    }
}

ドアクラスにStart()とUpdate()を書かなければアイテムと同じ様にドアも動かせますが、書くと上書きされて何もしなくなります。なので、アイテムクラスと同じ様にリジッドボディの取得などを書いています。

この時に使う変数はドアクラスで宣言する必要はありませんが、アイテムクラスでprivateになっているとエラーになるので、protectedにしました。protectedにするとクラス内部と派生クラスのインスタンスからアクセスできます。

// Itemクラス
protected Rigidbody rb;
protected Action operation;

そして、Update()の中で、開いているときに、HingeJoint.angleが小さくなると閉じて、進行管理のドアのイベントを呼びます。閉まっている時にangleが大きくなると開けます。

// DoorクラスのUpdate()
// 開いているとき
if(opened)
{
    // 閉まっているへ
    if(Mathf.Abs(hj.angle) < 5f)
    {
        opened = false;
        ProgressManager2.GetInstance().DoorEvent(gameObject, new DoorEventArgs() { open = opened });
    }
}
// 閉まっているとき
else
{
    // 開いているへ
    if(Mathf.Abs(hj.angle) >= 5f)
    {
        opened = true;
        ProgressManager2.GetInstance().DoorEvent(gameObject, new DoorEventArgs() { open = opened });
    }

}

HingeJoint.angleは開始時が0なので、ドアを置く向きは無関係です。開く方向によって正負が変わるので絶対値を使っています。

進行管理のスクリプトでは、ドアのイベントを宣言して、そのイベントを呼ぶメソッドを定義しています。

// 進行管理クラス
delegate void DoorEventHandler(GameObject sender, DoorEventArgs e);
event DoorEventHandler doorEvent;

public void DoorEvent(GameObject sender, DoorEventArgs e)
{
    if (doorEvent != null) doorEvent(sender, e);
}

また、同じスクリプトに、ドアのイベントの第2引数に渡すオブジェクトのクラスを書いています。その中のプロパティでドアが開いたのか閉じたのかを判別するようにしました。ドアが開いたときはtrueにして渡します。

public class DoorEventArgs
{
    public bool open { get; set; }
}

// Doorクラス
ProgressManager2.GetInstance().DoorEvent(gameObject, new DoorEventArgs() { open = opened/*=true*/ });

これでドアの開閉イベントを作れました。進行管理でドアイベントの変数の中身を入れ替えます。

// 白いCubeを放す
void ReleaseItem1(GameObject sender, ItemEventArgs e)
{
    if (e.itemName == "Cube1")
    {
        releaseItem = null;
        text.text = "ドアを開ける";
        doorEvent = DoorEvent1; // ドアイベントに1つ目を入れる
    }
}

// ドアを開ける
void DoorEvent1(GameObject sender, DoorEventArgs e)
{
    if(e.open)
    {
        text.text = "ドアを閉める";
        doorEvent = DoorEvent2; // ドアイベントに2つ目を入れる
    }
}

// ドアを閉める
void DoorEvent2(GameObject sender, DoorEventArgs e)
{
    if (!e.open)
    {
        doorEvent = null; // ドアイベントを空にする
        text.text = "2秒待つ";
        updateAction = UpdateAction1;
    }
}

コメントを残す

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