🎄teratailクリスマスプレゼントキャンペーン2024🎄』開催中!

\teratail特別グッズやAmazonギフトカード最大2,000円分が当たる!/

詳細はこちら
C#

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

Unity

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

Q&A

解決済

1回答

5702閲覧

Unityであるオブジェクトが引き寄せられてもう一つの物体に吸い付くようなギミックを作るにはどうすれば良いのか

ytDu9QHRgvzgNlB

総合スコア15

C#

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

Unity

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

0グッド

0クリップ

投稿2020/01/04 09:27

現在取り組んでいること

私は、Unityで3Dの世界でx,yの2軸だけを使ったボールゲームを作っています。現在、ギミックの一つとして以下の画像のようなアイデアがありそれを実装してみたいと思っています。![イメージ説明

これは、ボールがあるエリア内に入ると上の天井のところにあるオブジェクトが引き寄せられてくっつくという仕組みです。

わからないこと/教えていただきたいこと

Unityでこのギミックを実装するためには磁力で考えていくのか、それとも引力で考えていくのかということがわかりません。また、物理があまり得意ではないためこのような考え方以外にももう少し簡単に実装できるような方法があれば教えていただきたいです。

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

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

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

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

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

guest

回答1

0

ベストアンサー

ひきつけたいオブジェクトにタグをつけて、GameObject.FindGameObjectsWithTagで全部取得してしまってから、Rigidbody2D.AddForceでひきつけるオブジェクトの方向へ距離の2乗に反比例した力を掛けるコードを書けばいいと思います。具体的にはこんな感じでしょうか。

public class Attractor: MonoBehaviour { public float forceFactor = 1f; List<Rigidbody2D> objectBodies = new List<Rigidbody2D>(); void Start() { foreach(var obj in GameObject.FindGameObjectsWithTag("attracted")) { var rb = obj.GetComponent<Rigidbody>(); if (rb == null) { continue; } objectBodies.Add(rb); } } void Update() { foreach(var rb in objectBodies) { rb.AddForce(GetForce(rb.transform.position)); } } Vector2 GetForce(Vector2 pos) { float dist = Vector2.Distance(transform.position, pos); Vector2 dir = (transform.position - pos).normalized; return dir / (dist * dist) * forceFactor; } }

ボールなのでこういう簡易的なコードでも大丈夫なのですが、これが長方形だったりすると少し変な挙動になるので、GetForce関数を書き換える必要があります。

投稿2020/01/04 10:43

編集2020/01/04 10:44
frodo821

総合スコア322

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

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

ytDu9QHRgvzgNlB

2020/01/05 02:07

ありがとうございます。まだ、foreach文を勉強したことが無かったのでその勉強と並行しつつやってみたいと思います。
ytDu9QHRgvzgNlB

2020/01/05 07:35

すいません。質問なんですが、自分が作っているゲームは3D設定で行っているんですけどこの場合もRigidbody2DやVector2などを使ってもよろしいのですか?
frodo821

2020/01/05 08:14 編集

あー。そうなんですね。それなら全部3Dのものに置き換えちゃってください。(ぶっちゃけこのシチュエーションならVector2でも動きますが、Rigidbody2DだけはRigidbodyに必ず置き換えてください) 置き換えなくてもいい理由は、Vector2とVector3が相互に暗黙キャスト可能だからですね。あんまりいい書き方でもないと思うのですが、特段の問題はありません。
ytDu9QHRgvzgNlB

2020/01/05 09:19

このスクリプトはボールにアタッチするんでしょうか?それとも、引き付けられる側の方ですか?
frodo821

2020/01/05 09:27

ボールです。引き付けられる方にはRigidbodyとタグ(この場合はattracted)を設定してください。
ytDu9QHRgvzgNlB

2020/01/06 00:01

返信遅れてすいません。了解です。 丁寧に教えてくださりありがとうございます
ytDu9QHRgvzgNlB

2020/01/07 03:51

度々すいません。教えてもらったスクリプトをボールにアタッチしたところ、周りのattractorというタグをつけた物体は引き寄せられることには成功したのですがくっつくという事をせず体当たりのような形になってしまいました。くっくつという動作をさせる場合どのようなスクリプトにすればよいのでしょうか?
frodo821

2020/01/07 04:10

あ、もしかして反発係数とか設定していますか? もし、引き寄せたオブジェクトに別にPhysicsMaterialを設定しても構わないのであれば、Bouncinessを0、Bounce CombineをMinimumに設定したPhysicsMaterialを設定してみてください。
ytDu9QHRgvzgNlB

2020/01/08 02:16

返信遅れてすいません。反発係数は設定してないです。 PhysicsMaterialを設定してやってみたんですけど、動きがくっつくというよりはボールに当たるとそこで加速されているのかわからないんですけど、ものすごい勢いをもって飛ばされていくという感じでした。
frodo821

2020/01/08 02:25

ふむ……。なら、当たったらRigidbody.velocityを0にするようにしてみましょうか。 void OnCollisionEnter(Collision col) { if (col.gameObject.tag != "attracted") { return; } var target = objectBodies.Find(x => x.gameObject == col.gameObject); if (target == null) { return; } target.velocity = Vector3.zero; } この関数をAttractorクラスに追記してみてください。
ytDu9QHRgvzgNlB

2020/01/08 02:35

ありがとうございます。やってみます!
ytDu9QHRgvzgNlB

2020/01/08 06:09

頂いたスクリプト通りやったらいい感じの動きができました。ありがとうございます。 あと、引き付けるという動作をさせるためにスクリプトで以下のように書かれていたと思います。 dir / (dist * dist) * forceFactor; ここで、少し疑問に思ったのがなぜ、距離の二乗で割ると引力のような力が実現できるんでしょうか? 度々の質問申し訳ございません。
frodo821

2020/01/08 06:17

まず、点Aから点Bに向かう方向ベクトルは、位置ベクトルをそれぞれa, bとすると、b - aで求まります。 そのベクトルを求めて、正規化(ベクトルの長さを1にする操作)してしているのがその前の行の Vector3 dir = (transform.position - pos).normalized; というところです。 ところで、磁力のような空間に広がる力は、距離の逆2乗(-2乗)に比例します。そこで、この方向ベクトルを距離の2乗で割っている訳です。 forceFactorは引き寄せる強さを決める定数ですので、どのような値でも構いませんが、この場合は1fとしています。
ytDu9QHRgvzgNlB

2020/01/09 02:44

毎回返信が遅くなり申し訳ございません。丁寧なご説明ありがとうございます。正規化する理由として任意の大きさにするためという理解であっていますでしょうか? また、空間に広がる力が距離の逆二乗に比例しているという事は知らなかったので、なぜ逆二乗に比例するのかという事を知っていきたいなと思いました。
frodo821

2020/01/09 02:52

力がある1点から出る線だというふうに考えると分かりやすいと思います。 球の面積は半径の2乗に比例しますが、力の線の密度はその面積に反比例します。 力の強さ=力の線の密度ですので、力は距離の2乗に反比例します。 正規化は、大きさと向きを別々に計算するために行っています。一緒に計算するのであれば、距離の3乗で割っても同じ結果になります。
ytDu9QHRgvzgNlB

2020/01/09 03:02

ありがとうございます! とても分かりやすい説明で理解しやすかったです。多くの自分の質問に答えていただき本当にありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.36%

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

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

質問する

関連した質問