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

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

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

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

Unity

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

Q&A

解決済

2回答

1419閲覧

【Unity】Assetsの下にあるC#スクリプトをInspectorからpublic変数として取得できますか?

hokuto37

総合スコア14

C#

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

Unity

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

0グッド

0クリップ

投稿2021/06/30 01:02

前提・実現したいこと

例えばprefabファイルは public GameObject としてInspectorから取得できますが、同様にC#のスクリプトもInspectorから取得したいです。
用途としては取得したスクリプトのTypeを取得して、そのTypeのスクリプトがシーン中のオブジェクトにアタッチされていたら無効にしたいです。

C#スクリプトがシーン中のGameObjectにアタッチされている場合は、Public MonoBehaviour などで取得できると思いますが、シーン中には存在しないAssetsの下にあるスクリプトも取得したいです。
良い方法をご存じの方は教えてください。

試したこと

public MonoBehaviour ではAssetsの下のC#スクリプトをInspectorの変数へドラッグ&ドロップしようとしても設定することは出来ませんでした。
public UnityEngine.Object ならば可能でしたが、それではC#スクリプトのTypeが取得できません。

補足情報(FW/ツールのバージョンなど)

Unity 2018.4.19f1

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

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

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

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

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

guest

回答2

0

ベストアンサー

十分に動作確認したわけではないのですが、MonoScript型を使ってみてはいかがでしょうか?
これはGetClassなんてメソッドを持っており、スクリプトファイルから対応するスクリプトコンポーネントの型を取得できそうです。

lang

1using System; 2using System.Linq; 3using UnityEngine; 4 5#if UNITY_EDITOR 6using UnityEditor; 7#endif 8 9public class ComponentDisabler : MonoBehaviour 10{ 11 #if UNITY_EDITOR 12 public MonoScript script; 13 14 private void Update() 15 { 16 if (Input.GetKeyDown(KeyCode.Space) && (this.script != null)) 17 { 18 this.DisableAllComponents(this.script.GetClass()); 19 } 20 } 21 22 private void DisableAllComponents(Type componentType) 23 { 24 if (componentType == null) 25 { 26 return; 27 } 28 29 // コンポーネントが「enabled」という名前の設定可能なパブリックboolプロパティを持っているか調べる 30 var enabledProperty = componentType.GetProperty("enabled"); 31 var propertyIsValid = (enabledProperty != null) && enabledProperty.CanWrite && (enabledProperty.PropertyType == typeof(bool)); 32 33 // コンポーネントが「enabled」という名前のreadonlyでないパブリックboolフィールドを持っているか調べる 34 var enabledField = componentType.GetField("enabled"); 35 var fieldIsValid = (enabledField != null) && !enabledField.IsInitOnly && (enabledField.FieldType == typeof(bool)); 36 37 // 適切なプロパティ、または適切なフィールドを持っていなければ処理を中断する 38 if (!propertyIsValid && !fieldIsValid) 39 { 40 return; 41 } 42 43 // enabledをfalseにする処理を記述する 44 var disableComponent = propertyIsValid 45 ? target => { enabledProperty.SetValue(target, false); } 46 : (Action<Component>)(target => { enabledField.SetValue(target, false); }); 47 48 // 現在ロードされているコンポーネントの中で、いずれかのシーン上に存在する(アセットでない)ものを抜き出して... 49 // ※2018.4.19f1とのことですので、FindObjectsOfType(componentType, false)の形は使用できないかもしれません 50 // その場合は、アクティブなゲームオブジェクトだけを処理できればいいのでしたらFindObjectsOfType(componentType)を使い、 51 // さもなければリファレンスの説明にあるようにResources.FindObjectsOfTypeAllを使い、その中からシーンに 52 // 所属していないオブジェクトを除外して処理対象にすることになるかと思います 53 foreach (var component in FindObjectsOfType(componentType, false).OfType<Component>()) 54 { 55 // それを無効化する 56 Debug.Log($"{componentType.Name} on {component.name} will be disabled."); 57 disableComponent(component); 58 } 59 } 60 #endif 61}

ただしMonoScriptUnityEditorネームスペースにある型ですので、プレイモードでは使用可能だと思いますが、ビルドしたプログラム上では実行できないでしょうね。
苦肉の策として、「スクリプトファイルの名前とスクリプトコンポーネントの名前は一致するはず」と仮定して、下記のようにアセット名から型を探す形にしてみました。

lang

1using System; 2using System.Linq; 3using UnityEngine; 4 5public class ComponentDisabler2 : MonoBehaviour 6{ 7 // フィールドの型をObjectにする 8 public UnityEngine.Object target; 9 10 private void Update() 11 { 12 if (Input.GetKeyDown(KeyCode.Space) && (this.target != null)) 13 { 14 this.DisableAllComponents(GetType(this.target.name)); 15 } 16 } 17 18 // 名前がtypeNameの型を探す 19 private static Type GetType(string typeName) 20 { 21 return AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => assembly.GetTypes()).FirstOrDefault(type => type.Name == typeName); 22 } 23 24 // DisableAllComponentsはComponentDisablerのものと同じ 25 private void DisableAllComponents(Type componentType) 26 { 27 if (componentType == null) 28 { 29 return; 30 } 31 32 var enabledProperty = componentType.GetProperty("enabled"); 33 var propertyIsValid = (enabledProperty != null) && enabledProperty.CanWrite && (enabledProperty.PropertyType == typeof(bool)); 34 35 var enabledField = componentType.GetField("enabled"); 36 var fieldIsValid = (enabledField != null) && !enabledField.IsInitOnly && (enabledField.FieldType == typeof(bool)); 37 38 if (!propertyIsValid && !fieldIsValid) 39 { 40 return; 41 } 42 43 var disableComponent = propertyIsValid 44 ? target => { enabledProperty.SetValue(target, false); } 45 : (Action<Component>)(target => { enabledField.SetValue(target, false); }); 46 47 foreach (var component in FindObjectsOfType(componentType, false).OfType<Component>()) 48 { 49 Debug.Log($"{componentType.Name} on {component.name} will be disabled."); 50 disableComponent(component); 51 } 52 } 53}

こうなるともはやアセットの名前しか見ていませんので、セットするオブジェクトがスクリプトファイルである必要もなくなってしまうでしょう。ちょっと気持ち悪いかもしれませんが、下記のように「SphereCollider.txt」という名前のテキストファイルをセットしたところ...

図1

シーン上のSphereが持つSphereColliderが機能を停止し、物理的形状を失ってボールが床を貫通して落下していきました。

図2

投稿2021/06/30 12:06

編集2021/06/30 12:11
Bongo

総合スコア10811

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

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

hokuto37

2021/07/01 01:03

ありがとうございます! MonoScript型というのを知らなかったので助かりました。 これを使用して簡易的なものを作成してみました。
guest

0

回答いただいたMonoScript型を参考にして作成してみました。
targetScriptに無効化したいスクリプトを設定します。
すると OnValidateの中で、targetAssemblyQualifiedName に無効化したいスクリプトのAssemblyQualifiedNameが自動で設定されます。
このAssemblyQualifiedNameを比較して、同じスクリプトを無効化します。
AssemblyQualifiedNameではなくてType型で比較できればよかったのですが、TypeはSerialize出来なかったのでAssemblyQualifiedNameで代替しました。
AssemblyQualifiedNameも使ったことが無いのでこれで完全に問題無いのかよく分かってないですけども、簡易的なテストを行って動作確認済みです。

using UnityEngine; #if UNITY_EDITOR using UnityEditor; #endif public class ComponentDisabler : MonoBehaviour { #if UNITY_EDITOR public MonoScript targetScript; #endif [HideInInspector] public string targetAssemblyQualifiedName; void Start() { MonoBehaviour[] monoBehaviours = GameObject.FindObjectsOfType<MonoBehaviour>(); foreach (MonoBehaviour monoBehaviour in monoBehaviours) { if(monoBehaviour.GetType().AssemblyQualifiedName == targetAssemblyQualifiedName) { Debug.Log("Disable "+monoBehaviour.GetType().Name+" on "+monoBehaviour.gameObject.name); monoBehaviour.enabled = false; } } } #if UNITY_EDITOR private void OnValidate() { this.targetAssemblyQualifiedName = this.targetScript.GetClass().AssemblyQualifiedName; } #endif }

投稿2021/07/01 01:10

編集2021/07/01 17:00
hokuto37

総合スコア14

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

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

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.35%

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

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

質問する

関連した質問