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

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

3D脱出ゲーム:ItemBoxをドラッグできるようにしよう。

前回からだいぶん間が空いてしまいました😭
ゲーム作成をしていなかったわけではなく、あまりにもプログラミングや仕組み作りが楽しすぎて、ついついブログがおざなりになってしまってました💦

前回までで基本システムの構想はできたので、いよいよゲームにしていく段階に入りました。
脱出ゲームの部屋として、色々とアセットストアを探っていて、イメージに近いものが見つかりました。

assetstore.unity.com

このアセットで部屋を作り始めましたが、画面の一番下に表示されているアイテムボックスがどうにも気になり始めたので
アイテムボックスを開閉する様に改造する事にしました。
そうすると、アイテムボックスのリュックマークにアイテムをドラッグして取得する仕組みがうまくいかないので、
結局、アイテムの取得方法はクリックに戻すことになるのですが、そこは仕方ありません。🤣

パネルにそれっぽいイメージを重ねて、固定のアイテムボックスからSlotを移植して、こんな感じになりました。

開閉できるウィンドウ型にしました。
ウィンドウ型にしたので、やっぱりドラッグで移動できるようにもしようと思います。
前回まで散々学んだドラッグの仕組みの応用でできそうですし。😁

ということで、作成したスクリプトはこんな感じです。

using UnityEngine;
using UnityEngine.EventSystems;

public class DragUI : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler

{
    Vector3 screenPosition;
    [SerializeField]Canvas canvas;

    public void OnBeginDrag(PointerEventData eventData)
    {
            screenPosition=Input.mousePosition; //マウスポインタのスクリーン座標を取得
            var scrPos=new Vector3(screenPosition.x,screenPosition.y,canvas.planeDistance+0.01f)
            var worldPos=Camera.main.ScreenToWorldPoint(scrPos);
    }

    public void OnDrag(PointerEventData eventData)
    {

            screenPosition=Input.mousePosition; //マウスポインタのスクリーン座標を取得
            var scrPos=new Vector3(screenPosition.x,screenPosition.y,canvas.planeDistance+0.01f);//2fはカメラからキャン
            var worldPos=Camera.main.ScreenToWorldPoint(scrPos);
            transform.position = worldPos;
        
    }

    public void OnEndDrag(PointerEventData eventData)
    {
    }

}
canvas.planeDistance

と言うのは、Canvasの平面距離を取得するプロパティです。
今までは数値を直接入力していたのですが、やっぱり、マジックナンバーはよくないと思い、調べてみたら、ちゃんと取得するプロパティがありました。

で、動作確認ですが、

youtu.be

ItemBoxのTransform.positionに直接マウスの座標をぶちこんでいるので、ItemBoxのピポットとのズレを一瞬で移動していて、ItemBoxがぴょこっと瞬間移動しているように見えています。
もちろん、明らかな失敗です。😭
考えてみれば、今までのドラッグでも、このマウスの座標とピポットのズレは発生していたと思われるのですが、
今までのObjectの移動では、Objectのサイズ縮小を行っていたので、このズレに気づいていなかったのかもしれません😅

さっそく色々な記事を読み漁りながら、対策方法を考えていたら、今日もぴったりな解決方法が見つかりました。😁

www.youtube.com

あのゲームの作り方さんのyoutubeがズバリ、この問題の解決方法でした。

ざっくり要約すると、
ドラッグを開始するときに、マウスの座標とItemBoxのTransform.positionの差分をoffsetとして変数に確保しておき、
ドラッグ中に、ItemBoxのTransform.positionにマウス座標を入れるときに、offsetで補正をかけるという仕組みです。

早速、先ほどのスクリプトに導入。

using UnityEngine;
using UnityEngine.EventSystems;

public class DragUI : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler

{
    Vector3 m_offset;

    Vector3 screenPosition;
    [SerializeField]Canvas canvas;

    public void OnBeginDrag(PointerEventData eventData)
    {

            screenPosition=Input.mousePosition; //マウスポインタのスクリーン座標を取得
            var scrPos=new Vector3(screenPosition.x,screenPosition.y,canvas.planeDistance+0.01f);
            var worldPos=Camera.main.ScreenToWorldPoint(scrPos);
            m_offset=new Vector3( //ここでoffsetに座標の差分を格納する。
                transform.position.x-worldPos.x,
                transform.position.y-worldPos.y,
                worldPos.z 
            );
    }

    public void OnDrag(PointerEventData eventData)
    {

            screenPosition=Input.mousePosition; //マウスポインタのスクリーン座標を取得
            var scrPos=new Vector3(screenPosition.x,screenPosition.y,canvas.planeDistance+0.01f);
            var worldPos=Camera.main.ScreenToWorldPoint(scrPos);

            transform.position = new Vector3(worldPos.x+m_offset.x,worldPos.y+m_offset.y,worldPos.z);//offset分補正している。
        
    }

    public void OnEndDrag(PointerEventData eventData)
    {
    }
}

これでItemBoxが自由に動かせる様になりました。

youtu.be

ドラッグの仕組みは、色々と応用が聞いて面白いですね。
Event Triggerも色々と使い所が多く、早いうちに学習できたのは、かなりありがたいと思います。

さて、次は、アイテムのズーム機能の改造を行います。