質問するログイン新規登録

回答編集履歴

1

コードを旧バージョン向けに変更

2020/01/05 00:58

投稿

Bongo
Bongo

スコア10816

answer CHANGED
@@ -12,239 +12,246 @@
12
12
  using UnityEngine.UI;
13
13
 
14
14
  /// <summary>
15
- /// お絵描き
15
+ /// お絵描き
16
16
  /// </summary>
17
17
  [RequireComponent(typeof(RectTransform), typeof(Image))]
18
18
  public class Painter : MonoBehaviour
19
19
  {
20
- // ペンの半径...0で1ピクセルの線になる
20
+ // ペンの半径...0で1ピクセルの線になる
21
- [Range(0, 5)] public int penRadius;
21
+ [Range(0, 5)] public int penRadius;
22
22
 
23
- // 前景色
23
+ // 前景色
24
- public Color foregroundColor = Color.red;
24
+ public Color foregroundColor = Color.red;
25
25
 
26
- // 背景色
26
+ // 背景色
27
- [SerializeField] private Color backgroundColor = Color.white;
27
+ [SerializeField] private Color backgroundColor = Color.white;
28
28
 
29
- private RectTransform rectTransform;
29
+ private RectTransform rectTransform;
30
- private Image image;
30
+ private Image image;
31
- private Texture2D texture;
31
+ private Texture2D texture;
32
- private Vector2Int textureSize;
32
+ private Vector2Int textureSize;
33
- private Vector2Int previousPixelPosition;
33
+ private Vector2Int previousPixelPosition;
34
- private Vector2Int cachedPixelPosition;
34
+ private Vector2Int cachedPixelPosition;
35
35
 
36
- // Undo、Redo用のテクスチャ格納庫
36
+ // Undo、Redo用のテクスチャ格納庫
37
- private readonly Stack<Texture2D> undoStack = new Stack<Texture2D>();
37
+ private readonly Stack<Texture2D> undoStack = new Stack<Texture2D>();
38
- private readonly Stack<Texture2D> redoStack = new Stack<Texture2D>();
38
+ private readonly Stack<Texture2D> redoStack = new Stack<Texture2D>();
39
39
 
40
- // Undo、Redo可能かどうかを外部スクリプトから調べたい場合、これらプロパティを参照する
40
+ // Undo、Redo可能かどうかを外部スクリプトから調べたい場合、これらプロパティを参照する
41
+ public bool CanUndo
42
+ {
41
- public bool CanUndo => this.undoStack.Count > 0;
43
+ get { return this.undoStack.Count > 0; }
42
- public bool CanRedo => this.redoStack.Count > 0;
44
+ }
43
45
 
44
- // Undo時にはundoStackからテクスチャを1つ取り出して現在のテクスチャとし、
45
- // 古いテクスチャはredoStackに積んでおく
46
- public void Undo()
46
+ public bool CanRedo
47
- {
47
+ {
48
- if (!this.CanUndo)
48
+ get { return this.redoStack.Count > 0; }
49
- {
50
- return;
51
- }
49
+ }
52
50
 
53
- var previousTexture = this.texture;
51
+ // Undo時にはundoStackからテクスチャを1つ取り出して現在のテクスチャとし、
54
- var poppedTexture = this.undoStack.Pop();
52
+ // 古いテクスチャはredoStackに積んでおく
55
- this.texture = poppedTexture;
56
- this.redoStack.Push(previousTexture);
57
- this.UpdateSprite();
53
+ public void Undo()
54
+ {
58
- Debug.Log($"Undo! UndoStack : {this.undoStack.Count} RedoStack : {this.redoStack.Count}");
55
+ if (!this.CanUndo)
56
+ {
57
+ return;
59
- }
58
+ }
60
59
 
61
- // Redo時にはredoStackからテクスチャを1つ取り出して現在のテクスチャとし、
60
+ var previousTexture = this.texture;
62
- // 古いテクスチャはundoStackに積んでおく
61
+ var poppedTexture = this.undoStack.Pop();
62
+ this.texture = poppedTexture;
63
+ this.redoStack.Push(previousTexture);
63
- public void Redo()
64
+ this.UpdateSprite();
64
- {
65
- if (!this.CanRedo)
65
+ Debug.LogFormat("Undo! UndoStack : {0} RedoStack : {1}", this.undoStack.Count, this.redoStack.Count);
66
- {
67
- return;
68
- }
66
+ }
69
67
 
70
- var previousTexture = this.texture;
68
+ // Redo時にはredoStackからテクスチャを1つ取り出して現在のテクスチャとし、
71
- var poppedTexture = this.redoStack.Pop();
69
+ // 古いテクスチャはundoStackに積んでおく
72
- this.texture = poppedTexture;
73
- this.undoStack.Push(previousTexture);
74
- this.UpdateSprite();
70
+ public void Redo()
71
+ {
75
- Debug.Log($"Redo! UndoStack : {this.undoStack.Count} RedoStack : {this.redoStack.Count}");
72
+ if (!this.CanRedo)
73
+ {
74
+ return;
76
- }
75
+ }
77
76
 
78
- // テクスチャに何かしらの操作(線を引くなど)を行う前にはRecordを実行することにする
79
- // これによって変更前のテクスチャが複製されundoStackに積まれる
77
+ var previousTexture = this.texture;
80
- // また、このタイミングでredoStackは空にする
78
+ var poppedTexture = this.redoStack.Pop();
81
- private void Record()
79
+ this.texture = poppedTexture;
82
- {
83
- this.undoStack.Push(Instantiate(this.texture));
80
+ this.undoStack.Push(previousTexture);
84
- foreach (var textureInRedoStack in this.redoStack)
85
- {
86
- Destroy(textureInRedoStack);
81
+ this.UpdateSprite();
82
+ Debug.LogFormat("Redo! UndoStack : {0} RedoStack : {1}", this.undoStack.Count, this.redoStack.Count);
87
- }
83
+ }
88
84
 
85
+ // テクスチャに何かしらの操作(線を引くなど)を行う前にはRecordを実行することにする
86
+ // これによって変更前のテクスチャが複製されundoStackに積まれる
87
+ // また、このタイミングでredoStackは空にする
88
+ private void Record()
89
+ {
89
- this.redoStack.Clear();
90
+ this.undoStack.Push(Instantiate(this.texture));
90
- Debug.Log($"Record! UndoStack : {this.undoStack.Count} RedoStack : {this.redoStack.Count}");
91
+ foreach (var textureInRedoStack in this.redoStack)
92
+ {
93
+ Destroy(textureInRedoStack);
91
- }
94
+ }
92
95
 
93
- private void UpdateSprite()
94
- {
95
- var previousSprite = this.image.sprite;
96
- this.image.sprite = Sprite.Create(
96
+ this.redoStack.Clear();
97
- this.texture,
98
- new Rect(0, 0, this.texture.width, this.texture.height),
97
+ Debug.LogFormat("Record! UndoStack : {0} RedoStack : {1}", this.undoStack.Count, this.redoStack.Count);
99
- Vector2.zero);
100
- Destroy(previousSprite);
101
- }
98
+ }
102
99
 
103
- private Vector2Int GetPixelPosition()
100
+ private void UpdateSprite()
104
- {
101
+ {
105
- if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(
102
+ var previousSprite = this.image.sprite;
103
+ this.image.sprite = Sprite.Create(
106
- this.rectTransform,
104
+ this.texture,
105
+ new Rect(0, 0, this.texture.width, this.texture.height),
107
- Input.mousePosition,
106
+ Vector2.zero);
108
- null,
109
- out var pixelPositionFloat))
110
- {
111
- return this.cachedPixelPosition;
107
+ Destroy(previousSprite);
112
- }
108
+ }
113
109
 
114
- var sizeDelta = this.rectTransform.sizeDelta;
115
- pixelPositionFloat += sizeDelta * this.rectTransform.pivot;
116
- var pixelPosition = new Vector2Int(
117
- Mathf.Clamp((int)pixelPositionFloat.x, 0, this.textureSize.x - 1),
118
- Mathf.Clamp((int)pixelPositionFloat.y, 0, this.textureSize.y - 1));
119
- Debug.Log($"Pixel Position: {pixelPosition}");
120
- this.cachedPixelPosition = pixelPosition;
110
+ private Vector2Int GetPixelPosition()
111
+ {
112
+ if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(
113
+ this.rectTransform,
114
+ Input.mousePosition,
115
+ null,
116
+ out var pixelPositionFloat))
117
+ {
121
- return this.cachedPixelPosition;
118
+ return this.cachedPixelPosition;
122
- }
119
+ }
123
120
 
124
- // 入力座標がテクスチャ範囲内ならtrue、さもなければfalse
121
+ var sizeDelta = this.rectTransform.sizeDelta;
122
+ pixelPositionFloat += sizeDelta * this.rectTransform.pivot;
125
- private bool PositionIsWithinTexture(Vector2Int position)
123
+ var pixelPosition = new Vector2Int(
126
- {
127
- return (position.x >= 0) && (position.y >= 0) &&
124
+ Mathf.Clamp((int)pixelPositionFloat.x, 0, this.textureSize.x - 1),
128
- (position.x < this.textureSize.x) && (position.y < this.textureSize.y);
125
+ Mathf.Clamp((int)pixelPositionFloat.y, 0, this.textureSize.y - 1));
126
+ Debug.LogFormat("Pixel Position: {0}", pixelPosition);
127
+ this.cachedPixelPosition = pixelPosition;
128
+ return this.cachedPixelPosition;
129
- }
129
+ }
130
130
 
131
- // 入力座標に円を描く
131
+ // 入力座標がテクスチャ範囲内ならtrue、さもなければfalse
132
- private void PaintAt(Vector2Int position, Color32 color, int radius)
132
+ private bool PositionIsWithinTexture(Vector2Int position)
133
- {
133
+ {
134
- var sqrRadius = radius * radius;
135
- for (var i = -radius; i <= radius; i++)
136
- {
137
- for (var j = -radius; j <= radius; j++)
138
- {
139
- var p = new Vector2Int(position.x + i, position.y + j);
134
+ return (position.x >= 0) && (position.y >= 0) &&
140
- var dot = (i * i) + (j * j);
141
- if ((dot <= sqrRadius) && this.PositionIsWithinTexture(p))
135
+ (position.x < this.textureSize.x) && (position.y < this.textureSize.y);
142
- {
143
- this.texture.SetPixel(p.x, p.y, color);
144
- }
136
+ }
145
- }
146
- }
147
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
+ {
148
- this.texture.Apply();
150
+ this.texture.SetPixel(p.x, p.y, color);
149
- }
151
+ }
152
+ }
153
+ }
150
154
 
151
- private void LineTo(Vector2Int from, Vector2Int to, Color32 color, int radius)
152
- {
153
- var penPosition = from;
154
- var x = (float)penPosition.x;
155
- var y = (float)penPosition.y;
156
- var fromTo = to - from;
157
- var fromToSign = new Vector2Int((int)Mathf.Sign(fromTo.x), (int)Mathf.Sign(fromTo.y));
158
- var fromToXIsZero = fromToSign.x == 0;
159
- var fromToYIsZero = fromToSign.y == 0;
160
- fromToSign.x = fromToXIsZero ? 1 : fromToSign.x;
161
- fromToSign.y = fromToYIsZero ? 1 : fromToSign.y;
162
- var absFromTo = fromToSign * fromTo;
163
- var dominantDirection = 0;
164
- var delta = Vector2.zero;
165
- if (absFromTo.x >= absFromTo.y)
166
- {
167
- var tangent = fromToXIsZero ? 0 : (float)fromTo.y / fromTo.x;
168
- delta.x = fromToSign.x;
155
+ this.texture.Apply();
169
- delta.y = tangent * delta.x;
170
- }
156
+ }
171
- else
172
- {
173
- var tangent = fromToYIsZero ? 0 : (float)fromTo.x / fromTo.y;
174
- delta.y = fromToSign.y;
175
- delta.x = tangent * delta.y;
176
- dominantDirection = 1;
177
- }
178
157
 
179
- while (this.PositionIsWithinTexture(penPosition))
158
+ private void LineTo(Vector2Int from, Vector2Int to, Color32 color, int radius)
180
- {
159
+ {
181
- try
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)
182
- {
173
+ {
183
- this.PaintAt(penPosition, color, radius);
174
+ var tangent = fromToXIsZero ? 0 : (float)fromTo.y / fromTo.x;
184
- x += delta.x;
175
+ delta.x = fromToSign.x;
185
- y += delta.y;
186
- penPosition.x = (int)x;
176
+ delta.y = tangent * delta.x;
177
+ }
187
- penPosition.y = (int)y;
178
+ else
188
- if (fromToSign[dominantDirection] > 0)
189
- {
179
+ {
190
- if (penPosition[dominantDirection] >= to[dominantDirection])
180
+ var tangent = fromToYIsZero ? 0 : (float)fromTo.x / fromTo.y;
191
- {
181
+ delta.y = fromToSign.y;
182
+ delta.x = tangent * delta.y;
192
- break;
183
+ dominantDirection = 1;
193
- }
184
+ }
194
- }
195
- else
196
- {
197
- if (penPosition[dominantDirection] <= to[dominantDirection])
198
- {
199
- break;
200
- }
201
- }
202
- }
203
- catch (Exception e)
204
- {
205
- Debug.LogException(e);
206
- break;
207
- }
208
- }
209
- }
210
185
 
211
- private void Start()
186
+ while (this.PositionIsWithinTexture(penPosition))
212
- {
187
+ {
213
- this.rectTransform = this.transform as RectTransform;
188
+ try
189
+ {
214
- this.image = this.GetComponent<Image>();
190
+ this.PaintAt(penPosition, color, radius);
215
- var sizeDelta = this.rectTransform.sizeDelta;
191
+ x += delta.x;
192
+ y += delta.y;
216
- var width = (int)sizeDelta.x;
193
+ penPosition.x = (int)x;
217
- var height = (int)sizeDelta.y;
194
+ penPosition.y = (int)y;
218
- this.texture = new Texture2D(width, height, TextureFormat.ARGB32, false) {filterMode = FilterMode.Bilinear};
219
- this.texture.SetPixels32(Enumerable.Repeat<Color32>(this.backgroundColor, width * height).ToArray());
220
- this.texture.Apply();
221
- this.textureSize = new Vector2Int(width, height);
195
+ if (fromToSign[dominantDirection] > 0)
196
+ {
197
+ if (penPosition[dominantDirection] >= to[dominantDirection])
198
+ {
222
- this.UpdateSprite();
199
+ break;
223
- }
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
+ }
224
217
 
225
- private void Update()
218
+ private void Start()
226
- {
219
+ {
220
+ this.rectTransform = this.transform as RectTransform;
227
- if (Input.GetKeyDown(KeyCode.U))
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
+ this.texture = new Texture2D(width, height, TextureFormat.ARGB32, false) {filterMode = FilterMode.Bilinear};
226
+ this.texture.SetPixels32(Enumerable.Repeat<Color32>(this.backgroundColor, width * height).ToArray());
228
- {
227
+ this.texture.Apply();
228
+ this.textureSize = new Vector2Int(width, height);
229
- this.Undo();
229
+ this.UpdateSprite();
230
- }
230
+ }
231
231
 
232
- if (Input.GetKeyDown(KeyCode.R))
232
+ private void Update()
233
- {
233
+ {
234
+ if (Input.GetKeyDown(KeyCode.U))
235
+ {
234
- this.Redo();
236
+ this.Undo();
235
- }
237
+ }
236
238
 
239
+ if (Input.GetKeyDown(KeyCode.R))
240
+ {
241
+ this.Redo();
242
+ }
243
+
237
- if (Input.GetMouseButtonDown(0))
244
+ if (Input.GetMouseButtonDown(0))
238
- {
245
+ {
239
- this.Record();
246
+ this.Record();
240
- this.previousPixelPosition = this.GetPixelPosition();
247
+ this.previousPixelPosition = this.GetPixelPosition();
241
- }
248
+ }
242
- else if (Input.GetMouseButton(0))
249
+ else if (Input.GetMouseButton(0))
243
- {
250
+ {
244
- var currentPixelPosition = this.GetPixelPosition();
251
+ var currentPixelPosition = this.GetPixelPosition();
245
- this.LineTo(this.previousPixelPosition, currentPixelPosition, this.foregroundColor, this.penRadius);
252
+ this.LineTo(this.previousPixelPosition, currentPixelPosition, this.foregroundColor, this.penRadius);
246
- this.previousPixelPosition = currentPixelPosition;
253
+ this.previousPixelPosition = currentPixelPosition;
247
- }
254
+ }
248
- }
255
+ }
249
256
  }
250
257
  ```