uGuiでDrag And Drop処理

#こんな感じになります
http://dividebyzero.sakura.ne.jp/DragAndDrop/index.html
※Unity5.2.2f1でWebGL出力　読み込みにそこそこ時間がかかるので注意。

#参考に視聴したもの
https://www.youtube.com/watch?v=c47QYgsJrWc
https://www.youtube.com/watch?v=bMuYUOIAdnc
https://www.youtube.com/watch?v=P66SSOzCqFU
https://www.youtube.com/watch?v=AM7wBz9azyU

まぁ、これらを見ると「意外と簡単だな？」ということはわかるわけなのですが。

#足りないと思ったのは
* ドラッグしようとした瞬間、ポインタの位置に瞬間移動するのが気に食わない　→　*ちゃんと相対位置取っておけば良いのでは。*
* 入れ替えアニメーションとか付けたい　→　*簡単なUpdateで出来るのでは。*

ということで作ってみました。

#ドラッグされる方
```csharp:DragObject.cs
using UnityEngine;
using UnityEngine.EventSystems;

[RequireComponent(typeof(CanvasGroup))]
public class DragObject : MonoBehaviour ,IDragHandler,IBeginDragHandler,IEndDragHandler
{
    public static DragObject dragObject;
    public Transform parentTransform;
    private Vector3 tapRefPosition;
    private CanvasGroup canvasGroup;
    private Transform canvasTransform;

    public CanvasGroup CanvasGroup { get { return canvasGroup ?? (canvasGroup = gameObject.AddComponent<CanvasGroup>()); }}
    public Transform CanvasTransform { get { return canvasTransform ?? (canvasTransform = GameObject.Find("Canvas").transform); } }

    public void OnBeginDrag(PointerEventData eventData)
    {
        tapRefPosition = (Vector2)transform.position - eventData.position;
        dragObject = this;
        parentTransform = transform.parent;
        transform.SetParent(CanvasTransform);
        CanvasGroup.blocksRaycasts = false;
        CanvasGroup.alpha = 0.5f;
    }

    public void OnDrag(PointerEventData eventData)
    {
        transform.position = Input.mousePosition + tapRefPosition;
    }

    public void OnEndDrag(PointerEventData eventData)
    {
        if (transform.parent == canvasTransform)
        {
            transform.SetParent(parentTransform);
        }
        dragObject = null;
        CanvasGroup.blocksRaycasts = true;
        CanvasGroup.alpha = 1.0f;
    }

    public void Update()
    {
        if (dragObject == null)
        {
            transform.localPosition -= transform.localPosition / 3.0f;
        }
    }
}
```

ポイントは```onBeginDrag```でドラッグが始まる瞬間に、実際の位置とドラッグ開始位置の差分を```tapRefPosition```に確保している
```tapRefPosition = (Vector2)transform.position - eventData.position;```
と、```OnDrag```中はその差分```tapRefPosition```を加味して
```transform.position = Input.mousePosition + tapRefPosition;```
で実際にドラッグしている処理。

そして、```Update```で、```transform.localPosition```を0にイーズアウトで近づける
```transform.localPosition -= transform.localPosition / 3.0f;```
です。

#ドロップされる方
```csharp:DropTarget.cs
using UnityEngine;
using UnityEngine.EventSystems;

public class DropTarget : MonoBehaviour ,IDropHandler{
    public GameObject Item
    {
        get
        {
            if (transform.childCount > 0)
            {
                return transform.GetChild(0).gameObject;
            }
            return null;
        }
    }

    public void OnDrop(PointerEventData eventData)
    {
        if (Item == null)
        {
            DragObject.dragObject.transform.SetParent(transform);
        }
        else
        {
            Item.transform.SetParent(DragObject.dragObject.parentTransform);
            DragObject.dragObject.transform.SetParent(transform);
        }
    }
}
```

こちらは特筆することはなく、DropされたDropObjectのParentをセットしたり、交換したりしているだけです。
前述したDropObjectの```transform.localPosition -= transform.localPosition / 3.0f;```の処理によって、Parentを差し替えるだけでアニメーション付きで移動をするのでラクチンです。

#足りてない所
* Drag中のObjectは一番上に来て欲しいので、無理やり"Canvas"の名前でCanvas探してParentを変更している処理がありますが、名前変更してたら終わるね。　いくらでも手はあると思いますがぱっといい手が思いつかなかったのでペンディングしてます。

もっとuguiのノウハウが貯まるといいなぁ。