Unity勉強中!あこがれだったプログラマーに今からなろう!

昔あこがれだったプログラマー。今からでもUnityを勉強してみようと思い立ち、チャレンジ開始! Unity勉強メモや、悪戦苦闘な日々の記録です。

3D脱出ゲーム:ドラッグしたアイテムを所定位置にセットできるようにしよう。

先週は仕事に明け暮れて、ゲーム制作をするほど時間を確保できませんでした。
ただ特に忙しくなる最終週の前に、Unityroomのゲームジャムに参加していたので、結果の確認がてら他の人の作品を毎日遊んでいました。

他の人のゲームを遊ぶのは、色々と勉強になり楽しいものです。
ゲームジャンルも多種多様ですが、何より、テーマの「かわる」をどう捉えるかも様々。
素晴らしい発想が多く、いかに自分がまだ「自分の常識」に囚われているかを思い知らされました。

作品の中には、一週間で作り上げたとは思えないほど、完成度が高く、ハイクオリティーなものもあり
僕もまだまだ頑張らないといけないなと感じました。
「自分の常識」を壊して、自由な発想ができるように、もっといろいろな事を学んでいきたいと思います。

さて、年度末の繁忙期もようやくひと段落。
そろそろ、またゲーム制作を再稼働していこうと思います。

UniTaskの勉強というか実験もしたかったけれど、ゲームジャム参加の前にやっていた3D脱出ゲームの続きを再開することにしました。

しかし、一週間ゲーム制作から離れただけなのに、自分が作ったプログラムを理解するのにやたら時間がかかります。
どこで何をやっているのか、何が何やら、、、
コメントで注釈をいれる必要性をひしひしと感じました。

とにもかくにも、ある程度思い出したので、
先週の続き、ドラッグしたアイテムをドロップした場所が、所定位置であれば、そこにセットされる仕組み作りです。
下図にあるシリンダーを右のステージ上にセットできるようにします。

今は、シリンダーとステージは横並びの位置にいますが、
先週までに作成した仕組みで、シリンダーをドラッグすると、シリンダーは縮小され、Canvasの手前に移動されるようになっています。
そのため座標が違いすぎて、EventTriggerのDropでは判定できません。

そのため別の手段で、ドラッグしたObjectの位置が、ステージの手前なのかを調べる必要があります。
いろいろな方法があると思いますが、僕の場合は使い慣れてきたRaycastを使う事にしました。

Objectのドラッグが終了するOnEndDragでObjectからカメラと反対方向にRayを放ち、ステージにヒットしたら
ステージの関数を呼び出して、Objectをステージにセットさせるという計画。

まずはObjectがセットされる位置を格納して、その位置を返すスクリプトを作って、ステージにアタッチしてやる。

using UnityEngine;
using DG.Tweening;

public class DropObj : MonoBehaviour
{
    [SerializeField] private Transform SetPos;

    public void SetPosition(GameObject other)
    {
        var TriggerObj=other;
        TriggerObj.transform.DOMove(SetPos.position,0.5f);//0.5秒かけてSetPosの位置に移動
        TriggerObj.GetComponent<DragObj>().IsDropSuccess=true;//オブジェクトのIsDropSuccessをtrueにする
    }
}

次に、Objectからカメラと反対方向にRayを放って判定する。
カメラと逆の方向を出すには、Objectのpositionからカメラのpositionを引いてやって、それを正規化してやればOK。
ステージにヒットしたら、ステージのメソッドを呼び出してセット位置を取得する仕組み。
最後に、セット位置を取得できていればその位置で、そうでなければドラッグ開始位置でObjectの大きさと向きを元に戻してやる。

    public void OnEndDrag(PointerEventData eventData)
    {
        //省略〜

        //〜省略

        //カバンの位置でない場合、Rayを飛ばしてオブジェクトが何かのセット位置に当たっているかを調べる。
        Vector3 direction = (transform.position - Camera.main.transform.position).normalized;
        Ray ray = new Ray(transform.position, direction);
        RaycastHit hit;
        int layerMask = 1 << LayerMask.NameToLayer("SetObjectStage");

        if (Physics.SphereCast(ray, 0.5f, out hit, 12, layerMask))
        {
            Debug.Log("Hit " + hit.collider.name);
            //当たっていれば、そのオブジェクトのSetPositionメソッドを呼び出す。
            hit.collider.gameObject.GetComponent<DropObj>().SetPosition(gameObject);
        }

        Invoke("CheckPosition",0.03f);
    }

    void CheckPosition()
    {
        if(IsDropSuccess)
        {
            transform.localScale = ObjStartScale;
            transform.rotation = Quaternion.Euler(ObjStartRot);
        }
        else
        {
            transform.position = ObjStartPos;
            transform.rotation = Quaternion.Euler(ObjStartRot);
            transform.localScale = ObjStartScale;
        }
        canvasGroup.blocksRaycasts = true;

    }

動きはこんな感じになります。
www.youtube.com