回答編集履歴

2

targetRotation方式のコードを追記

2020/11/10 20:00

投稿

Bongo
Bongo

スコア10807

test CHANGED
@@ -457,3 +457,93 @@
457
457
 
458
458
 
459
459
  ![図4](14e1c62496ddfaaac22760ca7167f76a.gif)
460
+
461
+
462
+
463
+ ##追記: targetRotationによるカプセル操作
464
+
465
+
466
+
467
+ ```C#
468
+
469
+ using UnityEngine;
470
+
471
+
472
+
473
+ [RequireComponent(typeof(ConfigurableJoint))]
474
+
475
+ public class CapsuleController3 : MonoBehaviour
476
+
477
+ {
478
+
479
+ [SerializeField] private float angularSpeedInDegrees = 120.0f;
480
+
481
+ [SerializeField] private float spring = 500.0f;
482
+
483
+ [SerializeField] private float damper = 100.0f;
484
+
485
+ [SerializeField] private float angularLimitInDegrees = 60.0f;
486
+
487
+
488
+
489
+ private ConfigurableJoint configurableJoint;
490
+
491
+ private float angle;
492
+
493
+
494
+
495
+ private void Start()
496
+
497
+ {
498
+
499
+ this.configurableJoint = this.GetComponent<ConfigurableJoint>();
500
+
501
+ this.configurableJoint.xMotion = ConfigurableJointMotion.Locked;
502
+
503
+ this.configurableJoint.yMotion = ConfigurableJointMotion.Locked;
504
+
505
+ this.configurableJoint.zMotion = ConfigurableJointMotion.Locked;
506
+
507
+ this.configurableJoint.angularXMotion = ConfigurableJointMotion.Free;
508
+
509
+ this.configurableJoint.angularYMotion = ConfigurableJointMotion.Locked;
510
+
511
+ this.configurableJoint.angularZMotion = ConfigurableJointMotion.Locked;
512
+
513
+ this.configurableJoint.angularXDrive = new JointDrive
514
+
515
+ {
516
+
517
+ maximumForce = float.MaxValue,
518
+
519
+ positionSpring = this.spring,
520
+
521
+ positionDamper = this.damper
522
+
523
+ };
524
+
525
+ }
526
+
527
+
528
+
529
+ private void Update()
530
+
531
+ {
532
+
533
+ var input = Input.GetAxis("Vertical");
534
+
535
+ this.angle = Mathf.Clamp(
536
+
537
+ this.angle + (this.angularSpeedInDegrees * Time.deltaTime * input),
538
+
539
+ -this.angularLimitInDegrees,
540
+
541
+ this.angularLimitInDegrees);
542
+
543
+ this.configurableJoint.targetRotation = Quaternion.Euler(this.angle, 0.0f, 0.0f);
544
+
545
+ }
546
+
547
+ }
548
+
549
+ ```

1

ヘビ型ロボット製作を想定した案を追記

2020/11/10 20:00

投稿

Bongo
Bongo

スコア10807

test CHANGED
@@ -185,3 +185,275 @@
185
185
 
186
186
 
187
187
  ![図](07a9cafa79ba71e319c09cc24500b3f4.gif)
188
+
189
+
190
+
191
+ ##追記
192
+
193
+
194
+
195
+ 根拠のない直感なんですが、ヘビ型ロボットのようなものを作る布石ということを念頭に置くと、個々の体節が駆動する仕組みはなるべくシンプルにしておいた方がいいような予感がします。
196
+
197
+ 駆動方法についても、個人的には当初の`AddRelativeTorque`による方法は「オレンジカプセルを指でつまんでひねる」といったイメージ...つまりヘビ本体の動力ではなく、外部からの力で回転しているような感じがしました。それよりもジョイント部分に仕込まれたモーターで回転させるイメージの方がしっくりくる気がするのですが、いかがでしょうかね?
198
+
199
+
200
+
201
+ オレンジカプセルのスクリプトを下記のようにしてみました。本質的なのは`Update`と`FixedUpdate`で、`Start`内ではジョイントのパラメーターを設定しているだけです。
202
+
203
+ ここで設定しなくてもジョイントのインスペクター上に直接入力すればいいのですが、やたら設定項目が多くてどれをいじったか忘れてしまいそうになりこのようにしました。
204
+
205
+
206
+
207
+ ```C#
208
+
209
+ using UnityEngine;
210
+
211
+
212
+
213
+ [RequireComponent(typeof(ConfigurableJoint))]
214
+
215
+ public class CapsuleController2 : MonoBehaviour
216
+
217
+ {
218
+
219
+ [SerializeField] private float angularSpeedInDegrees = 120.0f;
220
+
221
+ [SerializeField] private float damper = 100.0f;
222
+
223
+ [SerializeField] private float angularLimitInDegrees = 60.0f;
224
+
225
+
226
+
227
+ private ConfigurableJoint configurableJoint;
228
+
229
+ private float input;
230
+
231
+
232
+
233
+ private void Start()
234
+
235
+ {
236
+
237
+ this.configurableJoint = this.GetComponent<ConfigurableJoint>();
238
+
239
+ this.configurableJoint.xMotion = ConfigurableJointMotion.Locked;
240
+
241
+ this.configurableJoint.yMotion = ConfigurableJointMotion.Locked;
242
+
243
+ this.configurableJoint.zMotion = ConfigurableJointMotion.Locked;
244
+
245
+ this.configurableJoint.angularXMotion = ConfigurableJointMotion.Limited;
246
+
247
+ this.configurableJoint.angularYMotion = ConfigurableJointMotion.Locked;
248
+
249
+ this.configurableJoint.angularZMotion = ConfigurableJointMotion.Locked;
250
+
251
+ this.configurableJoint.highAngularXLimit = new SoftJointLimit
252
+
253
+ {
254
+
255
+ limit = this.angularLimitInDegrees
256
+
257
+ };
258
+
259
+ this.configurableJoint.lowAngularXLimit = new SoftJointLimit
260
+
261
+ {
262
+
263
+ limit = -this.angularLimitInDegrees
264
+
265
+ };
266
+
267
+ this.configurableJoint.angularXDrive = new JointDrive
268
+
269
+ {
270
+
271
+ maximumForce = float.MaxValue,
272
+
273
+ positionSpring = 0.0f,
274
+
275
+ positionDamper = this.damper
276
+
277
+ };
278
+
279
+ }
280
+
281
+
282
+
283
+ private void Update()
284
+
285
+ {
286
+
287
+ this.input = Input.GetAxis("Vertical");
288
+
289
+ }
290
+
291
+
292
+
293
+ private void FixedUpdate()
294
+
295
+ {
296
+
297
+ this.configurableJoint.targetAngularVelocity = new Vector3(
298
+
299
+ this.input * this.angularSpeedInDegrees * Mathf.Deg2Rad,
300
+
301
+ 0.0f,
302
+
303
+ 0.0f);
304
+
305
+ }
306
+
307
+ }
308
+
309
+ ```
310
+
311
+
312
+
313
+ また、両カプセルのコライダーは`BoxCollider`に差し替えました。丸いカプセルではなく角柱にすることで、地面の上に落ちた後ふとしたはずみにコケてしまうのを防ごうという魂胆です。Freeze Rotation Yをオンにすることも考えたのですが、力の解決の結果すごく大きな力がかかることがあるようで、たまに空高く吹っ飛んでしまうことがありました。
314
+
315
+
316
+
317
+ ![図1](7f4f748617575b3ea105b94006c15b73.png)
318
+
319
+
320
+
321
+ 他にも、青カプセルとオレンジカプセルを親子関係にするのはやめました。親子関係になっていると、青カプセルが移動・回転した時に子オブジェクトであるオレンジカプセルも移動・回転してしまうことになります。経験上、物理シミュレーションの制御下にあるオブジェクトの位置や姿勢をダイレクトに操作するとろくなことにならないと思っておりまして、このようなオレンジカプセルの移動・回転もそれと同様の性質を持つだろうと考えてのことです。
322
+
323
+
324
+
325
+ 動かしてみると下図のようになりました。コメント欄で申し上げたたとえ話の、スカイダイビングをする人のような挙動になっています。
326
+
327
+
328
+
329
+ ![図2](2b61fc49470de896366802aa90894d6b.gif)
330
+
331
+
332
+
333
+ また、このようなコンセプトで駆動する体節を鎖状に繋げるとどんな挙動をするだろうかと気になりまして、下図のようにオブジェクトをセットアップしてみました。Headが青カプセル、Segment1~9がオレンジカプセルで、Segment1~9は`ConfigurableJoint`を持っており、Segment1はHeadに、Segment2はSegment1に...といった具合に鎖状につながっています。
334
+
335
+ コライダーはHeadだけ`CapsuleCollider`、他は`BoxCollider`としました。
336
+
337
+
338
+
339
+ ![図3](53b25d295260402d6ecbbca6dcee219a.png)
340
+
341
+
342
+
343
+ HeadとSegment1~8はスクリプトを持っておらず、Segment9にだけ下記のようなスクリプトをアタッチしました。
344
+
345
+ `CapsuleController2`は`targetAngularVelocity`を使ってモーターの速度を設定する方式なのに対し、こちらは`targetRotation`を使って目標角度を与える方式になっているという差異はありますが、セグメント間のジョイントが動力になっているという点は同様です。
346
+
347
+
348
+
349
+ ```C#
350
+
351
+ using System.Collections.Generic;
352
+
353
+ using UnityEngine;
354
+
355
+
356
+
357
+ [RequireComponent(typeof(ConfigurableJoint))]
358
+
359
+ public class WormController : MonoBehaviour
360
+
361
+ {
362
+
363
+ [SerializeField] private float omegaInDegrees = 90.0f;
364
+
365
+ [SerializeField] private float timeOffset = 0.5f;
366
+
367
+ [SerializeField] private float spring = 500.0f;
368
+
369
+ [SerializeField] private float damper = 100.0f;
370
+
371
+ [SerializeField] private float angularLimitInDegrees = 60.0f;
372
+
373
+
374
+
375
+ private readonly List<ConfigurableJoint> joints = new List<ConfigurableJoint>();
376
+
377
+ private float time;
378
+
379
+
380
+
381
+ private void Start()
382
+
383
+ {
384
+
385
+ var j = this.GetComponent<ConfigurableJoint>();
386
+
387
+ do
388
+
389
+ {
390
+
391
+ j.xMotion = ConfigurableJointMotion.Locked;
392
+
393
+ j.yMotion = ConfigurableJointMotion.Locked;
394
+
395
+ j.zMotion = ConfigurableJointMotion.Locked;
396
+
397
+ j.angularXMotion = ConfigurableJointMotion.Free;
398
+
399
+ j.angularYMotion = ConfigurableJointMotion.Locked;
400
+
401
+ j.angularZMotion = ConfigurableJointMotion.Locked;
402
+
403
+ j.angularXDrive = new JointDrive
404
+
405
+ {
406
+
407
+ maximumForce = float.MaxValue,
408
+
409
+ positionSpring = this.spring,
410
+
411
+ positionDamper = this.damper
412
+
413
+ };
414
+
415
+ this.joints.Add(j);
416
+
417
+ j = j.connectedBody.GetComponent<ConfigurableJoint>();
418
+
419
+ } while (j != null);
420
+
421
+ }
422
+
423
+
424
+
425
+ private void FixedUpdate()
426
+
427
+ {
428
+
429
+ for (var i = 0; i < this.joints.Count; i++)
430
+
431
+ {
432
+
433
+ var j = this.joints[i];
434
+
435
+ var t = Mathf.Max(this.time - (i * this.timeOffset), 0.0f);
436
+
437
+ var angle = this.angularLimitInDegrees * Mathf.Sin(t * this.omegaInDegrees * Mathf.Deg2Rad);
438
+
439
+ j.targetRotation = Quaternion.Euler(angle, 0.0f, 0.0f);
440
+
441
+ }
442
+
443
+
444
+
445
+ this.time += Time.deltaTime;
446
+
447
+ }
448
+
449
+ }
450
+
451
+ ```
452
+
453
+
454
+
455
+ 実行してみると、おぞましい化け物のような動きをしました...
456
+
457
+
458
+
459
+ ![図4](14e1c62496ddfaaac22760ca7167f76a.gif)