※ これは 2020/11/27 時点の Unity 2020.1.15f1 の情報です
最新版では動作が異なる可能性がありますのでご注意ください
前回の UI のプレースホルダーの続き
プレースホルダーとしてすき間ができるようにはなったが、もう少しわかりやすくしたいので、このすき間を明滅させたい
ここに入りますよ~みたいな感じに
スポンサードリンク
まずは明滅する空間をプレハブで作る
名前は Placeholder
にしてこんな感じに設定
明滅をさせたいので blink
という名前のアニメーションを作って張り付けている
このアニメーションの内容はこんな感じ
CanvasGroup
の Alpha
を 1.0 ~ 0.1 の間で反復変化させただけ
CanvasGroup
の Alpha
は直下の Image
だけでなく、子要素も含めた全体の透過率を変化できるので便利
さらにこのアニメーションはいくつか設定を変更
Wrap Mode
を Loop
でループ再生するようにして Debug
表示に切り替えたあと・・・
Legacy
にチェックを入れる
これは Animation Controller
を経由せずに Animation
コンポーネントに直接この Animation Clip
を指定する場合に必要
あとは Draggable.cs
を次のように修正
using System.Collections.Generic; using System.Linq; using UnityEngine; using UnityEngine.EventSystems; [RequireComponent(typeof(CanvasGroup))] public class Draggable : MonoBehaviour { [SerializeField] private GameObject prefab = null; private Transform root; private Transform area; private Transform self; private CanvasGroup canvasGroup = null; private GameObject placeholder = null; public void Awake() { this.self = this.transform; this.area = this.self.parent; this.root = this.area.parent; this.canvasGroup = this.GetComponent<CanvasGroup>(); } public void OnBeginDrag(BaseEventData eventData) { // プレースホルダー生成 this.placeholder = GameObject.Instantiate(this.prefab, this.area); // Instanciate による初期座標を補正 this.placeholder.transform.localPosition = Vector3.zero; // 元の場所にプレースホルダーを残す this.placeholder.transform.SetSiblingIndex(this.self.GetSiblingIndex()); // ドラッグできるよういったん DropArea の上位に移動する this.self.SetParent(this.root); // UI 機能を一時的無効化 this.canvasGroup.blocksRaycasts = false; } public void OnDrag(BaseEventData eventData) { this.self.localPosition = GetLocalPosition(((PointerEventData)eventData).position, this.transform); AddToArea(this.placeholder.transform, this.self.position.x, (PointerEventData)eventData); } private static Vector3 GetLocalPosition(Vector3 position, Transform transform) { // 画面上の座標 (Screen Point) を RectTransform 上のローカル座標に変換 RectTransformUtility.ScreenPointToLocalPointInRectangle( transform.parent.GetComponent<RectTransform>(), position, Camera.main, out var result); return new Vector3(result.x, result.y, 0); } private static void AddToArea(Transform item, float x, PointerEventData eventData) { // 座標位置に DropArea があったら挿入対象にする var dropArea = GetRaycastArea(eventData); if (dropArea == null) { return; } // 挿入位置を x 座標から計算 var area = dropArea.transform; var index = area.childCount; for (var i = 0; i < area.childCount; i++) { if (x < area.GetChild(i).position.x) { index = i; if (item.GetSiblingIndex() < index) index--; break; } } item.SetParent(area); item.SetSiblingIndex(index); } public void OnEndDrag(BaseEventData eventData) { // プレースホルダーを破棄 Destroy(this.placeholder); // DropArea 移動 AddToArea(this.self, this.self.position.x, (PointerEventData)eventData); this.area = this.self.parent; // UI 機能を復元 this.canvasGroup.blocksRaycasts = true; } /// <summary> /// イベント発生地点の DropArea を取得する /// </summary> /// <param name="eventData">イベントデータ</param> /// <returns>DropArea</returns> private static DropArea GetRaycastArea(PointerEventData eventData) { var results = new List<RaycastResult>(); EventSystem.current.RaycastAll(eventData, results); return results.Select(x => x.gameObject.GetComponent<DropArea>()) .FirstOrDefault(x => x != null); } }
SerializeField
経由で Placeholder
のプレハブを渡せるようにして、これまでコードで生成していたプレースホルダーを GameObject.Instantiate()
を利用して生成するようにしただけ
最後に Placeholder
のプレハブを Draggable.cs
を張り付けた Item
らに設定する
さてお試し
できたできた!