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

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

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

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

Unity3D

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

Unity

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

Q&A

1回答

6885閲覧

unityでクレーンゲームを作っているのですが・・・

binoyazyu

総合スコア6

C#

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

Unity3D

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

Unity

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

0グッド

1クリップ

投稿2018/11/11 16:13

編集2018/11/13 09:33

こんにちは。
unityで3Dのクレーンゲームを個人開発しようと思うのですが
どういった方法で動作させればいいのかわかりません。
とりあえず筐体を左右に移動はできました。が、

アームを開ける→筐体を下げる→アームを閉じる→筐体を上げる→初期位置まで戻りアームを開く

上記の動作をどういった方法で実現できますでしょうか。
初心者なのでわからないことだらけですが教えていただけると助かります。

C#で動かすべきなのでしょうか?
はたまたアニメーションで動かすべきなのでしょうか…?

イメージ説明

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

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

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

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

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

guest

回答1

0

一案としましては、去年の話ですがC# - Unityでゲーム内の物理的負荷をトリガーにしたい|teratailのご質問に案を投稿した際には、一連の動きを表現するのに入れ子のコルーチンを使ってみました。
投稿したコードでは、ご要望を実現しようと試行錯誤した結果クローをアームにジョイントで繋いで開閉していますが、クローもKinematicにしてしまいMoveRotationで回転させる方が制御が簡単かもしれません。

#追記
水平位置を元に戻すには、Craneがアタッチされたオブジェクトを元の位置に戻してやればよさそうですね。
Craneスクリプトに水平移動モーションを追加してみました。元々のコメントは削除し、今回変更があった部分にのみコメントを加えています。

C#

1using System.Collections; 2using System.Linq; 3using UnityEngine; 4 5public class Crane : MonoBehaviour 6{ 7 public Transform armTransform; 8 public Joint LoadDetectorJoint; 9 public HingeJoint[] ClawHinges; 10 11 private bool playing; 12 private float homePositionY; // フィールド名をhomePositionYに変更 13 private Vector2 homePositionXZ; // 水平位置用のフィールドを追加 14 15 private void Start() 16 { 17 this.homePositionY = armTransform.position.y; // フィールド名をhomePositionYに変更 18 this.homePositionXZ = new Vector2(this.transform.position.x, this.transform.position.z); // アーム上昇後、水平位置をここへ移動する 19 } 20 21 private void Update() 22 { 23 if (!this.playing && Input.GetKeyDown(KeyCode.Space)) 24 { 25 this.StartCoroutine(this.StartGame()); 26 } 27 } 28 29 private IEnumerator StartGame() 30 { 31 this.playing = true; 32 33 Debug.Log("Start!"); 34 35 yield return this.StartCoroutine(this.MoveClawsMotion(60.0f)); 36 yield return new WaitForSeconds(1.0f); 37 yield return this.StartCoroutine(this.MoveDownMotion()); 38 yield return new WaitForSeconds(1.0f); 39 yield return this.StartCoroutine(this.MoveClawsMotion(0.0f)); 40 yield return new WaitForSeconds(1.0f); 41 yield return this.StartCoroutine(this.MoveUpMotion()); 42 yield return new WaitForSeconds(1.0f); 43 yield return this.StartCoroutine(this.ReturnHomeMotion()); // 水平位置を元に戻す 44 yield return new WaitForSeconds(1.0f); // 少し待機 45 yield return this.StartCoroutine(this.MoveClawsMotion(60.0f)); 46 yield return new WaitForSeconds(1.0f); 47 yield return this.StartCoroutine(this.MoveClawsMotion(0.0f)); 48 49 this.playing = false; 50 } 51 52 private IEnumerator MoveDownMotion() 53 { 54 const int loadMovingAverageLength = 30; 55 const float loadThreshold = 0.0f; 56 const float acceleration = 0.5f; 57 const float velocityMax = 1.0f; 58 59 var loads = Enumerable.Repeat<float>(this.LoadDetectorJoint.currentForce.y, loadMovingAverageLength).ToArray(); 60 var loadSum = loads.Sum(); 61 var loadIndex = 0; 62 63 var velocity = 0.0f; 64 65 while (true) 66 { 67 var previousLoad = loads[loadIndex]; 68 var newLoad = this.LoadDetectorJoint.currentForce.y; 69 70 loadSum += (newLoad - previousLoad); 71 72 var averageLoad = loadSum / loadMovingAverageLength; 73 74 Debug.LogFormat("Load:{0}", averageLoad); 75 76 if (averageLoad >= loadThreshold) 77 { 78 Debug.Log("Stop!"); 79 break; 80 } 81 82 velocity = Mathf.Max(velocity - acceleration * Time.deltaTime, -velocityMax); 83 this.armTransform.Translate(0.0f, velocity * Time.deltaTime, 0.0f, Space.World); 84 loadIndex = (loadIndex + 1) % loadMovingAverageLength; 85 86 yield return null; 87 } 88 } 89 90 private IEnumerator MoveUpMotion() 91 { 92 const float acceleration = 0.5f; 93 const float velocityMax = 1.0f; 94 95 var velocity = 0.0f; 96 97 while (this.armTransform.position.y < this.homePositionY) // フィールド名をhomePositionYに変更 98 { 99 velocity = Mathf.Min(velocity + acceleration * Time.deltaTime, velocityMax); 100 this.armTransform.Translate(0.0f, velocity * Time.deltaTime, 0.0f, Space.World); 101 102 yield return null; 103 } 104 105 // コメントで申し上げたように、アームのX、Zを0にしてしまわないように変更しました 106 var armPosition = this.armTransform.position; 107 armPosition.y = this.homePositionY; // フィールド名をhomePositionYに変更 108 this.armTransform.position = armPosition; 109 } 110 111 // 元の位置に戻すためのモーションを追加 112 // クレーンゲームらしくしようと思い、景品を持ち上げた位置から一直線に戻るのではなく、XとZを独立して動かしています 113 private IEnumerator ReturnHomeMotion() 114 { 115 const float acceleration = 0.5f; // X軸またはZ軸の移動加速度 116 const float velocityMax = 1.0f; // X軸またはZ軸の最大移動速度 117 118 var velocity = 0.0f; 119 var position = new Vector2(this.transform.position.x, this.transform.position.z); // 現在の水平位置 120 121 // ホームポジションへの向きの符号を求める...移動方向のコントロールに使う 122 var sign = this.homePositionXZ - position; 123 sign.x = Mathf.Sign(sign.x); 124 sign.y = Mathf.Sign(sign.y); 125 126 while (true) 127 { 128 // ホームポジションへの相対位置を求め、十分近づいたら移動を終える 129 var left = this.homePositionXZ - position; 130 if (Mathf.Approximately(left.sqrMagnitude, 0.0f)) 131 { 132 break; 133 } 134 135 velocity = Mathf.Min(velocity + acceleration * Time.deltaTime, velocityMax); 136 var delta = velocity * Time.deltaTime; // XまたはZ方向の、このフレームでの移動量 137 var nextPosition = position + sign * delta; // このフレームでの移動先 138 139 // 目標地点を越えないように座標をクランプしてから、そこへ移動 140 position.x = sign.x > 0.0f ? Mathf.Min(nextPosition.x, this.homePositionXZ.x) : Mathf.Max(nextPosition.x, this.homePositionXZ.x); 141 position.y = sign.y > 0.0f ? Mathf.Min(nextPosition.y, this.homePositionXZ.y) : Mathf.Max(nextPosition.y, this.homePositionXZ.y); 142 this.transform.position = new Vector3(position.x, this.homePositionY, position.y); 143 144 yield return null; 145 } 146 147 this.transform.position = new Vector3(this.homePositionXZ.x, this.homePositionY, this.homePositionXZ.y); 148 } 149 150 private IEnumerator MoveClawsMotion(float angle, float timeout = 3.0f) 151 { 152 const float angularSpeed = 30.0f; 153 154 var time = 0.0f; 155 156 while (time < timeout) 157 { 158 var reached = true; 159 var angleDeltaMax = angularSpeed * Time.deltaTime; 160 161 foreach (var clawHinge in this.ClawHinges) 162 { 163 var spring = clawHinge.spring; 164 165 spring.targetPosition = Mathf.MoveTowardsAngle(spring.targetPosition, angle, angleDeltaMax); 166 clawHinge.spring = spring; 167 reached &= Mathf.Approximately(spring.targetPosition, angle); 168 } 169 170 if (reached) 171 { 172 break; 173 } 174 175 time += Time.deltaTime; 176 177 yield return null; 178 } 179 } 180}

投稿2018/11/11 21:59

編集2018/11/17 00:38
Bongo

総合スコア10811

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

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

binoyazyu

2018/11/12 07:37

回答していただきありがとうございます。 クローは2本なのですがその場合はどのように対応したらよいのでしょうか。 まだまだ未熟でわからないことだらけなので教えていただけると助かります。
Bongo

2018/11/12 10:25

リンク先の回答に書きましたクローを動かす機構は、あくまでも一例に過ぎませんので、適した方法はご質問者さんがどのようにクレーンを作ったかによって変わってくるかと思います。 実際のところ、あの回答のコードはクローの本数に依存しないよう作ったつもりでして、インスペクタ上の「Claw Hinges」の「Size」を変えれば2本でも3本でも対応可能なはずで、どのようなアドバイスを付け加えるべきか悩ましいです... これ以上のアドバイスとなりますと、ご質問者さんのクレーンの設計をより詳しくご説明いただきたいところです。 現状ではこのようにクレーンを作った、クレーンのこの部分にはこういうスクリプトをアタッチしている...といった情報を追記いただけますとありがたいです。
binoyazyu

2018/11/12 14:10 編集

回答ありがとうございます。 助言助かりました。クローの本数に関する問題は解決しました。 さらなる問題が起きているので画像をとりあえず追加しました。 ほぼ他のスクリプトはアタッチしていません。 今は試験的な感じでUFOキャッチャーを作っているのでとりあえず動けばそれでよし、という状態です。 なにか追加してほしい情報ありましたらコメントお願いします。 手伝ってもらってすみません:; 本当に助かります。
Bongo

2018/11/13 00:43 編集

図を見た感じですと、まず左右クローのヒンジジョイントの蝶番軸(クローを選択した時に表示される、小さなオレンジ色の矢印)の向きが違っているようです。 左右に開閉したいので、おそらく「claw right」は(0, 0, 1)、「claw left」は(0, 0, -1)だろうと予想されますが、とりあえず「Axis」を色々な向きにしてみて正しい向きに開閉するかチェックしてみてください。 また、アームを下に動かした時に、クローが上方にフワッと回転してしまっていることから想像すると、ジョイントの力が足りないのかもしれません。 「Use Spring」の下の「Spring」項目の左の三角をクリックして展開すると、その下にさらに「Spring」という項目が現れるかと思いますが、これを数千~数万に上げて試してみてはいかがでしょう。 もしバネのようにビョンビョンと動いて困るようでしたら、さらに「Spring」の下の「Damper」も上げてみてください。「Spring」が目標角度へ引きつける力であるのに対して、「Damper」はそれを妨げる向きに働く抵抗力です。これを上げるとバネ運動の減衰が早くなり、弾みにくい重いバネになるかと思います。
binoyazyu

2018/11/13 09:32

こんにちは。解決策をありがとうございます! おかげさまで解決することができました。 また問題が発生しているのですが、もし解決策をご存知でしたらご教授していただきますと助かります。 問題:クレーンが上がり終えた瞬間に高速で{X 0} {Z 0}の座標まで飛ばされてしまいます。 スクリプトの設定でしたら申し訳ないです:; ※GIFを追加しておきました。
Bongo

2018/11/13 20:16

なるほど、私の書いたコードの中で心当たりがありますね... あれを作った際には、クレーンの水平移動は重要な問題ではなかったため省略し、初期位置からの上下移動だけしか考慮していませんでした。 MoveUpMotionの一番最後に、 this.armTransform.position = new Vector3(0.0f, this.homePosition, 0.0f); とありますが、ここでYをホームポジションに戻すのと同時に、XとZも0に戻してしまっています。 ここを、 var armPosition = this.armTransform.position; armPosition.y = this.homePosition; this.armTransform.position = armPosition; に変更するとどうなるでしょうか? また念のため申し上げますと、あのコードの一連のモーションでは、アームの上昇が終わった後はクローを開くモーションへ進んでしまいますので、「アームを上げる」「少し待機」の後、「クローを開く」の前に、水平位置を初期位置まで移動させるモーションを加えてやる必要があるかと思います。
binoyazyu

2018/11/14 15:05

なるほど…了解しました。 水平移動をするためにどのようなモーションが必要となるのでしょうか。
Bongo

2018/11/14 21:43

念のため、最初にクレーンを左右に移動させる部分のコードをご提示いただけますでしょうか? 最初の左右移動と矛盾しないように水平移動しないと正しく元の位置に戻らないかもしれない、という点が気になってしまいまして...
binoyazyu

2018/11/15 08:32

了解です。 これが右(X軸)です ↓ using UnityEngine; using System.Collections; public class right : MonoBehaviour { bool rightmove; // Use this for initialization void Start() { } // Update is called once per frame void Update() { if (rightmove == true) { transform.position += new Vector3(1 * Time.deltaTime, 0, 0); } } public void rightButtonDown() { rightmove = true; } public void rightButtonUp() { rightmove = false; } } これが縦(Z軸) ↓ using UnityEngine; using System.Collections; public class forward : MonoBehaviour { bool forwardmove; // Use this for initialization void Start() { } // Update is called once per frame void Update() { if (forwardmove == true) { transform.position += new Vector3(0, 0, 1 * Time.deltaTime); } } public void forwardButtonDown() { forwardmove = true; } public void forwardButtonUp() { forwardmove = false; } }
binoyazyu

2018/11/15 08:34

buttonのEventTriggerで呼び出しています。 他に必要な情報がありましたらコメントお願いします。
Bongo

2018/11/15 20:01

たびたびすみません、これらright、forwardスクリプトはどのオブジェクトにアタッチされているでしょうか? 以前ご提示いただいた図では、たしか「Crane」という名前のキューブにCraneスクリプトがアタッチされていたかと思いますが、rightとforwardもこのオブジェクトでしょうか?それともアーム部分...「hontai」の方にアタッチされているでしょうか。
binoyazyu

2018/11/16 09:33

情報不足ですみません。Craneのほうにアタッチしました。
Bongo

2018/11/17 00:40

水平移動モーションについて追記しました。ご提示いただいたことから判断しますと、おそらくこれで水平位置が戻るかとは思いますが...
binoyazyu

2018/11/17 02:06

こんなに丁寧に対応していただき感謝の気持ちでいっぱいです! 無事動作することができました。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

まだベストアンサーが選ばれていません

会員登録して回答してみよう

アカウントをお持ちの方は

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問