【Unity】同じコンポーネントが複数アタッチされるのを防ぐ方法

【Unity】同じコンポーネントが複数アタッチされるのを防ぐ方法

今回もAttribute祭り。

ゲームオブジェクトにはコンポーネントをアタッチすることができますが、コンポーネントの中には「複数アタッチされると困るなー」というものもあります。

自分でスクリプトを作った時にいくつもインスタンスがあると困るケースなど、複数のコンポーネントをアタッチできないようにしたい時に便利なのが、[DisallowMultipleComponent]のAttributeです。

これを付けておくと、そのスクリプトは1つのゲームオブジェクトに複数アタッチすることができなくなります。

 

環境

macOS 10.13 High Sierra

Unity2018.1.0f2

DisallowMultipleComponentとは

DisallowMultipleComponentはスクリプトに記述するAttribute(属性)のひとつで、同じゲームオブジェクトに、このAttributeがついたスクリプトを複数アタッチできないようにします。

直訳すると、「許可しない」「複数の」「コンポーネント」となります。そのまんまですね。

例えばManager系のクラスだと、複数のコンポーネントが動いているとめっちゃ都合が悪いしバグの元です。なので、機械的にアタッチできないようにしておけば安心です。

Unityのスクリプトリファレンスの『DisallowMultipleComponent』では説明文だけでサンプルコードが無いため、ここでサンプルコードを紹介。

複数アタッチしてみる

まずは[DisallowMultipleComponent]を記述しないで、以下のスクリプトをゲームオブジェクトに複数アタッチします。

同じコンポーネントを複数アタッチ
同じコンポーネントを複数アタッチ

 

5つアタッチしてみました。この状態でゲームを実行してみると……。

だ、誰が本物なんだー(棒)
だ、誰が本物なんだー(棒)

 

今回のケースだとコンソールへの出力だけで済んでいますが、これがもしManager系のクラスで、シーンのロードなんかしていた日には、5つもシーンが読み込まれることに……。

そんな事故は未然に防いでおかねばならないので、[DisallowMultipleComponent]を記述しておきましょう。

記述する場所はクラス名の前です。

このスクリプトをInspectorウィンドウから追加でアタッチしてみます。

追加でアタッチしようとすると……
追加でアタッチしようとすると……

 

ダイアログが出てアタッチできない
ダイアログが出てアタッチできない

 

ちゃんとダイアログで『Invalid Operation.』と警告してくれます。Managerが二重にシーンを読み込むなんて悲劇はなかったんや……(1敗)

なお、すでに複数アタッチされている状態だと、スクリプトに[DisallowMultipleComponent]を書いても複数アタッチされたままなので注意。あくまでスクリプトに書いた後、コンポーネントをアタッチする時に有効なようです。

 

Copy Componentでも防ぐ

コンポーネントの右上にある歯車アイコンの中に、[Copy Component]の項目があります。

これを使ってコンポーネントのコピペをしても防いでくれるかな?

コピーしてみる
コピーしてみる

 

ペーストしてみる
ペーストしてみる

 

ででーん
ででーん

 

コンポーネントのコピペではダイアログが出ず、コンソールにエラーが出力されました。結果的に複数のアタッチはできていないので問題なさそう。

スクリプトからAddComponent

Inspectorウィンドウからだと、複数コンポーネントのアタッチはできませんでした。念のためスクリプトからもできないことを確認します。

今回使っている『MultipleComponentTest』のスクリプトを以下のように編集します。もし複数アタッチが可能なら、追加されるたびにStart()が呼び出されて無限にコンポーネントが増えていく恐ろしい仕様です。

Ifの世界線だとこうなります。

if ([DisallowMultipleComponent]が無い){大惨事}
if ([DisallowMultipleComponent]が無い){大惨事;}

[DisallowMultipleComponent]が付いていると、どうなるかなー。

この[DisallowMultipleComponent]で複数のアタッチはふせぐぞ!
この[DisallowMultipleComponent]で複数のアタッチはふせぐぞ!

ちゃんと複数アタッチを防いでくれました。コンポーネントのコピペのケースと警告の種類が違うのは……何でしょうね?

おまけ

RigidbodyやMesh Filterなどは複数アタッチできないのですが、この時のメッセージが[DisallowMultipleComponent]のケースと違っていました。

ちょっと違う
ちょっと違う

 

複数アタッチさせないという目的はどちらも達成しているので気にするほどのことでもないのかも。

まとめ

同じスクリプトやコンポーネントを同じゲームオブジェクトにアタッチさせたくない時には、[DisallowMultipleComponent]を使っておくと安心です。

ただ、同一のゲームオブジェクトでしか防いでくれないので、複数のゲームオブジェクトに跨って防ぐことはできません。

シーン内で絶対に1インスタンスしか作りたくない! という時には、自力でシングルトンになるようにした方が良さげかも。

アセット作ってます!

CTA-IMAGE

Unityでの開発に役立つアセットを作っています。

3DダンジョンRPGを開発するスピードを200%加速するAssetや、ファンタジーRPGのダンジョンを彩るパーツを取り揃えています。

特に3DダンジョンRPGのゲームを1から作るのは結構時間がかかります。ダンジョン部分の作成はこうしたアセットを使って、開発をブーストさせてみませんか?