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

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

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

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

Q&A

解決済

1回答

2687閲覧

Unity2D プレイヤーにオブジェクトを動かせなくする

kome-kit

総合スコア11

C#

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

0グッド

1クリップ

投稿2018/07/15 13:53

編集2018/07/17 15:08

2Dアクションゲームを作っています
Rigidbody2dとcoliderを持った重力の影響を受けず動くオブジェクト(ブロック)が複数と
同じくRigidbody2dとcoliderを持った重力の影響を受け動かせるオブジェクト(プレイヤー)があるとして次の状況が作りたいです
・ブロック同士は物理的に干渉しあう。
・プレイヤーはブロックを一切動かせない。
・ブロックはプレイヤーの足場や壁になる。

何かいい方法は無いでしょうか

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

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

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

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

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

sakura_hana

2018/07/17 01:17

「ぶつかられたブロックが動かずブロックが移動してブロックにぶつかったときはぶつかられたブロックも動くようにしたいです」の意味が分かりません。また、今「ぶつかった時に移動するスクリプト」は書いていますか? 書いているなら質問内に記載し、書いていないならまずはそれを調べてみてください。(ざっくりヒントを出すと「OnCollision〜系スクリプトを片方に付ける→"相手が〜なら動かす"という条件分岐を加える」で出来ると思います)
kome-kit

2018/07/17 09:35 編集

我ながら意味が分からない文章になってますね…すいません…
kome-kit

2018/07/17 09:36 編集

かなり修正してみましたがどうでしょうか。 ぶつかったときの移動はUnityの物理演算で行おうと思っています。
guest

回答1

0

ベストアンサー

プレイヤーとブロックの質量差を十分大きくするというのはどうでしょうか?
例えば下図の場合、プレイヤーの質量が約0.5kgなのに対し、オレンジ色のブロックは500~1000kgにしてみました。これぐらい差があると、プレイヤーがブロックに飛び乗ってもブロックの動きにはほとんど影響を及ぼさないかと思います。

プレビュー

ただし、ブロックが重いので、動いているブロックはかなり大きい運動量を持っていることになります。反発係数を調整したり、あるいはプレイヤーの速度に上限を設けるなど対策を施さないと、ブロックがゆっくりぶつかっただけなのにプレイヤーが遠くまで吹っ飛ばされる...なんてことになるかもしれません。

追記

ブロックへの干渉をなくす手はないか検討してみたのですが、ちょっと無理やり感のある方法になってしまいました...
概要としては、FixedUpdate内で...

...ブロックがプレイヤーの存在を無視した動きで移動・回転する。

  • 全ブロックのbodyTypeをダイナミックからスタティックに切り替える。

...ブロックを空間内に固定してしまう。なお、その結果ブロックの速度・角速度が失われてしまうので、後で復元するためにこれらを覚えておく。

  • プレイヤーのsimulatedをtrueに戻して、物理状態を1ステップ進める。

...このとき、プレイヤーにとってブロックは壁と同様の静的物体に見える。触れることができるが、押しても上に乗っても動かない。

  • 全ブロックをスタティックからダイナミックに戻す。

...ここで先ほど覚えておいた速度・角速度をRigidbody2Dに書き戻し、次回のFixedUpdateに備える。

といったような案です。先に述べたプレイヤーとブロックの質量差を大きくする方法と比べると、1回のFixedUpdateの中で2回もシミュレーションを実行させたり、スタティック・ダイナミックをころころ切り替えたり...と、シミュレーションエンジンには少々優しくない気はしますが、オブジェクトが多すぎなければなんとかなりそうでした。

下記のようなスクリプトを空のゲームオブジェクトにアタッチしてシーンに置き、

C#

1using System.Linq; 2using UnityEngine; 3 4public class BlockVersusPlayerPhysicsController : MonoBehaviour 5{ 6 // Rigidbody2Dと、その速度・角速度をペアで覚えておくための型 7 private class Rigidbody2DData 8 { 9 public float angularVelocity; 10 public Rigidbody2D rigidbody2D; 11 public Vector3 velocity; 12 } 13 14 private Rigidbody2DData[] blocks; 15 private Rigidbody2D[] players; 16 17 private void Start() 18 { 19 // シーン上のアクティブなブロック、プレイヤーを取得しておく 20 // さしあたりブロックやプレイヤーは増減しないと仮定して、Startで1回だけ取得していますが 21 // これらが新たに出現・消滅する場合は、その際にblocks・playersにも追加・削除して 22 // 配列を実際のシーン上のオブジェクトを反映するよう更新してやる必要があるでしょう 23 // また、私の場合ではブロックを別スクリプトのStart内で生成しているので、 24 // このスクリプトの実行はそれよりも後になるよう実行順を調整しています 25 var activeRigidbodies = FindObjectsOfType<Rigidbody2D>(); 26 var blockLayer = LayerMask.NameToLayer("Block"); 27 this.blocks = activeRigidbodies 28 .Where(r => r.gameObject.layer == blockLayer) 29 .Select( 30 r => new Rigidbody2DData 31 { 32 rigidbody2D = r, 33 angularVelocity = r.angularVelocity, 34 velocity = r.velocity 35 }) 36 .ToArray(); 37 var playerLayer = LayerMask.NameToLayer("Player"); 38 this.players = activeRigidbodies 39 .Where(r => r.gameObject.layer == playerLayer) 40 .ToArray(); 41 42 // Physics2Dの自動シミュレーションは切っておき、挙動はFixedUpdate内でコントロールする 43 Physics2D.autoSimulation = false; 44 } 45 46 private void FixedUpdate() 47 { 48 // プレイヤー側のシミュレーションを停止 49 foreach (var player in this.players) 50 { 51 player.simulated = false; 52 } 53 54 // シミュレーションを1ステップ進める 55 Physics2D.Simulate(Time.fixedDeltaTime); 56 57 // 全ブロックの現在の速度・角速度を保存してから、スタティックに変更 58 foreach (var block in this.blocks) 59 { 60 block.angularVelocity = block.rigidbody2D.angularVelocity; 61 block.velocity = block.rigidbody2D.velocity; 62 block.rigidbody2D.bodyType = RigidbodyType2D.Static; 63 } 64 65 // プレイヤー側のシミュレーションを再開 66 foreach (var player in this.players) 67 { 68 player.simulated = true; 69 } 70 71 // シミュレーションを1ステップ進める 72 Physics2D.Simulate(Time.fixedDeltaTime); 73 74 // 全ブロックをダイナミックに戻し、保存しておいた速度・角速度を復元 75 foreach (var block in this.blocks) 76 { 77 block.rigidbody2D.bodyType = RigidbodyType2D.Dynamic; 78 block.rigidbody2D.angularVelocity = block.angularVelocity; 79 block.rigidbody2D.velocity = block.velocity; 80 } 81 } 82}

動かした様子はこうなりました。前回と異なりブロックの質量はプレイヤーと同程度の0.5~1kgなのですが、プレイヤーがブロックに飛び乗ってもブロックの動きに干渉しなくなりました。

プレビュー

投稿2018/07/20 22:29

編集2018/07/22 03:36
Bongo

総合スコア10807

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

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

kome-kit

2018/07/21 09:44

回答ありがとうございます 試しにやってみた所結構いい感じではあったのですがどうやってもほんの少し影響が出ますね… 完全に影響0というわけにはいかないでしょうか
kome-kit

2018/07/30 23:48

遅くなってすいません ちゃんと干渉しなくていい感じですね! 少し重いですがなんとか合わせてみます
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.49%

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

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

質問する

関連した質問