質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

8633閲覧

ピンチの中心とした拡大縮小について

sakakura

総合スコア7

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

1クリップ

投稿2018/01/30 07:17

前提・実現したいこと

unityを始めて1週間くらいの初心者です。
現状、乙女ゲーのようなアプリを作成しようとしており
ギャラリー機能としてキャラの立ち画をピンチによる拡大縮小を
行おうとしております。

現状下記のサイトを参考にスクリプトを作成しています。
http://kohki.hatenablog.jp/entry/Unity-uGUI-Pinch-Scaling-forMobile

やりたい事としては参考サイトをベースとして
ピンチを行った際の中心を軸として拡大縮小を行いたいのです。

改良の方法が分かる方がいらっしゃいましたら
ご教授いただければと思います。

試したこと

下記のスクリプトでピンチの中心点に移動したオブジェクトを
上記参照サイトの「Content」の親に設定するように
「Content.transform.parent = 中心点オブジェクト.transform;」を
参考サイトのスクリプトに追加しましたがうまく行きませんでした。

using UnityEngine; using System.Collections; public class NewBehaviourScript : MonoBehaviour { RectTransform rectTransform = null; [SerializeField] Transform target = null; void Awake() { rectTransform = GetComponent<RectTransform>(); } void Update() { if (Input.touchCount == 2) { Touch touchZero = Input.GetTouch(0); Touch touchOne = Input.GetTouch(1); if (touchOne.phase == TouchPhase.Began) { Vector3 screen_point = (touchZero.position + touchOne.position) / 2; screen_point.z = 2.0f; rectTransform.position = screen_point;    Debug.Log(screen_point); } } } }

補足情報(FW/ツールのバージョンなど)

Unity 2017.3

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答1

0

ベストアンサー

UI関連は不慣れなうえモバイル向けに製作したことがなく、実機も持っていないので、あくまでもご参考程度に...ということでお願いしたいのですが、ご提示の参考サイトにならって試してみました。

オブジェクトの階層構造は、Unityのバージョンの違いのためサイトとは一部異なっていますが(「Scroll View」と「Content」の間に「Viewport」が挟まっており、これにMaskコンポーネントが付いています)、各種コンポーネントの設定は同様になっています。
インスペクタ
ただし「Scroll View」のScrollRectに関しては、本来のコンポーネントを削除してから、ScrollRectを継承した下記スクリプトをアタッチして、それに元のScrollRectと同じようにインスペクタ上の値を設定しています。
どうもScrollRectのドラッグスクロールが拡縮時の中心合わせ処理と干渉するらしく、そのままではおかしな動きをするので、ドラッグイベントを適宜無効化するようにしたものです。

C#

1using UnityEngine; 2using UnityEngine.UI; 3using UnityEngine.EventSystems; 4 5[AddComponentMenu("UI/Undraggable Scroll Rect")] 6public class UndraggableScrollRect : ScrollRect { 7 private bool isDraggable = true; 8 private GameObject draggingTarget; 9 10 // ドラッグによるスクロールが可能かを取得・設定する 11 public bool IsDraggable 12 { 13 get 14 { 15 return this.isDraggable; 16 } 17 18 set 19 { 20 if (this.isDraggable != value) 21 { 22 this.isDraggable = value; 23 if (this.draggingTarget != null) 24 { 25 if (value) 26 { 27 // draggingTargetが存在する状態でisDraggableがfalseからtrueになった→ドラッグ再開の必要ありと見なし、ニセのドラッグ開始イベントを発行する 28 var eventData = new PointerEventData(EventSystem.current); 29 eventData.pointerDrag = this.draggingTarget; 30 eventData.position = Input.mousePosition; 31 ExecuteEvents.Execute<IBeginDragHandler>(this.draggingTarget, eventData, ExecuteEvents.beginDragHandler); 32 } 33 else 34 { 35 // draggingTargetが存在する状態でisDraggableがtrueからfalseになった→ドラッグが中断されたと見なし、ニセのドラッグ終了イベントを発行する 36 ExecuteEvents.Execute<IEndDragHandler>(this.draggingTarget, new PointerEventData(EventSystem.current), ExecuteEvents.endDragHandler); 37 } 38 } 39 } 40 } 41 } 42 43 public override void OnBeginDrag(PointerEventData eventData) 44 { 45 if (isDraggable) 46 { 47 this.draggingTarget = eventData.pointerDrag; 48 base.OnBeginDrag(eventData); 49 } 50 } 51 52 public override void OnDrag(PointerEventData eventData) 53 { 54 if (isDraggable) 55 { 56 base.OnDrag(eventData); 57 } 58 } 59 60 public override void OnEndDrag(PointerEventData eventData) 61 { 62 if (eventData.dragging) 63 { 64 // IsDraggable切り替え時に発行されたニセイベントはdraggingがfalseになっているので区別できる 65 // 本物のドラッグ終了イベントの場合のみdraggingTargetをnullに戻す 66 this.draggingTarget = null; 67 } 68 base.OnEndDrag(eventData); 69 } 70}

PinchScalingManagerはほとんどサイトのものと同じで、変更箇所としてはUpdateScalingでの拡縮中心合わせ方法の変更と、先ほど申し上げたドラッグスクロールを拡縮開始でオフ、終了でオンに切り替えるようにした点ぐらいです。

C#

1using UnityEngine; 2using UnityEngine.UI; 3using System.Collections; 4 5public class PinchScalingManager : MonoBehaviour 6{ 7 [SerializeField] private GridLayoutGroup content; // 拡大縮小するコンテンツ 8 [SerializeField] private RectTransform wrapper; // コンテンツのラッパー // 変更...TransformをRectTransformに 9 10 // コンテンツのRectTransformの参照 11 private RectTransform contentRect; 12 13 [SerializeField] private float scale; // 現在の拡大率 14 15 [System.Serializable] 16 struct RangeClass 17 { 18 public float min, max; 19 } 20 21 [SerializeField] private RangeClass RangeScale; // 拡大縮小の範囲 22 [SerializeField] private RangeClass RangeLimitedScale; // 収束する範囲 23 24 [SerializeField] private float TweenSecond; // 収束するまでにかかる時間 25 26 private bool isPinch = false; // ピンチ中であればtrue 27 // private Vector3 center; // 現在の中心座標 // 削除 28 private Vector2 scalingCenter; // 追加...拡大縮小の中心となるスクリーン座標 29 private Vector2 defaultCellSize; // 拡大率が1の時のコンテンツの大きさ 30 private Vector2 marginTopLeft; // 追加...画像の左上余白 31 private UndraggableScrollRect scrollView; // 追加...スクロールビュー 32 33 #if UNITY_IOS || UNITY_ANDROID 34 private float max_distance = 0; // ピンチ開始時の指間の距離 35 #endif 36 37 void Start() 38 { 39 contentRect = content.GetComponent<RectTransform>(); // 参照を設定 40 scrollView = contentRect.GetComponentInParent<UndraggableScrollRect>(); // 参照を設定 41 42 defaultCellSize = content.cellSize; 43 // center = contentRect.localPosition / scale; // 削除 44 45 // 状態の初期化 46 Canvas.ForceUpdateCanvases(); // 追加...レイアウトを強制更新 47 UpdateScaling(ClampScale(scale)); // 変更...新形式に書き換え 48 49 // 表示されている画面の中心を拡大率に合わせて調整する 50 contentRect.anchoredPosition *= scale; 51 52 // 追加...余白の大きさを取得しておく 53 var padding = content.padding; 54 marginTopLeft = new Vector2(padding.left, -padding.top); 55 } 56 57 void Update() 58 { 59 #if UNITY_EDITOR 60 EditorControl(); 61 #endif 62 63 #if !UNITY_EDITOR 64 MobileControl(); 65 #endif 66 } 67 68 #if UNITY_EDITOR 69 private void EditorControl() 70 { 71 // タッチ中の処理 72 if (isPinch) 73 { 74 // タッチ終了を感知し、終了処理をする 75 if (Input.GetAxisRaw("Vertical") == 0) 76 { 77 isPinch = false; 78 scrollView.IsDraggable = true; // 追加...スクロールビューのドラッグを有効にする 79 StartTweenCoroutine(); 80 return; 81 } 82 UpdateScaling(ClampScale(scale + Input.GetAxisRaw("Vertical") * 1f * Time.deltaTime)); // 変更...新形式に書き換え 83 return; 84 } 85 // タッチ開始時を感知し、初期化処理をする 86 if (Input.GetAxisRaw("Vertical") != 0) 87 { 88 scalingCenter = (Vector2)Input.mousePosition; // 追加...中心をマウス位置に設定する 89 // center = contentRect.localPosition / scale; // 削除 90 scrollView.IsDraggable = false; // 追加...スクロールビューのドラッグを無効にする 91 isPinch = true; 92 } 93 } 94 #endif 95 96 #if UNITY_IOS || UNITY_ANDROID 97 private void MobileControl() 98 { 99 // タッチ中の処理 100 if (isPinch) 101 { 102 // タッチ終了を感知し、終了処理をする 103 if (Input.touchCount < 2) 104 { 105 isPinch = false; 106 scrollView.IsDraggable = true; 107 StartTweenCoroutine(); 108 return; 109 } 110 float distance = Vector2.Distance(Input.touches[0].position, Input.touches[1].position); 111 UpdateScaling(ClampScale(distance / max_distance)); // 変更...新形式に書き換え 112 return; 113 } 114 // タッチ開始時を感知し、初期化処理をする 115 if (Input.touchCount == 2) 116 { 117 // center = contentRect.localPosition / scale; // 削除 118 scalingCenter = Input.mousePosition; // 追加...中心をピンチ中心に設定する 119 scrollView.IsDraggable = false; 120 isPinch = true; 121 float distance = Vector2.Distance(Input.touches[0].position, Input.touches[1].position); 122 max_distance = distance / scale; 123 } 124 } 125 #endif 126 127 // 変更...新しいスケールをセットするメソッドの代わりに、拡大率を範囲内に収めて返すメソッドを作る 128 /* 129 /// <summary> 130 /// 新しい拡大率のバリデートと更新をする 131 /// </summary> 132 private void SetNewScale(float new_scale) 133 { 134 135 // min < 新しい拡大率 < max に設定する 136 new_scale = Mathf.Min(new_scale, RangeScale.max); 137 new_scale = Mathf.Max(new_scale, RangeScale.min); 138 139 scale = new_scale; 140 141 } 142 */ 143 /// <summary> 144 /// 拡大率を範囲内に収める 145 /// </summary> 146 /// <returns>クランプされた拡大率。</returns> 147 /// <param name="unclampedScale">未クランプの拡大率。</param> 148 private float ClampScale(float unclampedScale) 149 { 150 return Mathf.Clamp(unclampedScale, RangeScale.min, RangeScale.max); 151 } 152 153 /// <summary> 154 /// 収束させる拡大率を求め、コルーチンを開始する 155 /// </summary> 156 private void StartTweenCoroutine() 157 { 158 // min < 収束させる拡大率 < max に設定する 159 float limited_scale = scale; 160 limited_scale = Mathf.Min(limited_scale, RangeLimitedScale.max); 161 limited_scale = Mathf.Max(limited_scale, RangeLimitedScale.min); 162 163 StartCoroutine(TweenLimitedScale(limited_scale)); 164 } 165 166 /// <summary> 167 /// 拡大率を設定された値に収束させる 168 /// </summary> 169 IEnumerator TweenLimitedScale(float limited_scale) 170 { 171 if (scale == limited_scale) 172 yield break; 173 174 float timer = 0; 175 float def_scale = scale - limited_scale; 176 177 // scaleをTweenSecond秒以内にlimited_rateにする 178 while (timer < TweenSecond) 179 { 180 timer += Time.deltaTime; 181 UpdateScaling(ClampScale(scale - def_scale * Time.deltaTime * (1f / TweenSecond))); // 変更...新形式に書き換え 182 yield return 0; 183 } 184 } 185 186 // 変更...「scaleに新しい拡大率をセットしてUpdateScalingを実行」から「新しい拡大率を引数にしてUpdateScalingを実行」に動作を変え、中心調整の方法も変更する 187 /// <summary> 188 /// 新しい拡大率に基づいてオブジェクトの大きさを更新する 189 /// </summary> 190 /// <param name="newScale">新しい拡大率。</param> 191 private void UpdateScaling(float newScale) 192 { 193 // 拡縮後の拡縮中心のズレを調べ、スクロール量に換算する 194 var centerOnContent = (Vector2)contentRect.InverseTransformPoint(scalingCenter); 195 var nextScaledCenterOnContent = (centerOnContent - marginTopLeft) * (newScale / scale) + marginTopLeft; 196 var nextScaledCenterOnScreen = (Vector2)contentRect.TransformPoint(nextScaledCenterOnContent); 197 var delta = nextScaledCenterOnScreen - scalingCenter; 198 199 content.cellSize = defaultCellSize * newScale; // 想定するコンテンツの大きさを更新する 200 wrapper.localScale = new Vector3(newScale, newScale, 1); // 全体を拡大縮小する 201 contentRect.anchoredPosition -= delta; // コンテントをずらして位置を合わせる 202 203 scale = newScale; 204 } 205}

iOSシミュレーターで動かしてみたところ一応それらしく見えたものの、やはり実機を使わないと動作確認にはいまいちですね...
結果

投稿2018/02/04 19:55

Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sakakura

2018/02/05 05:20

細かく分かりやすいご回答ありがとう御座います。 教えていただいたように修正したところ 実機でも期待していた動作となりました。 ありがとう御座いました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問