回答編集履歴

4

コルーチン生存確認について追記

2021/02/09 21:21

投稿

Bongo
Bongo

スコア10807

test CHANGED
@@ -6,59 +6,59 @@
6
6
 
7
7
  ```C#
8
8
 
9
- [SerializeField] private GameObject startPoint;
10
-
11
- [SerializeField] private GameObject endPoint;
12
-
13
-
14
-
15
- float startTime;
16
-
17
- float speed = 2;
18
-
19
- Vector3 dir;
20
-
21
- Vector3 startPosition;
22
-
23
- float distance;
24
-
25
-
26
-
27
- void Start()
28
-
29
- {
30
-
31
- startTime = Time.time;
32
-
33
- startPosition = startPoint.transform.position;
34
-
35
- Vector3 endPosition = endPoint.transform.position;
36
-
37
- dir = (endPosition - startPosition).normalized;
38
-
39
- distance = Vector3.Distance(startPosition, endPosition);
40
-
41
- }
42
-
43
-
44
-
45
- void Update()
46
-
47
- {
48
-
49
- float t = (Time.time - startTime) * speed;
50
-
51
- transform.position = startPosition + (dir * Mathf.PingPong(t, distance));
52
-
53
-
54
-
55
- // 進行方向は、PingPongの式の中にある「t - length」の
56
-
57
- // 符号で判断できるんじゃないでしょうか?
58
-
59
- transform.rotation = Quaternion.LookRotation(dir * Mathf.Sign(this.distance - Mathf.Repeat(t, distance * 2.0f)));
60
-
61
- }
9
+ [SerializeField] private GameObject startPoint;
10
+
11
+ [SerializeField] private GameObject endPoint;
12
+
13
+
14
+
15
+ float startTime;
16
+
17
+ float speed = 2;
18
+
19
+ Vector3 dir;
20
+
21
+ Vector3 startPosition;
22
+
23
+ float distance;
24
+
25
+
26
+
27
+ void Start()
28
+
29
+ {
30
+
31
+ startTime = Time.time;
32
+
33
+ startPosition = startPoint.transform.position;
34
+
35
+ Vector3 endPosition = endPoint.transform.position;
36
+
37
+ dir = (endPosition - startPosition).normalized;
38
+
39
+ distance = Vector3.Distance(startPosition, endPosition);
40
+
41
+ }
42
+
43
+
44
+
45
+ void Update()
46
+
47
+ {
48
+
49
+ float t = (Time.time - startTime) * speed;
50
+
51
+ transform.position = startPosition + (dir * Mathf.PingPong(t, distance));
52
+
53
+
54
+
55
+ // 進行方向は、PingPongの式の中にある「t - length」の
56
+
57
+ // 符号で判断できるんじゃないでしょうか?
58
+
59
+ transform.rotation = Quaternion.LookRotation(dir * Mathf.Sign(this.distance - Mathf.Repeat(t, distance * 2.0f)));
60
+
61
+ }
62
62
 
63
63
  ```
64
64
 
@@ -74,83 +74,83 @@
74
74
 
75
75
  ```C#
76
76
 
77
- void Start()
78
-
79
- {
80
-
81
- startTime = Time.time;
82
-
83
- startPosition = startPoint.transform.position;
84
-
85
- Vector3 endPosition = endPoint.transform.position;
86
-
87
-
88
-
89
- // 下記のようにすればstartPositionを
90
-
91
- // 通る水平面上を動くはずです
92
-
93
- endPosition.y = startPosition.y;
94
-
95
-
96
-
97
- // あるいは、起点・終点のy成分を0にしてしまえば
98
-
99
- // 高さを無視してY=0の平面上を移動するでしょう
100
-
101
- //startPosition.y = 0.0f;
102
-
103
- //endPosition.y = 0.0f;
104
-
105
-
106
-
107
- dir = (endPosition - startPosition).normalized;
108
-
109
- distance = Vector3.Distance(startPosition, endPosition);
110
-
111
- }
112
-
113
-
114
-
115
- void Update()
116
-
117
- {
118
-
119
- float t = (Time.time - startTime) * speed;
120
-
121
- Vector3 newPosition = startPosition + (dir * Mathf.PingPong(t, distance));
122
-
123
-
124
-
125
- // さまざまな高さの建物がある地形とのことですが、それらの高さを無視して
126
-
127
- // 貫通して動くのではなく、建物の屋上に乗っているように見せたい場合は
128
-
129
- // Raycastも併用して位置を修正する必要があるかと思います
130
-
131
- // 「移動オブジェクトのY軸座標は変化させずに」とのことですので、
132
-
133
- // そういうことをしたいのではないだろうとは思うのですが...
134
-
135
- /*
136
-
137
- if (Physics.Raycast(new Ray(new Vector3(newPosition.x, 100.0f, newPosition.z), Vector3.down), out var hitInfo))
138
-
139
- {
140
-
141
- newPosition = hitInfo.point;
142
-
143
- }
144
-
145
- */
146
-
147
-
148
-
149
- transform.position = newPosition;
150
-
151
- transform.rotation = Quaternion.LookRotation(dir * Mathf.Sign(this.distance - Mathf.Repeat(t, distance * 2.0f)));
152
-
153
- }
77
+ void Start()
78
+
79
+ {
80
+
81
+ startTime = Time.time;
82
+
83
+ startPosition = startPoint.transform.position;
84
+
85
+ Vector3 endPosition = endPoint.transform.position;
86
+
87
+
88
+
89
+ // 下記のようにすればstartPositionを
90
+
91
+ // 通る水平面上を動くはずです
92
+
93
+ endPosition.y = startPosition.y;
94
+
95
+
96
+
97
+ // あるいは、起点・終点のy成分を0にしてしまえば
98
+
99
+ // 高さを無視してY=0の平面上を移動するでしょう
100
+
101
+ //startPosition.y = 0.0f;
102
+
103
+ //endPosition.y = 0.0f;
104
+
105
+
106
+
107
+ dir = (endPosition - startPosition).normalized;
108
+
109
+ distance = Vector3.Distance(startPosition, endPosition);
110
+
111
+ }
112
+
113
+
114
+
115
+ void Update()
116
+
117
+ {
118
+
119
+ float t = (Time.time - startTime) * speed;
120
+
121
+ Vector3 newPosition = startPosition + (dir * Mathf.PingPong(t, distance));
122
+
123
+
124
+
125
+ // さまざまな高さの建物がある地形とのことですが、それらの高さを無視して
126
+
127
+ // 貫通して動くのではなく、建物の屋上に乗っているように見せたい場合は
128
+
129
+ // Raycastも併用して位置を修正する必要があるかと思います
130
+
131
+ // 「移動オブジェクトのY軸座標は変化させずに」とのことですので、
132
+
133
+ // そういうことをしたいのではないだろうとは思うのですが...
134
+
135
+ /*
136
+
137
+ if (Physics.Raycast(new Ray(new Vector3(newPosition.x, 100.0f, newPosition.z), Vector3.down), out var hitInfo))
138
+
139
+ {
140
+
141
+ newPosition = hitInfo.point;
142
+
143
+ }
144
+
145
+ */
146
+
147
+
148
+
149
+ transform.position = newPosition;
150
+
151
+ transform.rotation = Quaternion.LookRotation(dir * Mathf.Sign(this.distance - Mathf.Repeat(t, distance * 2.0f)));
152
+
153
+ }
154
154
 
155
155
  ```
156
156
 
@@ -162,169 +162,169 @@
162
162
 
163
163
  ```C#
164
164
 
165
- [SerializeField] private GameObject startPoint;
166
-
167
- [SerializeField] private GameObject endPoint;
168
-
169
- [SerializeField] private float animationLength = 1.0f;
170
-
171
-
172
-
173
- float startTime;
174
-
175
- float pauseTime;
176
-
177
- bool paused;
178
-
179
- float speed = 2;
180
-
181
- Vector3 dir;
182
-
183
- Vector3 startPosition;
184
-
185
- float distance;
186
-
187
- int directionSign;
188
-
189
-
190
-
191
- public void Pause()
192
-
193
- {
194
-
195
- // 一時停止フラグを立て、現在の時刻を記録する
196
-
197
- paused = true;
198
-
199
- pauseTime = Time.time;
200
-
201
- }
202
-
203
-
204
-
205
- public void Resume()
206
-
207
- {
208
-
209
- // 移動再開時に、停止していた時間をstartTimeに加算する
210
-
211
- paused = false;
212
-
213
- startTime += Time.time - pauseTime;
214
-
215
- }
216
-
217
-
218
-
219
- void Start()
220
-
221
- {
222
-
223
- startTime = Time.time;
224
-
225
- startPosition = startPoint.transform.position;
226
-
227
- Vector3 endPosition = endPoint.transform.position;
228
-
229
- startPosition.y = 0.0f;
230
-
231
- endPosition.y = 0.0f;
232
-
233
- dir = (endPosition - startPosition).normalized;
234
-
235
- distance = Vector3.Distance(startPosition, endPosition);
236
-
237
-
238
-
239
- // 進行方向の符号...1で順方向、-1で逆方向
240
-
241
- // スタート時点の進行方向は順方向としておく
242
-
243
- directionSign = 1;
244
-
245
- }
246
-
247
-
248
-
249
- void Update()
250
-
251
- {
252
-
253
- if (paused)
254
-
255
- {
256
-
257
- return;
258
-
259
- }
260
-
261
-
262
-
263
- float t = (Time.time - startTime) * speed;
264
-
265
- Vector3 newPosition = startPosition + (dir * Mathf.PingPong(t, distance));
266
-
267
- transform.position = newPosition;
268
-
269
-
270
-
271
- int newDirectionSign = (int)Mathf.Sign(distance - Mathf.Repeat(t, distance * 2.0f));
272
-
273
- if (newDirectionSign != directionSign)
274
-
275
- {
276
-
277
- // もし進行方向が反転したら、一時停止して
278
-
279
- // 進行方向を更新、転回コルーチンを開始する
280
-
281
- Pause();
282
-
283
- directionSign = newDirectionSign;
284
-
285
- StartCoroutine(Turn(transform));
286
-
287
- return;
288
-
289
- }
290
-
291
-
292
-
293
- transform.rotation = Quaternion.LookRotation(dir * newDirectionSign);
294
-
295
- }
296
-
297
-
298
-
299
- IEnumerator Turn(Transform trf)
300
-
301
- {
302
-
303
- Vector3 baseForward = trf.forward;
304
-
305
- for (float time = 0.0f; time < animationLength; time += Time.deltaTime)
306
-
307
- {
308
-
309
- float t = time / animationLength;
310
-
311
- Quaternion q = Quaternion.Euler(0.0f, Mathf.Lerp(0.0f, 180.0f, t), 0.0f);
312
-
313
- trf.forward = q * baseForward;
314
-
315
- yield return null;
316
-
317
- }
318
-
319
- trf.forward = Quaternion.Euler(0.0f, 180.0f, 0.0f) * baseForward;
320
-
321
-
322
-
323
- // 転回終了後に移動を再開
324
-
325
- Resume();
326
-
327
- }
165
+ [SerializeField] private GameObject startPoint;
166
+
167
+ [SerializeField] private GameObject endPoint;
168
+
169
+ [SerializeField] private float animationLength = 1.0f;
170
+
171
+
172
+
173
+ float startTime;
174
+
175
+ float pauseTime;
176
+
177
+ bool paused;
178
+
179
+ float speed = 2;
180
+
181
+ Vector3 dir;
182
+
183
+ Vector3 startPosition;
184
+
185
+ float distance;
186
+
187
+ int directionSign;
188
+
189
+
190
+
191
+ public void Pause()
192
+
193
+ {
194
+
195
+ // 一時停止フラグを立て、現在の時刻を記録する
196
+
197
+ paused = true;
198
+
199
+ pauseTime = Time.time;
200
+
201
+ }
202
+
203
+
204
+
205
+ public void Resume()
206
+
207
+ {
208
+
209
+ // 移動再開時に、停止していた時間をstartTimeに加算する
210
+
211
+ paused = false;
212
+
213
+ startTime += Time.time - pauseTime;
214
+
215
+ }
216
+
217
+
218
+
219
+ void Start()
220
+
221
+ {
222
+
223
+ startTime = Time.time;
224
+
225
+ startPosition = startPoint.transform.position;
226
+
227
+ Vector3 endPosition = endPoint.transform.position;
228
+
229
+ startPosition.y = 0.0f;
230
+
231
+ endPosition.y = 0.0f;
232
+
233
+ dir = (endPosition - startPosition).normalized;
234
+
235
+ distance = Vector3.Distance(startPosition, endPosition);
236
+
237
+
238
+
239
+ // 進行方向の符号...1で順方向、-1で逆方向
240
+
241
+ // スタート時点の進行方向は順方向としておく
242
+
243
+ directionSign = 1;
244
+
245
+ }
246
+
247
+
248
+
249
+ void Update()
250
+
251
+ {
252
+
253
+ if (paused)
254
+
255
+ {
256
+
257
+ return;
258
+
259
+ }
260
+
261
+
262
+
263
+ float t = (Time.time - startTime) * speed;
264
+
265
+ Vector3 newPosition = startPosition + (dir * Mathf.PingPong(t, distance));
266
+
267
+ transform.position = newPosition;
268
+
269
+
270
+
271
+ int newDirectionSign = (int)Mathf.Sign(distance - Mathf.Repeat(t, distance * 2.0f));
272
+
273
+ if (newDirectionSign != directionSign)
274
+
275
+ {
276
+
277
+ // もし進行方向が反転したら、一時停止して
278
+
279
+ // 進行方向を更新、転回コルーチンを開始する
280
+
281
+ Pause();
282
+
283
+ directionSign = newDirectionSign;
284
+
285
+ StartCoroutine(Turn(transform));
286
+
287
+ return;
288
+
289
+ }
290
+
291
+
292
+
293
+ transform.rotation = Quaternion.LookRotation(dir * newDirectionSign);
294
+
295
+ }
296
+
297
+
298
+
299
+ IEnumerator Turn(Transform trf)
300
+
301
+ {
302
+
303
+ Vector3 baseForward = trf.forward;
304
+
305
+ for (float time = 0.0f; time < animationLength; time += Time.deltaTime)
306
+
307
+ {
308
+
309
+ float t = time / animationLength;
310
+
311
+ Quaternion q = Quaternion.Euler(0.0f, Mathf.Lerp(0.0f, 180.0f, t), 0.0f);
312
+
313
+ trf.forward = q * baseForward;
314
+
315
+ yield return null;
316
+
317
+ }
318
+
319
+ trf.forward = Quaternion.Euler(0.0f, 180.0f, 0.0f) * baseForward;
320
+
321
+
322
+
323
+ // 転回終了後に移動を再開
324
+
325
+ Resume();
326
+
327
+ }
328
328
 
329
329
  ```
330
330
 
@@ -336,272 +336,436 @@
336
336
 
337
337
  ```C#
338
338
 
339
- [SerializeField] GameObject startPoint;
340
-
341
- [SerializeField] GameObject endPoint;
342
-
343
- [SerializeField] float animationLength = 1.0f;
344
-
345
- [SerializeField] Transform target;
346
-
347
- Vector3 dir;
348
-
349
- int directionSign;
350
-
351
- float distance;
352
-
353
- bool paused;
354
-
355
- float pauseTime;
356
-
357
- readonly float speed = 2;
358
-
359
- Vector3 startPosition;
360
-
361
-
362
-
363
- float startTime;
364
-
365
-
366
-
367
- void Start()
368
-
369
- {
370
-
371
- startTime = Time.time;
372
-
373
- startPosition = startPoint.transform.position;
374
-
375
- Vector3 endPosition = endPoint.transform.position;
376
-
377
- startPosition.y = 0.0f;
378
-
379
- endPosition.y = 0.0f;
380
-
381
- dir = (endPosition - startPosition).normalized;
382
-
383
- distance = Vector3.Distance(startPosition, endPosition);
384
-
385
- directionSign = 1;
386
-
387
- }
388
-
389
-
390
-
391
- void Update()
392
-
393
- {
394
-
395
- if (paused)
396
-
397
- {
398
-
399
- return;
400
-
401
- }
402
-
403
-
404
-
405
- float t = (Time.time - startTime) * speed;
406
-
407
- Vector3 newPosition = startPosition + (dir * Mathf.PingPong(t, distance));
408
-
409
- transform.position = newPosition;
410
-
411
- int newDirectionSign = (int)Mathf.Sign(distance - Mathf.Repeat(t, distance * 2.0f));
412
-
413
- if (newDirectionSign != directionSign)
414
-
415
- {
416
-
417
- Pause();
418
-
419
- directionSign = newDirectionSign;
420
-
421
- StartCoroutine(Turn(transform));
422
-
423
- return;
424
-
425
- }
426
-
427
-
428
-
429
- transform.rotation = Quaternion.LookRotation(dir * newDirectionSign);
430
-
431
-
432
-
433
- // 実験として、スペースバーで模擬的な会話を行う
434
-
435
- if (!paused && Input.GetKeyDown(KeyCode.Space))
436
-
437
- {
438
-
439
- StartCoroutine(TalkWith(target));
440
-
441
- }
442
-
443
- }
444
-
445
-
446
-
447
- public void Pause()
448
-
449
- {
450
-
451
- // 今さらながら、もし一時停止中に再度Pauseを行うと時刻が狂うため
452
-
453
- // 一時停止中には時刻の記録を行わないようにしました
454
-
455
- if (paused)
456
-
457
- {
458
-
459
- return;
460
-
461
- }
462
-
463
-
464
-
465
- paused = true;
466
-
467
- pauseTime = Time.time;
468
-
469
- }
470
-
471
-
472
-
473
- public void Resume()
474
-
475
- {
476
-
477
- // 同じく時刻の狂いを防止するため、移動中には
478
-
479
- // 開始時刻の更新を行わないようにしました
480
-
481
- if (!paused)
482
-
483
- {
484
-
485
- return;
486
-
487
- }
488
-
489
-
490
-
491
- paused = false;
492
-
493
- startTime += Time.time - pauseTime;
494
-
495
- }
496
-
497
-
498
-
499
- IEnumerator TalkWith(Transform targetTransform)
500
-
501
- {
502
-
503
- // 念のため目標方向をXZ平面上に投影しておく
504
-
505
- Vector3 targetDir = Vector3.ProjectOnPlane(targetTransform.position - transform.position, Vector3.up).normalized;
506
-
507
- Vector3 forward = transform.forward;
508
-
509
-
510
-
511
- // 一時停止して目標方向へ回転し...
512
-
513
- Pause();
514
-
515
- yield return YTurnToTarget(transform, targetDir);
516
-
517
-
518
-
519
- // コンソールに文章を表示、少し待機する(会話しているつもり)
520
-
521
- Debug.Log("Hello!");
522
-
523
- yield return new WaitForSeconds(5.0f);
524
-
525
-
526
-
527
- // 元の方向へ回転し、一時停止を解除する
528
-
529
- yield return YTurnToTarget(transform, forward);
530
-
531
- Resume();
532
-
533
- }
534
-
535
-
536
-
537
- // 引数としてターゲットへの方角を受け取ることにする
538
-
539
- IEnumerator YTurnToTarget(Transform trf, Vector3 targetDir)
540
-
541
- {
542
-
543
- Vector3 baseForward = trf.forward;
544
-
545
-
546
-
547
- // Y軸周りの符号付き回転角を得て...
548
-
549
- float angle = Vector3.SignedAngle(baseForward, targetDir, Vector3.up);
550
-
551
- for (float time = 0.0f; time < animationLength; time += Time.deltaTime)
552
-
553
- {
554
-
555
- float t = time / animationLength;
556
-
557
-
558
-
559
- // Lerpの引数としてangleを使う
560
-
561
- Quaternion q = Quaternion.Euler(0.0f, Mathf.Lerp(0.0f, angle, t), 0.0f);
562
-
563
- trf.forward = q * baseForward;
564
-
565
- yield return null;
566
-
567
- }
568
-
569
-
570
-
571
- // 補間値t=1の調整処理
572
-
573
- trf.forward = Quaternion.Euler(0.0f, angle, 0.0f) * baseForward;
574
-
575
- }
576
-
577
-
578
-
579
- IEnumerator Turn(Transform trf)
580
-
581
- {
582
-
583
- Vector3 baseForward = trf.forward;
584
-
585
- for (float time = 0.0f; time < animationLength; time += Time.deltaTime)
586
-
587
- {
588
-
589
- float t = time / animationLength;
590
-
591
- Quaternion q = Quaternion.Euler(0.0f, Mathf.Lerp(0.0f, 180.0f, t), 0.0f);
592
-
593
- trf.forward = q * baseForward;
594
-
595
- yield return null;
596
-
597
- }
598
-
599
-
600
-
601
- trf.forward = Quaternion.Euler(0.0f, 180.0f, 0.0f) * baseForward;
602
-
603
- Resume();
604
-
605
- }
339
+ [SerializeField] GameObject startPoint;
340
+
341
+ [SerializeField] GameObject endPoint;
342
+
343
+ [SerializeField] float animationLength = 1.0f;
344
+
345
+ [SerializeField] Transform target;
346
+
347
+ Vector3 dir;
348
+
349
+ int directionSign;
350
+
351
+ float distance;
352
+
353
+ bool paused;
354
+
355
+ float pauseTime;
356
+
357
+ readonly float speed = 2;
358
+
359
+ Vector3 startPosition;
360
+
361
+
362
+
363
+ float startTime;
364
+
365
+
366
+
367
+ void Start()
368
+
369
+ {
370
+
371
+ startTime = Time.time;
372
+
373
+ startPosition = startPoint.transform.position;
374
+
375
+ Vector3 endPosition = endPoint.transform.position;
376
+
377
+ startPosition.y = 0.0f;
378
+
379
+ endPosition.y = 0.0f;
380
+
381
+ dir = (endPosition - startPosition).normalized;
382
+
383
+ distance = Vector3.Distance(startPosition, endPosition);
384
+
385
+ directionSign = 1;
386
+
387
+ }
388
+
389
+
390
+
391
+ void Update()
392
+
393
+ {
394
+
395
+ if (paused)
396
+
397
+ {
398
+
399
+ return;
400
+
401
+ }
402
+
403
+
404
+
405
+ float t = (Time.time - startTime) * speed;
406
+
407
+ Vector3 newPosition = startPosition + (dir * Mathf.PingPong(t, distance));
408
+
409
+ transform.position = newPosition;
410
+
411
+ int newDirectionSign = (int)Mathf.Sign(distance - Mathf.Repeat(t, distance * 2.0f));
412
+
413
+ if (newDirectionSign != directionSign)
414
+
415
+ {
416
+
417
+ Pause();
418
+
419
+ directionSign = newDirectionSign;
420
+
421
+ StartCoroutine(Turn(transform));
422
+
423
+ return;
424
+
425
+ }
426
+
427
+
428
+
429
+ transform.rotation = Quaternion.LookRotation(dir * newDirectionSign);
430
+
431
+
432
+
433
+ // 実験として、スペースバーで模擬的な会話を行う
434
+
435
+ if (!paused && Input.GetKeyDown(KeyCode.Space))
436
+
437
+ {
438
+
439
+ StartCoroutine(TalkWith(target));
440
+
441
+ }
442
+
443
+ }
444
+
445
+
446
+
447
+ public void Pause()
448
+
449
+ {
450
+
451
+ // 今さらながら、もし一時停止中に再度Pauseを行うと時刻が狂うため
452
+
453
+ // 一時停止中には時刻の記録を行わないようにしました
454
+
455
+ if (paused)
456
+
457
+ {
458
+
459
+ return;
460
+
461
+ }
462
+
463
+
464
+
465
+ paused = true;
466
+
467
+ pauseTime = Time.time;
468
+
469
+ }
470
+
471
+
472
+
473
+ public void Resume()
474
+
475
+ {
476
+
477
+ // 同じく時刻の狂いを防止するため、移動中には
478
+
479
+ // 開始時刻の更新を行わないようにしました
480
+
481
+ if (!paused)
482
+
483
+ {
484
+
485
+ return;
486
+
487
+ }
488
+
489
+
490
+
491
+ paused = false;
492
+
493
+ startTime += Time.time - pauseTime;
494
+
495
+ }
496
+
497
+
498
+
499
+ IEnumerator TalkWith(Transform targetTransform)
500
+
501
+ {
502
+
503
+ // 念のため目標方向をXZ平面上に投影しておく
504
+
505
+ Vector3 targetDir = Vector3.ProjectOnPlane(targetTransform.position - transform.position, Vector3.up).normalized;
506
+
507
+ Vector3 forward = transform.forward;
508
+
509
+
510
+
511
+ // 一時停止して目標方向へ回転し...
512
+
513
+ Pause();
514
+
515
+ yield return YTurnToTarget(transform, targetDir);
516
+
517
+
518
+
519
+ // コンソールに文章を表示、少し待機する(会話しているつもり)
520
+
521
+ Debug.Log("Hello!");
522
+
523
+ yield return new WaitForSeconds(5.0f);
524
+
525
+
526
+
527
+ // 元の方向へ回転し、一時停止を解除する
528
+
529
+ yield return YTurnToTarget(transform, forward);
530
+
531
+ Resume();
532
+
533
+ }
534
+
535
+
536
+
537
+ // 引数としてターゲットへの方角を受け取ることにする
538
+
539
+ IEnumerator YTurnToTarget(Transform trf, Vector3 targetDir)
540
+
541
+ {
542
+
543
+ Vector3 baseForward = trf.forward;
544
+
545
+
546
+
547
+ // Y軸周りの符号付き回転角を得て...
548
+
549
+ float angle = Vector3.SignedAngle(baseForward, targetDir, Vector3.up);
550
+
551
+ for (float time = 0.0f; time < animationLength; time += Time.deltaTime)
552
+
553
+ {
554
+
555
+ float t = time / animationLength;
556
+
557
+
558
+
559
+ // Lerpの引数としてangleを使う
560
+
561
+ Quaternion q = Quaternion.Euler(0.0f, Mathf.Lerp(0.0f, angle, t), 0.0f);
562
+
563
+ trf.forward = q * baseForward;
564
+
565
+ yield return null;
566
+
567
+ }
568
+
569
+
570
+
571
+ // 補間値t=1の調整処理
572
+
573
+ trf.forward = Quaternion.Euler(0.0f, angle, 0.0f) * baseForward;
574
+
575
+ }
576
+
577
+
578
+
579
+ IEnumerator Turn(Transform trf)
580
+
581
+ {
582
+
583
+ Vector3 baseForward = trf.forward;
584
+
585
+ for (float time = 0.0f; time < animationLength; time += Time.deltaTime)
586
+
587
+ {
588
+
589
+ float t = time / animationLength;
590
+
591
+ Quaternion q = Quaternion.Euler(0.0f, Mathf.Lerp(0.0f, 180.0f, t), 0.0f);
592
+
593
+ trf.forward = q * baseForward;
594
+
595
+ yield return null;
596
+
597
+ }
598
+
599
+
600
+
601
+ trf.forward = Quaternion.Euler(0.0f, 180.0f, 0.0f) * baseForward;
602
+
603
+ Resume();
604
+
605
+ }
606
606
 
607
607
  ```
608
+
609
+
610
+
611
+ ##コルーチンの生存確認
612
+
613
+
614
+
615
+ **案1**
616
+
617
+
618
+
619
+ `MyCoroutine`内での`null`チェックは削除し、`Update`でのコルーチン起動判定条件として`null`チェックを行うのはどうでしょう。
620
+
621
+
622
+
623
+ ```C#
624
+
625
+ using System.Collections;
626
+
627
+ using UnityEngine;
628
+
629
+
630
+
631
+ public class TestCoroutine : MonoBehaviour
632
+
633
+ {
634
+
635
+ Coroutine RunningMyCoroutine;
636
+
637
+
638
+
639
+ void Start()
640
+
641
+ {
642
+
643
+ RunningMyCoroutine = StartCoroutine(MyCoroutine());
644
+
645
+ }
646
+
647
+
648
+
649
+ void Update()
650
+
651
+ {
652
+
653
+ if ((RunningMyCoroutine == null) && Input.GetMouseButtonDown(0))
654
+
655
+ {
656
+
657
+ RunningMyCoroutine = StartCoroutine(MyCoroutine());
658
+
659
+ }
660
+
661
+ }
662
+
663
+
664
+
665
+ IEnumerator MyCoroutine()
666
+
667
+ {
668
+
669
+ int i = 0;
670
+
671
+ while (i < 5)
672
+
673
+ {
674
+
675
+ Debug.Log($"MyCoroutine:{i}");
676
+
677
+ i++;
678
+
679
+ yield return new WaitForSeconds(2.0f);
680
+
681
+ }
682
+
683
+ RunningMyCoroutine = null;
684
+
685
+ }
686
+
687
+ }
688
+
689
+ ```
690
+
691
+
692
+
693
+ **案2**
694
+
695
+
696
+
697
+ `yield return`を行わずにいきなり終了するコルーチンを始動した場合`StartCoroutine`の返り値は`null`になるようなので、「返り値が`null`なら`RunningMyCoroutine`は元の値のままとする」ということにしてもよさそうです。
698
+
699
+
700
+
701
+ ```C#
702
+
703
+ using System.Collections;
704
+
705
+ using UnityEngine;
706
+
707
+
708
+
709
+ public class TestCoroutine : MonoBehaviour
710
+
711
+ {
712
+
713
+
714
+
715
+ Coroutine RunningMyCoroutine;
716
+
717
+
718
+
719
+ void Start()
720
+
721
+ {
722
+
723
+ RunningMyCoroutine = StartCoroutine(MyCoroutine());
724
+
725
+ }
726
+
727
+
728
+
729
+ void Update()
730
+
731
+ {
732
+
733
+ if (Input.GetMouseButtonDown(0))
734
+
735
+ {
736
+
737
+ RunningMyCoroutine = StartCoroutine(MyCoroutine()) ?? RunningMyCoroutine;
738
+
739
+ }
740
+
741
+ }
742
+
743
+
744
+
745
+ IEnumerator MyCoroutine()
746
+
747
+ {
748
+
749
+ if (RunningMyCoroutine != null) yield break;
750
+
751
+ int i = 0;
752
+
753
+ while (i<5)
754
+
755
+ {
756
+
757
+ Debug.Log($"MyCoroutine:{i}");
758
+
759
+ i++;
760
+
761
+ yield return new WaitForSeconds(2.0f);
762
+
763
+ }
764
+
765
+ RunningMyCoroutine = null;
766
+
767
+ }
768
+
769
+ }
770
+
771
+ ```

3

目標方向への回転案を追記

2021/02/09 21:21

投稿

Bongo
Bongo

スコア10807

test CHANGED
@@ -327,3 +327,281 @@
327
327
  }
328
328
 
329
329
  ```
330
+
331
+
332
+
333
+ ##目標方向へ回転
334
+
335
+
336
+
337
+ ```C#
338
+
339
+ [SerializeField] GameObject startPoint;
340
+
341
+ [SerializeField] GameObject endPoint;
342
+
343
+ [SerializeField] float animationLength = 1.0f;
344
+
345
+ [SerializeField] Transform target;
346
+
347
+ Vector3 dir;
348
+
349
+ int directionSign;
350
+
351
+ float distance;
352
+
353
+ bool paused;
354
+
355
+ float pauseTime;
356
+
357
+ readonly float speed = 2;
358
+
359
+ Vector3 startPosition;
360
+
361
+
362
+
363
+ float startTime;
364
+
365
+
366
+
367
+ void Start()
368
+
369
+ {
370
+
371
+ startTime = Time.time;
372
+
373
+ startPosition = startPoint.transform.position;
374
+
375
+ Vector3 endPosition = endPoint.transform.position;
376
+
377
+ startPosition.y = 0.0f;
378
+
379
+ endPosition.y = 0.0f;
380
+
381
+ dir = (endPosition - startPosition).normalized;
382
+
383
+ distance = Vector3.Distance(startPosition, endPosition);
384
+
385
+ directionSign = 1;
386
+
387
+ }
388
+
389
+
390
+
391
+ void Update()
392
+
393
+ {
394
+
395
+ if (paused)
396
+
397
+ {
398
+
399
+ return;
400
+
401
+ }
402
+
403
+
404
+
405
+ float t = (Time.time - startTime) * speed;
406
+
407
+ Vector3 newPosition = startPosition + (dir * Mathf.PingPong(t, distance));
408
+
409
+ transform.position = newPosition;
410
+
411
+ int newDirectionSign = (int)Mathf.Sign(distance - Mathf.Repeat(t, distance * 2.0f));
412
+
413
+ if (newDirectionSign != directionSign)
414
+
415
+ {
416
+
417
+ Pause();
418
+
419
+ directionSign = newDirectionSign;
420
+
421
+ StartCoroutine(Turn(transform));
422
+
423
+ return;
424
+
425
+ }
426
+
427
+
428
+
429
+ transform.rotation = Quaternion.LookRotation(dir * newDirectionSign);
430
+
431
+
432
+
433
+ // 実験として、スペースバーで模擬的な会話を行う
434
+
435
+ if (!paused && Input.GetKeyDown(KeyCode.Space))
436
+
437
+ {
438
+
439
+ StartCoroutine(TalkWith(target));
440
+
441
+ }
442
+
443
+ }
444
+
445
+
446
+
447
+ public void Pause()
448
+
449
+ {
450
+
451
+ // 今さらながら、もし一時停止中に再度Pauseを行うと時刻が狂うため
452
+
453
+ // 一時停止中には時刻の記録を行わないようにしました
454
+
455
+ if (paused)
456
+
457
+ {
458
+
459
+ return;
460
+
461
+ }
462
+
463
+
464
+
465
+ paused = true;
466
+
467
+ pauseTime = Time.time;
468
+
469
+ }
470
+
471
+
472
+
473
+ public void Resume()
474
+
475
+ {
476
+
477
+ // 同じく時刻の狂いを防止するため、移動中には
478
+
479
+ // 開始時刻の更新を行わないようにしました
480
+
481
+ if (!paused)
482
+
483
+ {
484
+
485
+ return;
486
+
487
+ }
488
+
489
+
490
+
491
+ paused = false;
492
+
493
+ startTime += Time.time - pauseTime;
494
+
495
+ }
496
+
497
+
498
+
499
+ IEnumerator TalkWith(Transform targetTransform)
500
+
501
+ {
502
+
503
+ // 念のため目標方向をXZ平面上に投影しておく
504
+
505
+ Vector3 targetDir = Vector3.ProjectOnPlane(targetTransform.position - transform.position, Vector3.up).normalized;
506
+
507
+ Vector3 forward = transform.forward;
508
+
509
+
510
+
511
+ // 一時停止して目標方向へ回転し...
512
+
513
+ Pause();
514
+
515
+ yield return YTurnToTarget(transform, targetDir);
516
+
517
+
518
+
519
+ // コンソールに文章を表示、少し待機する(会話しているつもり)
520
+
521
+ Debug.Log("Hello!");
522
+
523
+ yield return new WaitForSeconds(5.0f);
524
+
525
+
526
+
527
+ // 元の方向へ回転し、一時停止を解除する
528
+
529
+ yield return YTurnToTarget(transform, forward);
530
+
531
+ Resume();
532
+
533
+ }
534
+
535
+
536
+
537
+ // 引数としてターゲットへの方角を受け取ることにする
538
+
539
+ IEnumerator YTurnToTarget(Transform trf, Vector3 targetDir)
540
+
541
+ {
542
+
543
+ Vector3 baseForward = trf.forward;
544
+
545
+
546
+
547
+ // Y軸周りの符号付き回転角を得て...
548
+
549
+ float angle = Vector3.SignedAngle(baseForward, targetDir, Vector3.up);
550
+
551
+ for (float time = 0.0f; time < animationLength; time += Time.deltaTime)
552
+
553
+ {
554
+
555
+ float t = time / animationLength;
556
+
557
+
558
+
559
+ // Lerpの引数としてangleを使う
560
+
561
+ Quaternion q = Quaternion.Euler(0.0f, Mathf.Lerp(0.0f, angle, t), 0.0f);
562
+
563
+ trf.forward = q * baseForward;
564
+
565
+ yield return null;
566
+
567
+ }
568
+
569
+
570
+
571
+ // 補間値t=1の調整処理
572
+
573
+ trf.forward = Quaternion.Euler(0.0f, angle, 0.0f) * baseForward;
574
+
575
+ }
576
+
577
+
578
+
579
+ IEnumerator Turn(Transform trf)
580
+
581
+ {
582
+
583
+ Vector3 baseForward = trf.forward;
584
+
585
+ for (float time = 0.0f; time < animationLength; time += Time.deltaTime)
586
+
587
+ {
588
+
589
+ float t = time / animationLength;
590
+
591
+ Quaternion q = Quaternion.Euler(0.0f, Mathf.Lerp(0.0f, 180.0f, t), 0.0f);
592
+
593
+ trf.forward = q * baseForward;
594
+
595
+ yield return null;
596
+
597
+ }
598
+
599
+
600
+
601
+ trf.forward = Quaternion.Euler(0.0f, 180.0f, 0.0f) * baseForward;
602
+
603
+ Resume();
604
+
605
+ }
606
+
607
+ ```

2

PingPong一時停止案を追記

2021/02/06 15:28

投稿

Bongo
Bongo

スコア10807

test CHANGED
@@ -153,3 +153,177 @@
153
153
  }
154
154
 
155
155
  ```
156
+
157
+
158
+
159
+ ##PingPongの一時停止
160
+
161
+
162
+
163
+ ```C#
164
+
165
+ [SerializeField] private GameObject startPoint;
166
+
167
+ [SerializeField] private GameObject endPoint;
168
+
169
+ [SerializeField] private float animationLength = 1.0f;
170
+
171
+
172
+
173
+ float startTime;
174
+
175
+ float pauseTime;
176
+
177
+ bool paused;
178
+
179
+ float speed = 2;
180
+
181
+ Vector3 dir;
182
+
183
+ Vector3 startPosition;
184
+
185
+ float distance;
186
+
187
+ int directionSign;
188
+
189
+
190
+
191
+ public void Pause()
192
+
193
+ {
194
+
195
+ // 一時停止フラグを立て、現在の時刻を記録する
196
+
197
+ paused = true;
198
+
199
+ pauseTime = Time.time;
200
+
201
+ }
202
+
203
+
204
+
205
+ public void Resume()
206
+
207
+ {
208
+
209
+ // 移動再開時に、停止していた時間をstartTimeに加算する
210
+
211
+ paused = false;
212
+
213
+ startTime += Time.time - pauseTime;
214
+
215
+ }
216
+
217
+
218
+
219
+ void Start()
220
+
221
+ {
222
+
223
+ startTime = Time.time;
224
+
225
+ startPosition = startPoint.transform.position;
226
+
227
+ Vector3 endPosition = endPoint.transform.position;
228
+
229
+ startPosition.y = 0.0f;
230
+
231
+ endPosition.y = 0.0f;
232
+
233
+ dir = (endPosition - startPosition).normalized;
234
+
235
+ distance = Vector3.Distance(startPosition, endPosition);
236
+
237
+
238
+
239
+ // 進行方向の符号...1で順方向、-1で逆方向
240
+
241
+ // スタート時点の進行方向は順方向としておく
242
+
243
+ directionSign = 1;
244
+
245
+ }
246
+
247
+
248
+
249
+ void Update()
250
+
251
+ {
252
+
253
+ if (paused)
254
+
255
+ {
256
+
257
+ return;
258
+
259
+ }
260
+
261
+
262
+
263
+ float t = (Time.time - startTime) * speed;
264
+
265
+ Vector3 newPosition = startPosition + (dir * Mathf.PingPong(t, distance));
266
+
267
+ transform.position = newPosition;
268
+
269
+
270
+
271
+ int newDirectionSign = (int)Mathf.Sign(distance - Mathf.Repeat(t, distance * 2.0f));
272
+
273
+ if (newDirectionSign != directionSign)
274
+
275
+ {
276
+
277
+ // もし進行方向が反転したら、一時停止して
278
+
279
+ // 進行方向を更新、転回コルーチンを開始する
280
+
281
+ Pause();
282
+
283
+ directionSign = newDirectionSign;
284
+
285
+ StartCoroutine(Turn(transform));
286
+
287
+ return;
288
+
289
+ }
290
+
291
+
292
+
293
+ transform.rotation = Quaternion.LookRotation(dir * newDirectionSign);
294
+
295
+ }
296
+
297
+
298
+
299
+ IEnumerator Turn(Transform trf)
300
+
301
+ {
302
+
303
+ Vector3 baseForward = trf.forward;
304
+
305
+ for (float time = 0.0f; time < animationLength; time += Time.deltaTime)
306
+
307
+ {
308
+
309
+ float t = time / animationLength;
310
+
311
+ Quaternion q = Quaternion.Euler(0.0f, Mathf.Lerp(0.0f, 180.0f, t), 0.0f);
312
+
313
+ trf.forward = q * baseForward;
314
+
315
+ yield return null;
316
+
317
+ }
318
+
319
+ trf.forward = Quaternion.Euler(0.0f, 180.0f, 0.0f) * baseForward;
320
+
321
+
322
+
323
+ // 転回終了後に移動を再開
324
+
325
+ Resume();
326
+
327
+ }
328
+
329
+ ```

1

動きを水平方向へ制限したバージョンを追記

2021/02/02 19:41

投稿

Bongo
Bongo

スコア10807

test CHANGED
@@ -65,3 +65,91 @@
65
65
 
66
66
 
67
67
  `PingPong`の`length`に0以下の値を入れると狂うのは、どうやら確からしいですね。[PingPong](https://github.com/Unity-Technologies/UnityCsReference/blob/61f92bd79ae862c4465d35270f9d1d57befd1761/Runtime/Export/Math/Mathf.cs#L362)、[Repeat](https://github.com/Unity-Technologies/UnityCsReference/blob/61f92bd79ae862c4465d35270f9d1d57befd1761/Runtime/Export/Math/Mathf.cs#L356)、[Clamp](https://github.com/Unity-Technologies/UnityCsReference/blob/61f92bd79ae862c4465d35270f9d1d57befd1761/Runtime/Export/Math/Mathf.cs#L182)の式にマイナスの`length`を代入して手計算してみると確認できるかと思います。
68
+
69
+
70
+
71
+ ## 水平の動きに制限
72
+
73
+
74
+
75
+ ```C#
76
+
77
+ void Start()
78
+
79
+ {
80
+
81
+ startTime = Time.time;
82
+
83
+ startPosition = startPoint.transform.position;
84
+
85
+ Vector3 endPosition = endPoint.transform.position;
86
+
87
+
88
+
89
+ // 下記のようにすればstartPositionを
90
+
91
+ // 通る水平面上を動くはずです
92
+
93
+ endPosition.y = startPosition.y;
94
+
95
+
96
+
97
+ // あるいは、起点・終点のy成分を0にしてしまえば
98
+
99
+ // 高さを無視してY=0の平面上を移動するでしょう
100
+
101
+ //startPosition.y = 0.0f;
102
+
103
+ //endPosition.y = 0.0f;
104
+
105
+
106
+
107
+ dir = (endPosition - startPosition).normalized;
108
+
109
+ distance = Vector3.Distance(startPosition, endPosition);
110
+
111
+ }
112
+
113
+
114
+
115
+ void Update()
116
+
117
+ {
118
+
119
+ float t = (Time.time - startTime) * speed;
120
+
121
+ Vector3 newPosition = startPosition + (dir * Mathf.PingPong(t, distance));
122
+
123
+
124
+
125
+ // さまざまな高さの建物がある地形とのことですが、それらの高さを無視して
126
+
127
+ // 貫通して動くのではなく、建物の屋上に乗っているように見せたい場合は
128
+
129
+ // Raycastも併用して位置を修正する必要があるかと思います
130
+
131
+ // 「移動オブジェクトのY軸座標は変化させずに」とのことですので、
132
+
133
+ // そういうことをしたいのではないだろうとは思うのですが...
134
+
135
+ /*
136
+
137
+ if (Physics.Raycast(new Ray(new Vector3(newPosition.x, 100.0f, newPosition.z), Vector3.down), out var hitInfo))
138
+
139
+ {
140
+
141
+ newPosition = hitInfo.point;
142
+
143
+ }
144
+
145
+ */
146
+
147
+
148
+
149
+ transform.position = newPosition;
150
+
151
+ transform.rotation = Quaternion.LookRotation(dir * Mathf.Sign(this.distance - Mathf.Repeat(t, distance * 2.0f)));
152
+
153
+ }
154
+
155
+ ```