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

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

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

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

Q&A

解決済

2回答

4804閲覧

OnTriggerEnter2Dで接触判定がたまに無視されてしまう

sukiyakigozens

総合スコア28

C#

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

0グッド

0クリップ

投稿2017/10/29 20:59

編集2017/11/04 02:43

スマホ用のパズルアプリを制作しております初心者です。(Unity5.6使用)
パズルピースをドラッグドロップで、
正解の位置のスロットにはめ込むというゲーム内容です。
(70個程のパズルピースがあります)

OnTriggerEnter2Dで接触判定しております。
パズルピースと正解スロットとの接触があった場合、以下の3つの命令を同時に実行しております。


  1. パズルピースオブジェクトの一部分をDestroy
  2. スロットオブジェクトの添付スクリプトをDestroy
  3. パズルピースオブジェクトの添付スクリプトをDestroy

問題点
たいていの場合、3つの命令は問題なく作動するのですが、
だいたい数十回に1回ほどですが、接触判定後の上記の3つの命令が全て無視されます。

その他の問題の詳細

  •  PC上(MAC)でもスマホ実機上でも起こります
  •  パズルピースが70個のシーンでこの問題が起こり、パズルピースが10個のみのシーンでは起こらないようです。
  •  パズルピースのRigidbodyの「Sleeping Mode」を「Start Awake」にしても「Never Sleep」にしても起こります

無視された場合は、パズルピースをもう一度ドラッグし直して、
再び同じ位置のスロットにはめ直しをすると、3つの命令は実行されます。


対策(やってみた事)
接触判定が無視されてしまう事に対しての対策として、
FixedUpdate内にも、接触判定時と同様の上記の3つのの命令を入れました。
(もし削除希望のオブジェクトが残っていた場合に、実行されるように設定しました。)
※常時FixedUpdate内で判定を連続するとメモリ消費が大きいと思われるので、
フラグがtrueの時のみに判定を実行されるようにしております。
(ドラッグ終了時点でフラグをtrue、0.3秒後にフラッグをfalseと設定))

その結果、FixedUpdate内の命令が効いているようで、
接触判定が無視されることはなくなったようです。
(それによりRigitbody2DのSleeping ModeをStart Asleepにしました
「Start Asleep」がもっともメモリ消費が少ないと思われるので)


質問
2重に(OnTriggerEnter2DとFixedUpdate)で同じDestroyの命令を実行することに
不安を感じております。この方法はやはりおかしいでしょうか?
(ログを確認すると先にFixedUpdate内の命令が実行されているようで、
実際には、FixedUpdateのみが効いていて、OnTriggerEnter2Dの命令は効いてないと思われます)

何か別の方法はありませんでしょうか?
UpdateおよびFixedUpdateは遅く、メモリ消費も心配なので、できればUpdate、FixedUpdateを使用せずに
OnTriggerEnter2Dで確実に命令が実行される方法はないでしょうか?

すいませんが、ご教授よろしくおねがいいたします。


追記(やってみた事2)
「OnTriggerEnter2D」を「OnTriggerStay2D」に変更し、FixedUpdateの命令をやめてみましたが、
それでもまだ、ごくたまに上記1〜3の命令が、無視はされなくなったようですが、
命令実行のタイミングが若干遅れる事があります。

※さらに「FixedUpdateで上記1~3の命令を実行する場合」と、
「OnTriggerStay2Dで実行する場合」を比較すると「OnTriggerStay2D」の方が
多くメモリ消費しています。(大幅な差はありませんが)
(常時命令が呼び出されないように両方の方法ともに、フラグで命令の実行時間を制限しております)

※Rigidbody2Dの「Collision Detection」は「Continous」、
「Sleeping mode」は「Never sleep」に設定しております。

再度考えましたが、
シンプルなドラッグドロップのパズルゲームで、
静止してるスロットにパズルピースをドラッグして重ねるだけなので、
理論的には「OnTriggerStay2D」ではなく
最初に「OnTriggerEnter2D」で重なった瞬間のみ判定するほうが、
正しいような気がしております。

どうにか「OnTriggerEnter2D」で確実に命令を実行させる方法なないものでしょうか?
ご教授よろしくおねがいいたします。

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

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

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

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

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

guest

回答2

0

OnTriggerEnter2Dが発動しない原因

OnTriggerEnter2D内にDebug.Logを置いても表示されないことが確認出来ている場合、
「そもそも衝突が発生していない」ことになります。

この原因としては下記ページにある
UnityのCollision Detectionでとんでもなくつまづいた - こまけぇこたぁいんだよ
Collision Detectionの設定によるもの。

もしくは
Post Position 【Unity】 静止した物体同士の当たり判定の検出について
における「Rigidbodyが付いている方のオブジェクトが移動もしくは回転している(静止しているとダメ)」というパターンが考えられます。

FixedUpdateは使用すべきではない

質問主さんの仰る通り、FixedUpdateは頻繁に呼ばれる為(条件分岐を挟んでいたとしても)使用は最小限にすべきです。
上記ColliderとRigidbodyの設定で直らない場合は、「OnTriggerEnter2D+FixedUpdate」を「OnTriggerStay2D(=接触している間呼ばれ続ける)」にするとシンプルになるかと思います。

こちらもフラグ判定は必要になりますので、以下のようにするとよいかと思います。
(Destroyは即時行われない場合があるので判定には使用していません)

C#

1private bool isCollision; 2void OnTriggerStay2D(Collider2D other) { 3 if (!isCollision) { 4 isCollision = true; 5 //Destroy処理 6 } 7} 8

投稿2017/10/30 03:17

sakura_hana

総合スコア11427

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

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

sukiyakigozens

2017/10/30 04:03

ご説明ありがとうございます。 1つめの 「Collision Detection」は現状ですでに「Continous」になっておりました。 2つめの 「Rigidbodyが付いている方のオブジェクト」=「パズルピース」になるのですが、 ドラッグで移動して、スロット(静止してます)の上に重ねるので、 移動している最中に接触しております。 移動はしていて、回転はしていない状態です。 ですので上記2つには該当しないと思われます。 元は「OnTriggerStay」を使用しておりましたが、少し前に「OnTriggerEnter」に変えておりました。 理由は「OnTriggerStay」の方が、呼び出し回数が多いので、 メモリ消費を心配して接触した瞬間だけ呼び出される、 「OnTriggerEnter」に変えておりました。 しかしながら判定が無視されるという問題が出てきてしまい、 さらに、やはりFixedUpdateは使うべきではないとなると、 もう一度「OnTriggerStay」に戻して 調整を考えたいと思います。 ありがとうございました。
sakura_hana

2017/10/30 04:19

OnTriggerStayとFixedUpdateについて、同じスクリプト上であれば秒間あたりの呼び出し回数は同じという認識でいました。 FixedUpdateは触れていない間も呼ばれることを考えると、OnTriggerStayの方がいいという判断でした。 が、改めて考えると、ピースが多くて目的のオブジェクト以外でも衝突していてOnTriggerStayも呼ばれっぱなしになっているような場合は、ManagerクラスのFixedUpdateで管理したりする方がスマートかもしれません。 (既に設定済みかもしれませんが、もしピース同士、スロット同士の衝突が必要無いなら、衝突レイヤーの設定でオフにすると多少改善するかもしれません。 https://docs.unity3d.com/jp/current/Manual/LayerBasedCollision.html)
sukiyakigozens

2017/10/30 04:53

ご指摘ありがとうございます。 当方の制作中のゲームはシンプルなパズルゲームですので、 動くものは、ドラッグできる「パズルピース」だけで、 あとは何も動きませんし、衝突もありません。 やはりフラグで判定時間を限定しながら「OnTriggerStay」を使用するのが いいかと思います。 レイヤーの設定はしておりませんでした。確認してみます。 ありがとうございました。
sukiyakigozens

2017/10/30 12:29

「OnTriggerStay2D」に変更し「FixedUpdate内の命令を削除」してみましたが、 まだ確実に命令が実行されるようにはできないようです。 (上記の「追記」に記しました。) (命令が実行されるのですが、ごくたまに命令実行が若干遅れる事があります)
sakura_hana

2017/11/01 01:26

「OnTriggerStay内の実行が若干遅れる」ということは、やはり何らかの理由で物理演算処理が遅延していると考えられます。 衝突判定はピースとスロットの2つしか存在しないということですが、ドラッグしたタイミングでRigidbodyやColliderを有効化しているような形でしょうか? もしそうならその処理と関連して物理判定有効化までの遅延が発生している可能性も考えられます。 (とは言えOnTriggerEnterを飛ばしてOnTriggerStayが呼ばれるというのは疑問ですが……) 話をひっくり返して申し訳無いですが、どうしても無理ならFixedUpdateでもいいと思います。 (メモリ消費量を気にするなら、少し操作感に差が出るかもしれませんがUpdate内でRayCastを使って「タッチしている場所がピースとスロット両方と重なったら」という処理とも比較してみるといいかもしれません。どちらが負荷が低いかは要検証ですが……)
sukiyakigozens

2017/11/03 11:35

ご返答ありがとうございます。 解決しました。上記に(自己解決)記しました。 いろいろご説明いただき大変ありがとうございました。 感謝しております。
guest

0

自己解決

追記 / 自己解決しました
あくまで当方の予測ですが、70個のパズルピースがあるという事により、
Unityの処理が追いつかない部分があり、そのせいで命令が無視されるのではないか、と思われます。
(パズルピースが10個ほどのシーンではこの問題は起こっておりません。)

解決方法
OnTriggerEnter2D使用で、
コライダーの形を「BoxCollider2D」から**「CircleCollider2D」**に変えました。
理由は、いくつかのサイトで「CircleCollider2D」の方が、最もシンプルな処理で、
「BoxCollider2D」より処理が早いとの記述があった為です。

さらに、スロット側、パズルピース側の
両方のコライダーの判定範囲の半径を共に最小数値の**「0.0001」**に変えました。
(この数値が大きくなると上記の判定無視が起こってしまいます。)

※ Rigidbody2D「Collision Detection」は**「Continous」、「Discrete」両方共に動作します。
※ Rigidbody2D「Sleeping Mode」は
「Never Sleep」**に設定しております。
※ 上記のFixedUpdate内での衝突判定の処理は削除しました。

何度も設定を変えて実験しましたが、
70個のパスルピースがあるという、この私の状況では、
上記の設定でなければ、うまく作動しない模様です。

閲覧いただき、ありがとうございました。

投稿2017/11/03 11:33

編集2017/11/06 09:40
sukiyakigozens

総合スコア28

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問