前提・実現したいこと
unity imageに線を引くアプリでCommandButtonを押した時はMainy画面に戻りたいなどの処理をしたいのですが,線は引けたのですが,CommandButtonを追加してMaine画面に戻る処理を追加した場合動きがおかしくなります。
ただ GetkeyDownなどの処理は問題ないので,OnButtonClickではなくCommandButonが押された時にGetkeyDownで判定する方法はないでしょうか?
タッチ処理の場合CommandButtonを使えないような気がするのですが?
if (Input.GetKeyDown("u"))この処理は問題なく動きます。
発生している問題・エラーメッセージ
該当のソースコード
// *** MAINLOOP *** void Update() { if (enableTouch) { TouchPaint(); } else { MousePaint(); } } public void OnButtonClick() { Debug.Log("Click "); } // handle mouse events void MousePaint() { if (Input.GetKeyDown("u")) { DoUndo(); } if (Input.GetMouseButtonDown(0)) { beforeMousePos = GetPosition(); } if (Input.GetMouseButton(0)) { Vector3 v = GetPosition(); LineTo(beforeMousePos, v, lineColor); beforeMousePos = v; UpdateTexture(); textureNeedsUpdate = true; } // left mouse button released if (Input.GetMouseButtonUp(0)) { GrabUndoBufferNow(); } if (Input.GetMouseButton(1)) { DoUndo(); } }
気になる質問をクリップする
クリップした質問は、後からいつでもMYページで確認できます。
またクリップした質問に回答があった際、通知やメールを受け取ることができます。
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/01/15 09:06 編集
回答1件
0
ベストアンサー
一案として、Painter
スクリプトに下記のような修正を加えてみてはどうでしょうか?
Painter
スクリプトにIPointerDownHandler、IPointerUpHandlerインターフェイスを実装する。- OnPointerDownは通常はImage上でマウスボタンを押し下げる、あるいはタッチを開始すると動作するが、Imageよりも前面に配置されたボタンをクリックした時には、ボタンによってイベントが遮断され動作しないので都合がいいと思われる。そこで、このタイミングで線引き中であることを示すフラグを
true
にする。 - 線引きロジックは線引き中フラグが
true
の場合のみ動作させるようにする。OnPointerDown
はUpdate
よりも先行して処理されるので、OnPointerDown
内で線引きフラグを立てておけばUpdate
内やMousePaint
内、TouchPaint
内でそれに基づいた分岐ができる。 - OnPointerUpのタイミングで線引き中フラグを
false
にする。
C#
1// 省略 2 3// イベント関連の機能群を使用できるように、usingディレクティブを追加する 4using UnityEngine.EventSystems; 5 6// IPointerDownHandler、IPointerUpHandlerを実装することを宣言する 7[RequireComponent(typeof(RectTransform), typeof(Image))] 8public class Painter : MonoBehaviour, IPointerDownHandler, IPointerUpHandler 9{ 10 // 省略 11 12 // お絵かき中であることを示すフィールドを追加 13 bool isPainting; 14 15 // 省略 16 17 // このImage上でタッチ開始、またはマウスボタンを押し下げた時にisPaintingをtrueにし... 18 public void OnPointerDown(PointerEventData eventData) 19 { 20 isPainting = true; 21 } 22 23 // タッチが終了、またはマウスボタンが離されたらisPaintingをfalseにする 24 public void OnPointerUp(PointerEventData eventData) 25 { 26 isPainting = false; 27 } 28 29 // MousePaint内でisPaintingを見て適宜分岐する 30 // TouchPaintについても同様に分岐させる 31 // あるいはメソッドの構成を見直して、MousePaintやTouchPaintには線引き関連の 32 // 機能だけを記述することにし、Update内でisPaintingによる分岐を行うという作りなら 33 // 似たような分岐を2ヶ所に分散して記述する必要がなくなっていいかもしれない 34 // handle mouse events 35 void MousePaint() 36 { 37 if (Input.GetKeyDown("u")) 38 { 39 DoUndo(); 40 } 41 42 // 線引き中かどうかに関係なく動作させたいコードはここよりも上に記述する 43 // たとえばキーボード操作によるUndo、Redoなど 44 if (!isPainting) 45 { 46 // 線引き中に動作されると困るコードがあればこの辺に記述する 47 48 return; 49 } 50 // 線引き中のみ動作させたいコードはここよりも下に記述する 51 52 if (Input.GetMouseButtonDown(0)) 53 { 54 beforeMousePos = GetPosition(); 55 } 56 if (Input.GetMouseButton(0)) 57 { 58 Vector3 v = GetPosition(); 59 LineTo(beforeMousepos, v, lineColor); 60 beforeMousePos = v; 61 UpdateTexture(); 62 textureNeedsUpdate = true; 63 } 64 65 // left mouse button released 66 if (Input.GetMouseButtonUp(0)) 67 { 68 GrabUndoBufferNow(); 69 } 70 71 // 右ボタンクリックによるUndoも、この位置にあるとこのImage上で 72 // クリックした時しか動作しなくなると思われる 73 // もしそれだと困るようなら、適宜分岐経路を検討する 74 if (Input.GetMouseButton(1)) 75 { 76 DoUndo(); 77 } 78 } 79 80 // 省略 81}
すみませんがすぐに試せるモバイル環境を持っていないため、実機上だとどうなるか未確認です。意図と異なる動きをするようでしたら、異常の様子を詳しくコメントいただければ可能であれば直してみようと思います。
追記
「UNITY LineRendererで線を描く事はできるのですが,canvasの下のimageに描く事は出来ないでしょうか?」の時のPainter
と折衷させたバージョン
C#
1using System; 2using System.Collections.Generic; 3using UnityEngine; 4using UnityEngine.EventSystems; 5using UnityEngine.SceneManagement; 6using UnityEngine.UI; 7 8/// <summary> 9/// お絵描き 10/// </summary> 11[RequireComponent(typeof(RectTransform), typeof(Image))] 12public class Painter : MonoBehaviour, IPointerDownHandler, IPointerUpHandler 13{ 14 // ペンの半径...0で1ピクセルの線になる 15 [Range(0, 5)] public int penRadius; 16 17 // 前景色(ペンの色) 18 public Color foregroundColor = Color.red; 19 20 // 背景色 21 // ただし、現状は以前のご質問で製作した「元々セットされているテクスチャを下絵にする」 22 // という方式になっているため、この背景色はスクリプト中で使用されていない 23 [SerializeField] private Color backgroundColor = Color.white; 24 25 private RectTransform rectTransform; 26 private Image image; 27 private Texture2D texture; 28 private Vector2Int textureSize; 29 private Vector2Int previousPixelPosition; 30 private Vector2Int cachedPixelPosition; 31 32 // 線引き中であることを示すフラグ 33 private bool isPainting; 34 35 private readonly Stack<Texture2D> undoStack = new Stack<Texture2D>(); 36 private readonly Stack<Texture2D> redoStack = new Stack<Texture2D>(); 37 38 public bool CanUndo => this.undoStack.Count > 0; 39 public bool CanRedo => this.redoStack.Count > 0; 40 41 // タイトルシーンに移動するメソッド 42 // ボタンのインスペクターの「On Click ()」でこのメソッドを実行するよう設定しておく 43 // 個人的な好みでは、「タイトルシーンに移動する」という機能は「Image上にお絵かきする」という機能と 44 // 直接的な関係があるようには感じられないので、別のスクリプトに役割分担させた方がいい気もしますが... 45 public void OnButtonClick() 46 { 47 SceneManager.LoadScene("Title"); 48 } 49 50 public void OnPointerDown(PointerEventData eventData) 51 { 52 this.isPainting = true; 53 } 54 55 public void OnPointerUp(PointerEventData eventData) 56 { 57 this.isPainting = false; 58 } 59 60 public void Undo() 61 { 62 if (!this.CanUndo) 63 { 64 return; 65 } 66 67 var previousTexture = this.texture; 68 var poppedTexture = this.undoStack.Pop(); 69 this.texture = poppedTexture; 70 this.redoStack.Push(previousTexture); 71 this.UpdateSprite(); 72 Debug.Log($"Undo! UndoStack : {this.undoStack.Count} RedoStack : {this.redoStack.Count}"); 73 } 74 75 public void Redo() 76 { 77 if (!this.CanRedo) 78 { 79 return; 80 } 81 82 var previousTexture = this.texture; 83 var poppedTexture = this.redoStack.Pop(); 84 this.texture = poppedTexture; 85 this.undoStack.Push(previousTexture); 86 this.UpdateSprite(); 87 Debug.Log($"Redo! UndoStack : {this.undoStack.Count} RedoStack : {this.redoStack.Count}"); 88 } 89 90 private void Record() 91 { 92 this.undoStack.Push(Instantiate(this.texture)); 93 foreach (var textureInRedoStack in this.redoStack) 94 { 95 Destroy(textureInRedoStack); 96 } 97 98 this.redoStack.Clear(); 99 Debug.Log($"Record! UndoStack : {this.undoStack.Count} RedoStack : {this.redoStack.Count}"); 100 } 101 102 private void UpdateSprite() 103 { 104 var previousSprite = this.image.sprite; 105 this.image.sprite = Sprite.Create( 106 this.texture, 107 new Rect(0, 0, this.texture.width, this.texture.height), 108 Vector2.zero); 109 Destroy(previousSprite); 110 } 111 112 private Vector2Int GetPixelPosition() 113 { 114 if (!RectTransformUtility.ScreenPointToLocalPointInRectangle( 115 this.rectTransform, 116 Input.mousePosition, 117 null, 118 out var pixelPositionFloat)) 119 { 120 return this.cachedPixelPosition; 121 } 122 123 var sizeDelta = this.rectTransform.sizeDelta; 124 pixelPositionFloat += sizeDelta * this.rectTransform.pivot; 125 var pixelPosition = new Vector2Int( 126 Mathf.Clamp((int)pixelPositionFloat.x, 0, this.textureSize.x - 1), 127 Mathf.Clamp((int)pixelPositionFloat.y, 0, this.textureSize.y - 1)); 128 Debug.Log($"Pixel Position: {pixelPosition}"); 129 this.cachedPixelPosition = pixelPosition; 130 return this.cachedPixelPosition; 131 } 132 133 private bool PositionIsWithinTexture(Vector2Int position) 134 { 135 return (position.x >= 0) && (position.y >= 0) && 136 (position.x < this.textureSize.x) && (position.y < this.textureSize.y); 137 } 138 139 private void PaintAt(Vector2Int position, Color32 color, int radius) 140 { 141 var sqrRadius = radius * radius; 142 for (var i = -radius; i <= radius; i++) 143 { 144 for (var j = -radius; j <= radius; j++) 145 { 146 var p = new Vector2Int(position.x + i, position.y + j); 147 var dot = (i * i) + (j * j); 148 if ((dot <= sqrRadius) && this.PositionIsWithinTexture(p)) 149 { 150 this.texture.SetPixel(p.x, p.y, color); 151 } 152 } 153 } 154 155 this.texture.Apply(); 156 } 157 158 private void LineTo(Vector2Int from, Vector2Int to, Color32 color, int radius) 159 { 160 var penPosition = from; 161 var x = (float)penPosition.x; 162 var y = (float)penPosition.y; 163 var fromTo = to - from; 164 var fromToSign = new Vector2Int((int)Mathf.Sign(fromTo.x), (int)Mathf.Sign(fromTo.y)); 165 var fromToXIsZero = fromToSign.x == 0; 166 var fromToYIsZero = fromToSign.y == 0; 167 fromToSign.x = fromToXIsZero ? 1 : fromToSign.x; 168 fromToSign.y = fromToYIsZero ? 1 : fromToSign.y; 169 var absFromTo = fromToSign * fromTo; 170 var dominantDirection = 0; 171 var delta = Vector2.zero; 172 if (absFromTo.x >= absFromTo.y) 173 { 174 var tangent = fromToXIsZero ? 0 : (float)fromTo.y / fromTo.x; 175 delta.x = fromToSign.x; 176 delta.y = tangent * delta.x; 177 } 178 else 179 { 180 var tangent = fromToYIsZero ? 0 : (float)fromTo.x / fromTo.y; 181 delta.y = fromToSign.y; 182 delta.x = tangent * delta.y; 183 dominantDirection = 1; 184 } 185 186 while (this.PositionIsWithinTexture(penPosition)) 187 { 188 try 189 { 190 this.PaintAt(penPosition, color, radius); 191 x += delta.x; 192 y += delta.y; 193 penPosition.x = (int)x; 194 penPosition.y = (int)y; 195 if (fromToSign[dominantDirection] > 0) 196 { 197 if (penPosition[dominantDirection] >= to[dominantDirection]) 198 { 199 break; 200 } 201 } 202 else 203 { 204 if (penPosition[dominantDirection] <= to[dominantDirection]) 205 { 206 break; 207 } 208 } 209 } 210 catch (Exception e) 211 { 212 Debug.LogException(e); 213 break; 214 } 215 } 216 } 217 218 private void Start() 219 { 220 this.rectTransform = this.transform as RectTransform; 221 this.image = this.GetComponent<Image>(); 222 var sizeDelta = this.rectTransform.sizeDelta; 223 var width = (int)sizeDelta.x; 224 var height = (int)sizeDelta.y; 225 var backgroundPixels = (this.image.mainTexture as Texture2D).GetPixels32(); 226 this.image.sprite = null; 227 this.texture = new Texture2D(width, height, TextureFormat.ARGB32, false) {filterMode = FilterMode.Bilinear}; 228 this.texture.SetPixels32(backgroundPixels); 229 this.texture.Apply(); 230 this.textureSize = new Vector2Int(width, height); 231 this.UpdateSprite(); 232 } 233 234 private void Update() 235 { 236 if (Input.GetKeyDown(KeyCode.U)) 237 { 238 this.Undo(); 239 } 240 241 if (Input.GetKeyDown(KeyCode.R)) 242 { 243 this.Redo(); 244 } 245 246 // 線引き中かどうかに関係なく動作させたいコードはここよりも上に記述する 247 if (!this.isPainting) 248 { 249 // 線引き中に動作されると困るコードがあればこの辺に記述する 250 return; 251 } 252 // 線引き中のみ動作させたいコードはここよりも下に記述する 253 254 if (Input.GetMouseButtonDown(0)) 255 { 256 this.Record(); 257 this.previousPixelPosition = this.GetPixelPosition(); 258 } 259 else if (Input.GetMouseButton(0)) 260 { 261 var currentPixelPosition = this.GetPixelPosition(); 262 this.LineTo(this.previousPixelPosition, currentPixelPosition, this.foregroundColor, this.penRadius); 263 this.previousPixelPosition = currentPixelPosition; 264 } 265 266 // 右クリックによるUndo 267 if (Input.GetMouseButtonDown(1)) 268 { 269 this.Undo(); 270 } 271 } 272}
投稿2020/01/15 09:51
編集2020/01/15 17:05総合スコア10807
バッドをするには、ログインかつ
こちらの条件を満たす必要があります。
2020/01/15 10:50 編集
2020/01/15 10:55
2020/01/15 11:31 編集
2020/01/15 17:06
2020/01/26 01:15 編集
2020/01/26 07:27
あなたの回答
tips
太字
斜体
打ち消し線
見出し
引用テキストの挿入
コードの挿入
リンクの挿入
リストの挿入
番号リストの挿入
表の挿入
水平線の挿入
プレビュー
質問の解決につながる回答をしましょう。 サンプルコードなど、より具体的な説明があると質問者の理解の助けになります。 また、読む側のことを考えた、分かりやすい文章を心がけましょう。