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

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

新規登録して質問してみよう
ただいま回答率
85.50%
Unity

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

Q&A

解決済

1回答

2658閲覧

UnityでPolygonCollider2Dを付け直しせず再設定したい

yrema

総合スコア286

Unity

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

0グッド

3クリップ

投稿2018/10/23 23:46

スプライトが動的に変わるGameObjectがあり、polygonCollider2DをAddComponentしています。
スプライトが変わるごとにPolygonCollider2DをGetComponentしDestroyし、またAddComponentするという付け直しをしています。
これを付け直しすることなくコライダー領域を再生成することはできないでしょうか?
https://docs.unity3d.com/ja/2017.4/ScriptReference/PolygonCollider2D.html
これを見る限り、それっぽいメソッドは見当たりませんでした。

◆環境
Unity2017 3.1f1

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

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

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

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

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

guest

回答1

0

ベストアンサー

おっしゃる通りそれらしいメソッドはなさそうですね。
コライダーの再アタッチを使わない方法として、Refreshing the Polygon Collider (2D) upon sprite change? - Unity AnswersのLCStarkさんの案を参考に、スプライトが変化するGameObjectにこのようなスクリプトをアタッチし...

C#

1using System.Collections.Generic; 2using UnityEngine; 3 4[RequireComponent(typeof(PolygonCollider2D))] 5public class PolygonCollider2DUpdater : MonoBehaviour 6{ 7 private static readonly Dictionary<Sprite, Vector2[][]> PathsForSprite = new Dictionary<Sprite, Vector2[][]>(); 8 private PolygonCollider2D polygonCollider; 9 10 // このゲームオブジェクトのスプライトを変更した場合、併せてこのメソッドを実行するようにする 11 public void UpdateColliderShape(Sprite sprite) 12 { 13 if (sprite == null) 14 { 15 return; 16 } 17 18 if (!PathsForSprite.ContainsKey(sprite)) 19 { 20 // spriteに対応するパスが未キャッシュなら、スプライトから物理形状を取得し 21 // PathsForSpriteに保存しておく 22 var shapeCount = sprite.GetPhysicsShapeCount(); 23 var newPaths = new Vector2[shapeCount][]; 24 var shape = new List<Vector2>(); 25 for (var i = 0; i < shapeCount; i++) 26 { 27 sprite.GetPhysicsShape(i, shape); 28 var path = shape.ToArray(); 29 newPaths[i] = path; 30 } 31 32 PathsForSprite.Add(sprite, newPaths); 33 } 34 35 // spriteと対応するパスをPathsForSpriteから取り出し、コライダーにセットする 36 var paths = PathsForSprite[sprite]; 37 var pathCount = paths.Length; 38 for (var i = 0; i < pathCount; i++) 39 { 40 this.polygonCollider.SetPath(i, paths[i]); 41 } 42 } 43 44 // 比較用のコライダー破壊・再アタッチ方式での実装 45 /* 46 public void UpdateColliderShape(Sprite sprite) 47 { 48 Destroy(this.polygonCollider); 49 this.polygonCollider = this.gameObject.AddComponent<PolygonCollider2D>(); 50 }*/ 51 52 private void Awake() 53 { 54 this.polygonCollider = this.GetComponent<PolygonCollider2D>(); 55 } 56}

スプライトを変更した際には、下記のようにUpdateColliderShapeを実行してみました。

C#

1 this.spriteRenderer.sprite = sprite; 2 this.polygonCollider2DUpdater.UpdateColliderShape(sprite);

ですが、ちょっと動かしてみた限りでは性能面に大きな違いはなさそうでした。

SetPath方式で毎フレームスプライト差し替え
SetPath

コライダー破壊・再アタッチ方式で毎フレームスプライト差し替え
Destroy

差し替え時の「GC Allocated」はSetPath方式の方が若干小さく、結果として「Total GC Allocated」のノコギリ形グラフはSetPath方式の方が周期が長くなりましたが、コライダー破壊方式がSetPath方式に対して極端に劣るようなことはなさそうです。

コライダー破壊方式はコライダーのインスタンスが差し替わってしまうため、色々なスクリプトからコライダーを参照している場合はそれらをすべて新しいインスタンスに参照を更新してやる必要があるでしょうから、そのような場合はインスタンスが置き換わらないSetPath方式を使う利点がありそうです。
ですが、コライダー破壊方式の方がコードがシンプルですので、上記のような条件でなければコライダー破壊方式でも問題ないかと思います。

その他、試していないのですが、Santosh_Nairさんの紹介されているUnity 4.3 2D Tutorial: Physics and Screen Sizes | raywenderlich.com記事内の「スプライトと対応するPolygon Collider 2Dをいくつもアタッチし、現在レンダラーにセットされているスプライトに応じてコライダーのenabledを切り替える」という方式もありそうです。
スプライトの種類が少ない場合はいいかもしれませんが、切り替え候補のスプライトが多数ある場合はオブジェクトに大量のコライダーがアタッチされることになるでしょうから、インスペクタは見づらくなりそうです。パフォーマンスについては実験してみないと予想しにくいですね。大量のコライダーがあるとはいえ、アクティブなのは常に一つだけですので、案外パフォーマンス上の不利は小さいかもしれません。

投稿2018/10/27 08:43

Bongo

総合スコア10807

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

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

yrema

2018/10/27 21:45

検証ありがとうございます。「案外パフォーマンス上の不利は小さいかもしれません。」最後のこの言葉が最大の結果と思われます。ありがとうございました。
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.50%

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

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

質問する

関連した質問