Reputation: 307
There's a platform class that contains several movement types. TypeA is AutoMove at initiation between waypoints TypeB is Falling with gravity when a specific boolean is true. I'm controlling these different behaviors via selecting its own Enum type.
What I'm trying to do now is to be able to only see those variables on inspector matching the movement types since TypeA uses waypoint system which TypeB completely ignores and all the unused variables remaining on inspector just gets things messy and chaotic.
I could just make them their own class at a time, but if I insist and try to do this: can this be done? How can I do it?
Another thing to ask is if there's a class such as mine which is better in performance efficiency-wise? To have classes on their own script? Or that just don't bother with performance? If there's no significant performance difference I intend to do this as I was doing.
EDIT : Added the issued inspector with indication. Red is the Enum selecting which movement function to follow 1. is one of the movement type that follows the waypoint system and roam 2. is one of the movement type that falls down on contact with PC 3. is one of the movement type that moves only if powered boolean is true
Upvotes: 1
Views: 4378
Reputation: 3861
I think it would be much better to make 3 separate controller scripts that all inherit a MovementType interface (if you want to keep them linked together). Then you only attach the controller that's required. So if it's auto move, you only attach the auto move script.
The interface would ensure that all 3 types keep certain ways of operating and ensure they keep certain functions. I assume they're related somehow which is why they're currently in the same file. If not just create the 3 separate scripts without the interface.
The interface would let you force certain objects to define a movement type.
The problem with the way you currently have it set up is that you have 1 script doing 4 things. This violates some best practices for programming, especially the idea in Unity where every script should be reusable and only do one main task.
EDITED for elaboration:
The idea is to compartmentalize behaviours. So if you need something to auto move, you create a separate script. Then in the future, if you want other things to auto move, like say a different type of game object similar to a platform like a cloud (thinking mario), then you can just drag your auto move script onto that game object as well. Likewise with fall at touch, you might want platforms to fall, but you might also want bricks to do that sometimes. So for the bricks you want to fall at touch, you just reuse that script for them as well.
ScriptableObjects are probably not applicable to this problem. They are meant for situations where there's something abstract in the game, like an Inventory. For actual objects that are in the game, you want to use standard GameObjects with scripts attached.
Upvotes: 1
Reputation: 1484
You will need to implement your own Custom Inspector. There is Unity's official tutorial on this topic. The custom inspector uses GUI classes, and you will need to check your condition and draw a field if and only if the condition is met.
Here's an example code that I took from Change Inspector Variables Depending On Enum. From this code you will learn how to dynamically get a value of a enum
field from your target class.
~/Assets/PropertyHolder.cs
using System.Collections;
using UnityEngine;
public class PropertyHolder : MonoBehaviour
{
public enum Status { A, B, C };
public Status state;
public int valForAB;
public int valForA;
public int valForC;
public bool controllable;
void Start()
{
}
void Update()
{
}
}
~/Assets/Editor/PropertyHolderEditor.cs
using UnityEditor;
using UnityEngine;
[CustomEditor(typeof (PropertyHolder)), CanEditMultipleObjects]
public class PropertyHolderEditor : Editor
{
public SerializedProperty
state_Prop,
valForAB_Prop,
valForA_Prop,
valForC_Prop,
controllable_Prop;
void OnEnable()
{
// Setup the SerializedProperties
state_Prop = serializedObject.FindProperty("state");
valForAB_Prop = serializedObject.FindProperty("valForAB");
valForA_Prop = serializedObject.FindProperty("valForA");
valForC_Prop = serializedObject.FindProperty("valForC");
controllable_Prop = serializedObject.FindProperty("controllable");
}
public override void OnInspectorGUI()
{
serializedObject.Update();
EditorGUILayout.PropertyField(state_Prop);
PropertyHolder.Status st = (PropertyHolder.Status) state_Prop.enumValueIndex;
switch (st)
{
case PropertyHolder.Status.A:
EditorGUILayout.PropertyField(controllable_Prop, new GUIContent("controllable"));
EditorGUILayout.IntSlider(valForA_Prop, 0, 10, new GUIContent("valForA"));
EditorGUILayout.IntSlider(valForAB_Prop, 0, 100, new GUIContent("valForAB"));
break;
case PropertyHolder.Status.B:
EditorGUILayout.PropertyField(controllable_Prop, new GUIContent("controllable"));
EditorGUILayout.IntSlider(valForAB_Prop, 0, 100, new GUIContent("valForAB"));
break;
case PropertyHolder.Status.C:
EditorGUILayout.PropertyField(controllable_Prop, new GUIContent("controllable"));
EditorGUILayout.IntSlider(valForC_Prop, 0, 100, new GUIContent("valForC"));
break;
}
serializedObject.ApplyModifiedProperties();
}
}
And this is how to check bool & draw only if the condition is met, from Hide/Show properties dynamically in inspector. Modify the boolean checking part to compare the enum
value you found using the above code.
public class MyScript : MonoBehaviour
{
public bool flag;
public int i = 1;
}
[CustomEditor(typeof (MyScript))]
public class MyScriptEditor : Editor
{
void OnInspectorGUI()
{
var myScript = target as MyScript;
myScript.flag = GUILayout.Toggle(myScript.flag, "Flag");
if (myScript.flag)
myScript.i = EditorGUILayout.IntSlider("I field:", myScript.i, 1, 100);
}
}
Combining these two you should get the behaviour you want.
Upvotes: 2