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

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

ドラッグ&ドロップで3Dオブジェクトを移動したり取得したりしよう!

3D脱出ゲームの勉強と試行中。

しまづさんのyoutubeシリーズ

www.youtube.com

を、金曜・土曜・日曜で
# 08ズームパネルの作成
# 09ズームオブジェクトの作成
# 10ズームオブジェクトの回転
# 11アイテムの設置
# 12 パスワードギミックの作成
# 13パスワードクリアの実装
# 14カメラの回転
# 15カメラのズーム
# 16設計(フローチャート)の作成
# 17モデルのインポート編
# 18モデルの設定
#19 アイテムの取得 メイン編
まで、一気に学習しました。

その関係で、オブジェクトをドラッグで移動したり、所定の枠に嵌めたりする方法の説明を、スタジオしまづさんのサロンで
以前にしていた事があったのを思い出したので、過去の記録を探してみたけれど、どうしても見つかりませんでした。
仕方がないので、しまづさんにもう一度説明をお願いしたところ、以前より濃い内容の説明動画をyoutubeに上げてくださいました😄

www.youtube.com

ありがたいことに冒頭に僕の紹介までしてくださいました!🙇
いつもながら判りやすい説明で、理解しやすかったです。
Event Triggerコンポーネントを今まで全く使っていなかったので、すごく勉強になりました。

youtubeでしまづさんが仰られた様に、3D脱出ゲームに組み込みたい機能だったので、
しまづさんのyoutubeシリーズで作成した3D脱出ゲームに、Event Triggerを使うドラッグを早速組み込んでみることにしましたが
youtubeは2Dをベースに説明されており、僕が作成している3Dには、そのままでは使えません。

座標変換の方法は、以前に皿割りゲームで勉強したことがあり

amaniku.hatenablog.com

その時はワールド座標をUI座標に変換する方法でしたが、この時の経験のおかげで、逆の変換についても理解しやすかった様に思います。

要はxとyの世界のスクリーン座標を、xとyとzのワールド座標に変換するためには、どうしても、zに相当するものが必要になってくるので、
まずは、カメラとCanvasの位置関係から、ドラッグしたオブジェクトをどう見えるようにしたいかを考えて、
カメラからどれくらい離した座標で扱うかを決めてやれば良いわけです。

僕の場合は、下図の様に2枚のCanvasがカメラから2.5と3.5の距離にあり、それより手前にドラッグしたオブジェクトを見せたいと
思っているので、距離を2にしました。

次に、オブジェクトをカメラから2の距離で、そのままの大きさで表示させると、カメラに近づきすぎて画面がオブジェクトに占有されてしまうので、ドラッグ中はスケールを縮小させることにしました。

オブジェクトの縮小率を一定にするためには、現在のオブジェクトの高さを調べる必要がありますが、
これも以前に、Rect Transformを使う方法の記事を見た覚えがあったので、今回も採用することにして、オブジェクトのTransformをRectTransformに変更しました。

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;

public class DragObj : MonoBehaviour, IBeginDragHandler, IDragHandler, IEndDragHandler
{
    Transform ObjStartTransform;//ドラッグ開始時のTransform格納用。
    Vector3 ObjStartPos;//Positionを格納用。
    Vector3 ObjStartRot;//回転を格納用。
    Vector3 ObjStartScale;//スケールを格納用。

    CanvasGroup canvasGroup;
    public bool IsDropSuccess=false;

    [SerializeField]RectTransform rectTransform;//Rect Transform格納用。
    Vector3 screenPosition;

    private void Awake()
    {
        canvasGroup = GetComponent<CanvasGroup>();
    }

    public void OnBeginDrag(PointerEventData eventData)
    {
        ObjStartTransform = transform;
        ObjStartPos = transform.position;
        ObjStartRot = transform.rotation.eulerAngles;
        ObjStartScale = transform.localScale;
        canvasGroup.blocksRaycasts = false;
        IsDropSuccess=false;

        rectTransform=eventData.pointerDrag.GetComponent<RectTransform>();
        float currentHighest = rectTransform.sizeDelta.y; //オブジェクトの高さを取得。
        float scaleFactor=10/currentHighest;//オブジェクトの高さを10にするスケールを算出。
                
        transform.localScale=new Vector3(scaleFactor,scaleFactor,scaleFactor); //算出したスケールを適用する。
    }

    public void OnDrag(PointerEventData eventData)
    {
        screenPosition=Input.mousePosition; //マウスポインタのスクリーン座標を取得

        //スクリーン座標をワールド座標に変換
        var scrPos=new Vector3(screenPosition.x,screenPosition.y,2f);
        var worldPos=Camera.main.ScreenToWorldPoint(scrPos);

        //ワールド座標に変換した座標をオブジェクトの座標に代入
        transform.position = worldPos;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        if(screenPosition.x>35 && screenPosition.x<185    
         && screenPosition.y>35 && screenPosition.y<185)//画面右下のカバンのパネルの範囲
        {
            eventData.pointerDrag.transform.GetComponent<PickUpObj>().ClickObj();
            canvasGroup.blocksRaycasts = true;
            return;
        }

        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;
    }
}

元々のしまづさんのyoutubeシリーズでは、オブジェクトをクリックする事で、アイテムとして取得する方法になっていますが、
改造版ではItem Boxパネルのカバンにドラッグする事で、アイテムとして取得するようにしています。

このために、ドラッグしたオブジェクトをItem BoxパネルのCanvasより手前に表示したかったわけです。

www.youtube.com

次は、所定位置にアイテムを設置する機能と、Item Boxからアイテムをドラッグして取り出せるようにしてみます。