I want to create a script that allows, at the press of a key of my choice, to activate or deactivate any of the scripts associated with the gameobject to which I associate it.
using System;
using System.Linq;
using UnityEditor;
using UnityEngine;
public class ToggleComponent : MonoBehaviour
{
public KeyCode toggleKey;
[ComponentSelector] public Behaviour componentToToggle;
void Update()
{
if (Input.GetKeyDown(toggleKey))
{
if (componentToToggle != null)
{
componentToToggle.enabled = !componentToToggle.enabled;
}
}
}
}
public class ComponentSelectorAttribute : PropertyAttribute
{
}
[CustomPropertyDrawer(typeof(ComponentSelectorAttribute))]
public class ComponentSelectorDrawer : PropertyDrawer
{
public override void OnGUI(Rect position, SerializedProperty property, GUIContent label)
{
Component targetObject = property.serializedObject.targetObject as Component;
Behaviour[] components = targetObject.GetComponents<Behaviour>().Where(c => c != targetObject).ToArray();
if (components.Length > 0)
{
string[] componentNames = components.Select(c => c.GetType().Name).ToArray();
int selectedIndex = System.Array.IndexOf(components, property.objectReferenceValue as Behaviour);
selectedIndex = EditorGUI.Popup(position, label.text, selectedIndex, componentNames);
if (selectedIndex >= 0)
{
property.objectReferenceValue = components[selectedIndex];
}
}
else
{
EditorGUI.LabelField(position, label.text, "No valid components found");
}
}
}
This works on cameras, but not on meshes, to give an example.
I don’t quite understand this sentence. What are “chambers” and why do you mention meshes? You can not disable meshes. You can disable MeshRenderers. However MeshRenderer are not Behaviours. Unity unfortunately has several base components which each introduce their own enabled property.
Behaviour
Renderer
Collider
Those are the 3 intermediate base classes which all are Components but introduce their own enabled property. You can not treat them abstractly because the enabled property is distinct for each of those Components. So if you want to be able to handle any built-in component that has an enabled property, you would need to use a Component field and in code check which of those 3 types it actually is
public Component comp;
// [ ... ]
if (comp as Behaviour behaviour)
behaviour.enabled = !behaviour.enabled;
else if (comp as Renderer renderer)
renderer.enabled = !renderer.enabled;
else if (comp as Collider collider)
collider.enabled = !collider.enabled;
This should cover 99% of all cases. There may be some exotic components which may also introduce an enabled property, but currently I can’t think of one. All built-in components are essentially derived from one of those 3, or they don’t have an enabled property at all. Like a Rigidbody for example.
Why do you use such a property drawer in the first place? By default when you have a Component field you can simply drag any component into that slot. In case you didn’t know, you can drag the component header onto serialized fields. This does also work when you want to assign a component from a different gameobject. However in that case you would need a second Inspector that you can lock, or you lock that target property so you can select another gameobject.
I’ve just digged on my HDD to find my old gif animation I made:
At that time the free version didn’t have the dark mode yet
Uhm, have you actually looked at his code and read the question? He’s using GetComponents<Behaviour>(). Behaviour is even a super class of MonoBehaviour and would get him many additional built-in components. Though he said it doesn’t work for some cases. Which cases aren’t clear, but I assumed he meant a MeshRenderer.
You don’t have all this code you posted in the one script file do you?
The property drawer should either be in an editor folder or assembly, or surrounded by #if UNITY_EDITOR pre-processors. Same with any editor-only using imports, such as UnityEditor.
@CodeSmile
I think the error is because as I posted it, it uses components valid only in the editor. If I add conditional compilation instead, of course, it compiles but does nothing.
@Bunny83
Sorry, I got confused. I change into “Camera”. MeshRenderer was correct instead.
Thanks, I didn’t remember you could drag the component rather than the whole Gameobject.
Good.
@spiney199
I actually didn’t try to put in “#if editor” the property drawer, I was convinced that using a decorator anyway also worked only in the editor. Using the decorator instructions that work only in the editor.