回答編集履歴

1

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

2020/01/05 00:58

投稿

Bongo
Bongo

スコア10811

test CHANGED
@@ -26,7 +26,7 @@
26
26
 
27
27
  /// <summary>
28
28
 
29
- /// お絵描き
29
+ /// お絵描き
30
30
 
31
31
  /// </summary>
32
32
 
@@ -36,463 +36,477 @@
36
36
 
37
37
  {
38
38
 
39
- // ペンの半径...0で1ピクセルの線になる
40
-
41
- [Range(0, 5)] public int penRadius;
42
-
43
-
44
-
45
- // 前景色
46
-
47
- public Color foregroundColor = Color.red;
48
-
49
-
50
-
51
- // 背景色
52
-
53
- [SerializeField] private Color backgroundColor = Color.white;
54
-
55
-
56
-
57
- private RectTransform rectTransform;
58
-
59
- private Image image;
60
-
61
- private Texture2D texture;
62
-
63
- private Vector2Int textureSize;
64
-
65
- private Vector2Int previousPixelPosition;
66
-
67
- private Vector2Int cachedPixelPosition;
68
-
69
-
70
-
71
- // Undo、Redo用のテクスチャ格納庫
72
-
73
- private readonly Stack<Texture2D> undoStack = new Stack<Texture2D>();
74
-
75
- private readonly Stack<Texture2D> redoStack = new Stack<Texture2D>();
76
-
77
-
78
-
79
- // Undo、Redo可能かどうかを外部スクリプトから調べたい場合、これらプロパティを参照する
80
-
81
- public bool CanUndo => this.undoStack.Count > 0;
82
-
83
- public bool CanRedo => this.redoStack.Count > 0;
84
-
85
-
86
-
87
- // Undo時にはundoStackからテクスチャを1つ取り出して現在のテクスチャとし、
88
-
89
- // 古いテクスチャはredoStackに積んでおく
90
-
91
- public void Undo()
92
-
93
- {
94
-
95
- if (!this.CanUndo)
96
-
97
- {
98
-
99
- return;
100
-
101
- }
102
-
103
-
104
-
105
- var previousTexture = this.texture;
106
-
107
- var poppedTexture = this.undoStack.Pop();
108
-
109
- this.texture = poppedTexture;
110
-
111
- this.redoStack.Push(previousTexture);
112
-
113
- this.UpdateSprite();
114
-
115
- Debug.Log($"Undo! UndoStack : {this.undoStack.Count} RedoStack : {this.redoStack.Count}");
116
-
117
- }
118
-
119
-
120
-
121
- // Redo時にはredoStackからテクスチャを1つ取り出して現在のテクスチャとし、
122
-
123
- // 古いテクスチャはundoStackに積んでおく
124
-
125
- public void Redo()
126
-
127
- {
128
-
129
- if (!this.CanRedo)
130
-
131
- {
132
-
133
- return;
134
-
135
- }
136
-
137
-
138
-
139
- var previousTexture = this.texture;
140
-
141
- var poppedTexture = this.redoStack.Pop();
142
-
143
- this.texture = poppedTexture;
144
-
145
- this.undoStack.Push(previousTexture);
146
-
147
- this.UpdateSprite();
148
-
149
- Debug.Log($"Redo! UndoStack : {this.undoStack.Count} RedoStack : {this.redoStack.Count}");
150
-
151
- }
152
-
153
-
154
-
155
- // テクスチャに何かしらの操作(線を引くなど)を行う前にはRecordを実行することにする
156
-
157
- // これによって変更前のテクスチャが複製されundoStackに積まれる
158
-
159
- // また、このタイミングでredoStackは空にする
160
-
161
- private void Record()
162
-
163
- {
164
-
165
- this.undoStack.Push(Instantiate(this.texture));
166
-
167
- foreach (var textureInRedoStack in this.redoStack)
168
-
169
- {
170
-
171
- Destroy(textureInRedoStack);
172
-
173
- }
174
-
175
-
176
-
177
- this.redoStack.Clear();
178
-
179
- Debug.Log($"Record! UndoStack : {this.undoStack.Count} RedoStack : {this.redoStack.Count}");
180
-
181
- }
182
-
183
-
184
-
185
- private void UpdateSprite()
186
-
187
- {
188
-
189
- var previousSprite = this.image.sprite;
190
-
191
- this.image.sprite = Sprite.Create(
192
-
193
- this.texture,
194
-
195
- new Rect(0, 0, this.texture.width, this.texture.height),
196
-
197
- Vector2.zero);
198
-
199
- Destroy(previousSprite);
200
-
201
- }
202
-
203
-
204
-
205
- private Vector2Int GetPixelPosition()
206
-
207
- {
208
-
209
- if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(
210
-
211
- this.rectTransform,
212
-
213
- Input.mousePosition,
214
-
215
- null,
216
-
217
- out var pixelPositionFloat))
218
-
219
- {
220
-
221
- return this.cachedPixelPosition;
222
-
223
- }
224
-
225
-
226
-
227
- var sizeDelta = this.rectTransform.sizeDelta;
228
-
229
- pixelPositionFloat += sizeDelta * this.rectTransform.pivot;
230
-
231
- var pixelPosition = new Vector2Int(
232
-
233
- Mathf.Clamp((int)pixelPositionFloat.x, 0, this.textureSize.x - 1),
234
-
235
- Mathf.Clamp((int)pixelPositionFloat.y, 0, this.textureSize.y - 1));
236
-
237
- Debug.Log($"Pixel Position: {pixelPosition}");
238
-
239
- this.cachedPixelPosition = pixelPosition;
240
-
241
- return this.cachedPixelPosition;
242
-
243
- }
244
-
245
-
246
-
247
- // 入力座標がテクスチャ範囲内ならtrue、さもなければfalse
248
-
249
- private bool PositionIsWithinTexture(Vector2Int position)
250
-
251
- {
252
-
253
- return (position.x >= 0) && (position.y >= 0) &&
254
-
255
- (position.x < this.textureSize.x) && (position.y < this.textureSize.y);
256
-
257
- }
258
-
259
-
260
-
261
- // 入力座標に円を描く
262
-
263
- private void PaintAt(Vector2Int position, Color32 color, int radius)
264
-
265
- {
266
-
267
- var sqrRadius = radius * radius;
268
-
269
- for (var i = -radius; i <= radius; i++)
270
-
271
- {
272
-
273
- for (var j = -radius; j <= radius; j++)
274
-
275
- {
276
-
277
- var p = new Vector2Int(position.x + i, position.y + j);
278
-
279
- var dot = (i * i) + (j * j);
280
-
281
- if ((dot <= sqrRadius) && this.PositionIsWithinTexture(p))
282
-
283
- {
284
-
285
- this.texture.SetPixel(p.x, p.y, color);
286
-
287
- }
288
-
289
- }
290
-
291
- }
292
-
293
-
294
-
295
- this.texture.Apply();
296
-
297
- }
298
-
299
-
300
-
301
- private void LineTo(Vector2Int from, Vector2Int to, Color32 color, int radius)
302
-
303
- {
304
-
305
- var penPosition = from;
306
-
307
- var x = (float)penPosition.x;
308
-
309
- var y = (float)penPosition.y;
310
-
311
- var fromTo = to - from;
312
-
313
- var fromToSign = new Vector2Int((int)Mathf.Sign(fromTo.x), (int)Mathf.Sign(fromTo.y));
314
-
315
- var fromToXIsZero = fromToSign.x == 0;
316
-
317
- var fromToYIsZero = fromToSign.y == 0;
318
-
319
- fromToSign.x = fromToXIsZero ? 1 : fromToSign.x;
320
-
321
- fromToSign.y = fromToYIsZero ? 1 : fromToSign.y;
322
-
323
- var absFromTo = fromToSign * fromTo;
324
-
325
- var dominantDirection = 0;
326
-
327
- var delta = Vector2.zero;
328
-
329
- if (absFromTo.x >= absFromTo.y)
330
-
331
- {
332
-
333
- var tangent = fromToXIsZero ? 0 : (float)fromTo.y / fromTo.x;
334
-
335
- delta.x = fromToSign.x;
336
-
337
- delta.y = tangent * delta.x;
338
-
339
- }
340
-
341
- else
342
-
343
- {
344
-
345
- var tangent = fromToYIsZero ? 0 : (float)fromTo.x / fromTo.y;
346
-
347
- delta.y = fromToSign.y;
348
-
349
- delta.x = tangent * delta.y;
350
-
351
- dominantDirection = 1;
352
-
353
- }
354
-
355
-
356
-
357
- while (this.PositionIsWithinTexture(penPosition))
358
-
359
- {
360
-
361
- try
362
-
363
- {
364
-
365
- this.PaintAt(penPosition, color, radius);
366
-
367
- x += delta.x;
368
-
369
- y += delta.y;
370
-
371
- penPosition.x = (int)x;
372
-
373
- penPosition.y = (int)y;
374
-
375
- if (fromToSign[dominantDirection] > 0)
376
-
377
- {
378
-
379
- if (penPosition[dominantDirection] >= to[dominantDirection])
380
-
381
- {
382
-
383
- break;
384
-
385
- }
386
-
387
- }
388
-
389
- else
390
-
391
- {
392
-
393
- if (penPosition[dominantDirection] <= to[dominantDirection])
394
-
395
- {
396
-
397
- break;
398
-
399
- }
400
-
401
- }
402
-
403
- }
404
-
405
- catch (Exception e)
406
-
407
- {
408
-
409
- Debug.LogException(e);
410
-
411
- break;
412
-
413
- }
414
-
415
- }
416
-
417
- }
418
-
419
-
420
-
421
- private void Start()
422
-
423
- {
424
-
425
- this.rectTransform = this.transform as RectTransform;
426
-
427
- this.image = this.GetComponent<Image>();
428
-
429
- var sizeDelta = this.rectTransform.sizeDelta;
430
-
431
- var width = (int)sizeDelta.x;
432
-
433
- var height = (int)sizeDelta.y;
434
-
435
- this.texture = new Texture2D(width, height, TextureFormat.ARGB32, false) {filterMode = FilterMode.Bilinear};
436
-
437
- this.texture.SetPixels32(Enumerable.Repeat<Color32>(this.backgroundColor, width * height).ToArray());
438
-
439
- this.texture.Apply();
440
-
441
- this.textureSize = new Vector2Int(width, height);
442
-
443
- this.UpdateSprite();
444
-
445
- }
446
-
447
-
448
-
449
- private void Update()
450
-
451
- {
452
-
453
- if (Input.GetKeyDown(KeyCode.U))
454
-
455
- {
456
-
457
- this.Undo();
458
-
459
- }
460
-
461
-
462
-
463
- if (Input.GetKeyDown(KeyCode.R))
464
-
465
- {
466
-
467
- this.Redo();
468
-
469
- }
470
-
471
-
472
-
473
- if (Input.GetMouseButtonDown(0))
474
-
475
- {
476
-
477
- this.Record();
478
-
479
- this.previousPixelPosition = this.GetPixelPosition();
480
-
481
- }
482
-
483
- else if (Input.GetMouseButton(0))
484
-
485
- {
486
-
487
- var currentPixelPosition = this.GetPixelPosition();
488
-
489
- this.LineTo(this.previousPixelPosition, currentPixelPosition, this.foregroundColor, this.penRadius);
490
-
491
- this.previousPixelPosition = currentPixelPosition;
492
-
493
- }
494
-
495
- }
39
+ // ペンの半径...0で1ピクセルの線になる
40
+
41
+ [Range(0, 5)] public int penRadius;
42
+
43
+
44
+
45
+ // 前景色
46
+
47
+ public Color foregroundColor = Color.red;
48
+
49
+
50
+
51
+ // 背景色
52
+
53
+ [SerializeField] private Color backgroundColor = Color.white;
54
+
55
+
56
+
57
+ private RectTransform rectTransform;
58
+
59
+ private Image image;
60
+
61
+ private Texture2D texture;
62
+
63
+ private Vector2Int textureSize;
64
+
65
+ private Vector2Int previousPixelPosition;
66
+
67
+ private Vector2Int cachedPixelPosition;
68
+
69
+
70
+
71
+ // Undo、Redo用のテクスチャ格納庫
72
+
73
+ private readonly Stack<Texture2D> undoStack = new Stack<Texture2D>();
74
+
75
+ private readonly Stack<Texture2D> redoStack = new Stack<Texture2D>();
76
+
77
+
78
+
79
+ // Undo、Redo可能かどうかを外部スクリプトから調べたい場合、これらプロパティを参照する
80
+
81
+ public bool CanUndo
82
+
83
+ {
84
+
85
+ get { return this.undoStack.Count > 0; }
86
+
87
+ }
88
+
89
+
90
+
91
+ public bool CanRedo
92
+
93
+ {
94
+
95
+ get { return this.redoStack.Count > 0; }
96
+
97
+ }
98
+
99
+
100
+
101
+ // Undo時にはundoStackからテクスチャを1つ取り出して現在のテクスチャとし、
102
+
103
+ // 古いテクスチャはredoStackに積んでおく
104
+
105
+ public void Undo()
106
+
107
+ {
108
+
109
+ if (!this.CanUndo)
110
+
111
+ {
112
+
113
+ return;
114
+
115
+ }
116
+
117
+
118
+
119
+ var previousTexture = this.texture;
120
+
121
+ var poppedTexture = this.undoStack.Pop();
122
+
123
+ this.texture = poppedTexture;
124
+
125
+ this.redoStack.Push(previousTexture);
126
+
127
+ this.UpdateSprite();
128
+
129
+ Debug.LogFormat("Undo! UndoStack : {0} RedoStack : {1}", this.undoStack.Count, this.redoStack.Count);
130
+
131
+ }
132
+
133
+
134
+
135
+ // Redo時にはredoStackからテクスチャを1つ取り出して現在のテクスチャとし、
136
+
137
+ // 古いテクスチャはundoStackに積んでおく
138
+
139
+ public void Redo()
140
+
141
+ {
142
+
143
+ if (!this.CanRedo)
144
+
145
+ {
146
+
147
+ return;
148
+
149
+ }
150
+
151
+
152
+
153
+ var previousTexture = this.texture;
154
+
155
+ var poppedTexture = this.redoStack.Pop();
156
+
157
+ this.texture = poppedTexture;
158
+
159
+ this.undoStack.Push(previousTexture);
160
+
161
+ this.UpdateSprite();
162
+
163
+ Debug.LogFormat("Redo! UndoStack : {0} RedoStack : {1}", this.undoStack.Count, this.redoStack.Count);
164
+
165
+ }
166
+
167
+
168
+
169
+ // テクスチャに何かしらの操作(線を引くなど)を行う前にはRecordを実行することにする
170
+
171
+ // これによって変更前のテクスチャが複製されundoStackに積まれる
172
+
173
+ // また、このタイミングでredoStackは空にする
174
+
175
+ private void Record()
176
+
177
+ {
178
+
179
+ this.undoStack.Push(Instantiate(this.texture));
180
+
181
+ foreach (var textureInRedoStack in this.redoStack)
182
+
183
+ {
184
+
185
+ Destroy(textureInRedoStack);
186
+
187
+ }
188
+
189
+
190
+
191
+ this.redoStack.Clear();
192
+
193
+ Debug.LogFormat("Record! UndoStack : {0} RedoStack : {1}", this.undoStack.Count, this.redoStack.Count);
194
+
195
+ }
196
+
197
+
198
+
199
+ private void UpdateSprite()
200
+
201
+ {
202
+
203
+ var previousSprite = this.image.sprite;
204
+
205
+ this.image.sprite = Sprite.Create(
206
+
207
+ this.texture,
208
+
209
+ new Rect(0, 0, this.texture.width, this.texture.height),
210
+
211
+ Vector2.zero);
212
+
213
+ Destroy(previousSprite);
214
+
215
+ }
216
+
217
+
218
+
219
+ private Vector2Int GetPixelPosition()
220
+
221
+ {
222
+
223
+ if (!RectTransformUtility.ScreenPointToLocalPointInRectangle(
224
+
225
+ this.rectTransform,
226
+
227
+ Input.mousePosition,
228
+
229
+ null,
230
+
231
+ out var pixelPositionFloat))
232
+
233
+ {
234
+
235
+ return this.cachedPixelPosition;
236
+
237
+ }
238
+
239
+
240
+
241
+ var sizeDelta = this.rectTransform.sizeDelta;
242
+
243
+ pixelPositionFloat += sizeDelta * this.rectTransform.pivot;
244
+
245
+ var pixelPosition = new Vector2Int(
246
+
247
+ Mathf.Clamp((int)pixelPositionFloat.x, 0, this.textureSize.x - 1),
248
+
249
+ Mathf.Clamp((int)pixelPositionFloat.y, 0, this.textureSize.y - 1));
250
+
251
+ Debug.LogFormat("Pixel Position: {0}", pixelPosition);
252
+
253
+ this.cachedPixelPosition = pixelPosition;
254
+
255
+ return this.cachedPixelPosition;
256
+
257
+ }
258
+
259
+
260
+
261
+ // 入力座標がテクスチャ範囲内ならtrue、さもなければfalse
262
+
263
+ private bool PositionIsWithinTexture(Vector2Int position)
264
+
265
+ {
266
+
267
+ return (position.x >= 0) && (position.y >= 0) &&
268
+
269
+ (position.x < this.textureSize.x) && (position.y < this.textureSize.y);
270
+
271
+ }
272
+
273
+
274
+
275
+ // 入力座標に円を描く
276
+
277
+ private void PaintAt(Vector2Int position, Color32 color, int radius)
278
+
279
+ {
280
+
281
+ var sqrRadius = radius * radius;
282
+
283
+ for (var i = -radius; i <= radius; i++)
284
+
285
+ {
286
+
287
+ for (var j = -radius; j <= radius; j++)
288
+
289
+ {
290
+
291
+ var p = new Vector2Int(position.x + i, position.y + j);
292
+
293
+ var dot = (i * i) + (j * j);
294
+
295
+ if ((dot <= sqrRadius) && this.PositionIsWithinTexture(p))
296
+
297
+ {
298
+
299
+ this.texture.SetPixel(p.x, p.y, color);
300
+
301
+ }
302
+
303
+ }
304
+
305
+ }
306
+
307
+
308
+
309
+ this.texture.Apply();
310
+
311
+ }
312
+
313
+
314
+
315
+ private void LineTo(Vector2Int from, Vector2Int to, Color32 color, int radius)
316
+
317
+ {
318
+
319
+ var penPosition = from;
320
+
321
+ var x = (float)penPosition.x;
322
+
323
+ var y = (float)penPosition.y;
324
+
325
+ var fromTo = to - from;
326
+
327
+ var fromToSign = new Vector2Int((int)Mathf.Sign(fromTo.x), (int)Mathf.Sign(fromTo.y));
328
+
329
+ var fromToXIsZero = fromToSign.x == 0;
330
+
331
+ var fromToYIsZero = fromToSign.y == 0;
332
+
333
+ fromToSign.x = fromToXIsZero ? 1 : fromToSign.x;
334
+
335
+ fromToSign.y = fromToYIsZero ? 1 : fromToSign.y;
336
+
337
+ var absFromTo = fromToSign * fromTo;
338
+
339
+ var dominantDirection = 0;
340
+
341
+ var delta = Vector2.zero;
342
+
343
+ if (absFromTo.x >= absFromTo.y)
344
+
345
+ {
346
+
347
+ var tangent = fromToXIsZero ? 0 : (float)fromTo.y / fromTo.x;
348
+
349
+ delta.x = fromToSign.x;
350
+
351
+ delta.y = tangent * delta.x;
352
+
353
+ }
354
+
355
+ else
356
+
357
+ {
358
+
359
+ var tangent = fromToYIsZero ? 0 : (float)fromTo.x / fromTo.y;
360
+
361
+ delta.y = fromToSign.y;
362
+
363
+ delta.x = tangent * delta.y;
364
+
365
+ dominantDirection = 1;
366
+
367
+ }
368
+
369
+
370
+
371
+ while (this.PositionIsWithinTexture(penPosition))
372
+
373
+ {
374
+
375
+ try
376
+
377
+ {
378
+
379
+ this.PaintAt(penPosition, color, radius);
380
+
381
+ x += delta.x;
382
+
383
+ y += delta.y;
384
+
385
+ penPosition.x = (int)x;
386
+
387
+ penPosition.y = (int)y;
388
+
389
+ if (fromToSign[dominantDirection] > 0)
390
+
391
+ {
392
+
393
+ if (penPosition[dominantDirection] >= to[dominantDirection])
394
+
395
+ {
396
+
397
+ break;
398
+
399
+ }
400
+
401
+ }
402
+
403
+ else
404
+
405
+ {
406
+
407
+ if (penPosition[dominantDirection] <= to[dominantDirection])
408
+
409
+ {
410
+
411
+ break;
412
+
413
+ }
414
+
415
+ }
416
+
417
+ }
418
+
419
+ catch (Exception e)
420
+
421
+ {
422
+
423
+ Debug.LogException(e);
424
+
425
+ break;
426
+
427
+ }
428
+
429
+ }
430
+
431
+ }
432
+
433
+
434
+
435
+ private void Start()
436
+
437
+ {
438
+
439
+ this.rectTransform = this.transform as RectTransform;
440
+
441
+ this.image = this.GetComponent<Image>();
442
+
443
+ var sizeDelta = this.rectTransform.sizeDelta;
444
+
445
+ var width = (int)sizeDelta.x;
446
+
447
+ var height = (int)sizeDelta.y;
448
+
449
+ this.texture = new Texture2D(width, height, TextureFormat.ARGB32, false) {filterMode = FilterMode.Bilinear};
450
+
451
+ this.texture.SetPixels32(Enumerable.Repeat<Color32>(this.backgroundColor, width * height).ToArray());
452
+
453
+ this.texture.Apply();
454
+
455
+ this.textureSize = new Vector2Int(width, height);
456
+
457
+ this.UpdateSprite();
458
+
459
+ }
460
+
461
+
462
+
463
+ private void Update()
464
+
465
+ {
466
+
467
+ if (Input.GetKeyDown(KeyCode.U))
468
+
469
+ {
470
+
471
+ this.Undo();
472
+
473
+ }
474
+
475
+
476
+
477
+ if (Input.GetKeyDown(KeyCode.R))
478
+
479
+ {
480
+
481
+ this.Redo();
482
+
483
+ }
484
+
485
+
486
+
487
+ if (Input.GetMouseButtonDown(0))
488
+
489
+ {
490
+
491
+ this.Record();
492
+
493
+ this.previousPixelPosition = this.GetPixelPosition();
494
+
495
+ }
496
+
497
+ else if (Input.GetMouseButton(0))
498
+
499
+ {
500
+
501
+ var currentPixelPosition = this.GetPixelPosition();
502
+
503
+ this.LineTo(this.previousPixelPosition, currentPixelPosition, this.foregroundColor, this.penRadius);
504
+
505
+ this.previousPixelPosition = currentPixelPosition;
506
+
507
+ }
508
+
509
+ }
496
510
 
497
511
  }
498
512