質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

Q&A

解決済

1回答

1940閲覧

Unityでゲーム内の物理的負荷をトリガーにしたい

yuu1111main

総合スコア6

C#

C#はマルチパラダイムプログラミング言語の1つで、命令形・宣言型・関数型・ジェネリック型・コンポーネント指向・オブジェクティブ指向のプログラミング開発すべてに対応しています。

Unity3D

Unity3Dは、ゲームや対話式の3Dアプリケーション、トレーニングシュミレーション、そして医学的・建築学的な技術を可視化する、商業用の開発プラットフォームです。

Unity

Unityは、Unity Technologiesが開発・販売している、IDEを内蔵するゲームエンジンです。主にC#を用いたプログラミングでコンテンツの開発が可能です。

0グッド

1クリップ

投稿2017/11/26 03:49

###前提・実現したいこと
Unityでクレーンゲームのシュミレーターを作成しています。
アームユニットを下降させる際にrigidbody(Is Kinematic)を用いているのですが、
アームユニットが物体に衝突しても、トリガーを設定していないのでそのまま下降していき非現実的な挙動となってしまいます。(y座標の最低高度は指定してあります。)

現実のクレーンゲームだと紐を巻き取ったりして制御しているそうです。(負荷がかかると紐がたるんで下降がストップする)

どのようなアルゴリズムを用いれば良いでしょうか?
まだプログラムに関するリテラシーが浅いので質問させていただきました。
###試したこと
_★_ 
◯◯◯
◯◆◯
◯_◯
◯◯◯

★がトリガー(Is trigger)
◯がrigidbody(Use Gravity)を適用した物体(繋がっています)
◆がユニット

上記で◯が★に接触した場合に下降を停止するようにしていますが、ほかの方法の方が良いのではという勘です。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

sakura_hana

2017/11/27 05:13

現状はどうなっていて(トリガーを設定していないのか?停止するようにしているのか?)、どのような問題を懸念しているのか(または問題が発生しているのか)、質問内から読み取れません。ヒエラルキーツリーやスクリプトを提示して説明してください。
guest

回答1

0

ベストアンサー

申し訳ないです、せっかく図で説明していただきましたが、いまいち状況が把握しきれず、勝手な解釈での回答です(クレーンが景品に下降していく際、何も対策しないとクレーンが景品の山にめり込んでいってしまうので、個々の景品の上面にクレーン停止用トリガー領域を設置する方法をとったが、これ以外に案はないだろうか...ということでしょうか?)。

トリガー方式も悪くないと思うのですが、違ったアプローチもご所望でしたら、一案としてクレーンをキネマティックなRigidbodyと非キネマティックなRigidbodyを組み合わせた構造にして、両者をFixedJointなど適当なジョイントで繋ぎ、そのジョイントのcurrentForceを監視して負荷のかかり方を検出する...というのを思いつきましたが、いかがでしょう。

クレーンが空中にあるときは、非キネマティック部分にかかる重力によってジョイントに下向きの負荷がかかるが、景品の上に非キネマティック部分が乗っかると、景品からの抗力で下方向の負荷が消失するはず...という目論見で実験してみました。

下図のような構造のクレーンを作って、

クレーン

クレーンに下記スクリプトをアタッチしました。

C#

1using System.Collections; 2using System.Linq; 3using UnityEngine; 4 5public class Crane : MonoBehaviour 6{ 7 public Transform armTransform; // アームのTransform...アームはキネマティックとし、Transformを操作して移動させる 8 public Joint LoadDetectorJoint; // アームと円盤(非キネマティック)を繋ぐジョイント...ここにかかる負荷を見てアームの衝突を検知する(今回はFixedJointを使用しました) 9 public HingeJoint[] ClawHinges; // クローと円盤を繋ぐヒンジ...Use Springをオンにし、適当なSpring(大きいほど握力が強まる)を設定しておく 10 11 private bool playing; 12 private float homePosition; 13 14 private void Start() 15 { 16 this.homePosition = armTransform.position.y; // アームを上げるとき、この高さまで戻す 17 } 18 19 private void Update() 20 { 21 if (!this.playing && Input.GetKeyDown(KeyCode.Space)) 22 { 23 this.StartCoroutine(this.StartGame()); // スペースキー押下で一連のモーションを開始 24 } 25 } 26 27 private IEnumerator StartGame() 28 { 29 this.playing = true; 30 31 Debug.Log("Start!"); 32 33 yield return this.StartCoroutine(this.MoveClawsMotion(60.0f)); // クローを開く 34 yield return new WaitForSeconds(1.0f); // 少し待機 35 yield return this.StartCoroutine(this.MoveDownMotion()); // アームを下げる 36 yield return new WaitForSeconds(1.0f); // 少し待機 37 yield return this.StartCoroutine(this.MoveClawsMotion(0.0f)); // クローを閉じる 38 yield return new WaitForSeconds(1.0f); // 少し待機 39 yield return this.StartCoroutine(this.MoveUpMotion()); // アームを上げる 40 yield return new WaitForSeconds(1.0f); // 少し待機 41 yield return this.StartCoroutine(this.MoveClawsMotion(60.0f)); // クローを開く 42 yield return new WaitForSeconds(1.0f); // 少し待機 43 yield return this.StartCoroutine(this.MoveClawsMotion(0.0f)); // クローを閉じる 44 45 this.playing = false; 46 } 47 48 private IEnumerator MoveDownMotion() 49 { 50 const int loadMovingAverageLength = 30; // 負荷を積算するフレーム数(試しに「1」などとしてみると、アーム降下開始時の加速によって負荷が消失し、すぐにアームが止まってしまうと思います) 51 const float loadThreshold = 0.0f; // アームを停止する負荷値 52 const float acceleration = 0.5f; // アームの下降加速度 53 const float velocityMax = 1.0f; // アームの最大下降速度 54 55 var loads = Enumerable.Repeat<float>(this.LoadDetectorJoint.currentForce.y, loadMovingAverageLength).ToArray(); 56 var loadSum = loads.Sum(); 57 var loadIndex = 0; 58 59 var velocity = 0.0f; 60 61 while (true) 62 { 63 var previousLoad = loads[loadIndex]; 64 var newLoad = this.LoadDetectorJoint.currentForce.y; // currentForceのY成分を負荷の指標とする 65 66 loadSum += (newLoad - previousLoad); 67 68 var averageLoad = loadSum / loadMovingAverageLength; // 過去loadMovingAverageLengthフレーム分の負荷を平均して、それで停止するべきか判定する 69 70 Debug.LogFormat("Load:{0}", averageLoad); 71 72 if (averageLoad >= loadThreshold) 73 { 74 Debug.Log("Stop!"); 75 break; 76 } 77 78 velocity = Mathf.Max(velocity - acceleration * Time.deltaTime, -velocityMax); 79 this.armTransform.Translate(0.0f, velocity * Time.deltaTime, 0.0f, Space.World); 80 loadIndex = (loadIndex + 1) % loadMovingAverageLength; 81 82 yield return null; 83 } 84 } 85 86 private IEnumerator MoveUpMotion() 87 { 88 const float acceleration = 0.5f; // アームの上昇加速度 89 const float velocityMax = 1.0f; // アームの最大上昇速度 90 91 var velocity = 0.0f; 92 93 while (this.armTransform.position.y < this.homePosition) 94 { 95 velocity = Mathf.Min(velocity + acceleration * Time.deltaTime, velocityMax); 96 this.armTransform.Translate(0.0f, velocity * Time.deltaTime, 0.0f, Space.World); 97 98 yield return null; 99 } 100 101 this.armTransform.position = new Vector3(0.0f, this.homePosition, 0.0f); 102 } 103 104 private IEnumerator MoveClawsMotion(float angle, float timeout = 3.0f) 105 { 106 const float angularSpeed = 30.0f; // 毎秒30°で開閉 107 108 var time = 0.0f; 109 110 while (time < timeout) // 景品を掴もうとしているときなど、クローに負荷がかかっているといつまで経っても目標角に到達できない場合があるので、一定時間が経過したら強制的にモーションを終了 111 { 112 var reached = true; 113 var angleDeltaMax = angularSpeed * Time.deltaTime; 114 115 foreach (var clawHinge in this.ClawHinges) 116 { 117 var spring = clawHinge.spring; 118 119 spring.targetPosition = Mathf.MoveTowardsAngle(spring.targetPosition, angle, angleDeltaMax); 120 clawHinge.spring = spring; 121 reached &= Mathf.Approximately(spring.targetPosition, angle); 122 } 123 124 if (reached) 125 { 126 break; // すべてのクローが目標角に到達したらモーションを終了 127 } 128 129 time += Time.deltaTime; 130 131 yield return null; 132 } 133 } 134} 135

円盤が景品に乗っかっている状態以外でも、アームの加速時など一時的に負荷がなくなる場合があるので、一定フレームの間の平均の負荷でアーム停止の判定をしています。

アームの下降に伴う負荷の変化は下図のようになりました(あくまでも一例で、クレーンの各部位や景品の質量設定などの要因でクレーンの挙動は変わってくると思います)。

負荷の変化

[追記]
補足として、今回はcurrentForceのyをそのまま使っていますが、ジョイントでRigidbody同士を接続した場合、currentForceは接続相手の座標系に従うみたいですので、今回のように重力の負荷を調べる場合は、適宜ワールド座標系に直す必要があるかもしれません。

投稿2017/11/27 22:30

編集2017/11/28 00:01
Bongo

総合スコア10807

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

yuu1111main

2017/12/01 11:25

ものすごく丁寧な回答ありがとうございます。 currentForceは考えたこともありませんでした! 参考にさせていただきます。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問