I have multiple scripts that have one common boolean variable with the same name. As shown below:
Script1.cs
public bool isTrigger = false;
Script2.cs
public bool isTrigger = false;
... ...
Now I have a master script, that should find all the scripts with the common boolean name and change it. Here in the example allScripts
would be the list of all scripts that have the isTrigger boolean.
MasterScript.cs
for(int i = 0; i<allScripts.Length; i ){
allScripts[i].isTrigger = true;
}
How do I achieve this? How do I find all the scripts that have the same boolean variable and add it to a list?
CodePudding user response:
As said there are basically two options:
Common Base class
Use a common base class for your components like e.g.
public abstract class MyBase : MonoBehaviour
{
public bool IsTrigger;
// more common fields, properties and methods
}
and then instead inherit your other classes from that one
public class ClassA : MyBase
{
// additional A specific stuff
}
public class ClassB : MyBase
{
// additional B specific stuff
}
Since ClassA
and ClassB
aready inherit the members from MyBase
you can then directly use
public class Master : MonoBehaviour
{
// Use the common base type!
// Either populated via the Inspector
public MyBase[] allInstances;
// Or on runtime
private void Awake()
{
// e.g. find everything of the base type in your scene
allInstances = FindObjectsOfType<MyBase>(true);
foreach(var instance in allInstances)
{
instance.IsTrigger = true;
}
}
}
- Advantages
- Disadvantages
- You can only inherit from one single class so extending this with another base class is very inflexible
Interface
Instead of a common base class you can use an interface
. An interface does not bring any own implementation but is rather a member template.
As in an interface you can't define fields you will have to use properties
public interface IMyThing
{
bool IsTrigger { get; set; }
}
and then
public class ClassA : MonoBehaviour, IMyThing
{
// example using a serialzed auto-property
[field: SerializeField] public bool IsTrigger { get; set; }
}
public class ClassB : MonoBehaviour, IMyThing
{
// Example using a backing field
[SerializeField] private bool isTrigger;
public bool IsTrigger
{
get => isTrigger;
set => isTrigger = value;
}
}
and then in your master
public class Master : MonoBehaviour
{
// reference via Inspector
// Using the SeriaizeReferenceAttribute enables to serialize and reference any instances of
// classes inheriting from UnityEngine.Object and implementing the interface
[SeriaizeReference] public IMyThing[] allInstances;
private void Awake()
{
// since FindObjectOfType can not be sued on interfaces here i gets a bit more complex
// find all instances from all scenes
var list = new List<IMyThing>();
for (var i = 0; i < SceneManager.sceneCount; i )
{
var scene = SceneManager.GetSceneAt(i);
var roots = scene.GetRootGameObjects( );
foreach (var root in roots)
{
list.AddRange(root.GetComponentsInChildren<IMyThing>(true));
}
}
allInstances = list.ToArray();
foreach(var instance in allInstances)
{
instance.isTrigger = true;
}
}
}
- Advantage
- Solves the limitation of the base class: You can implement as many interfaces as you wish
- Disadvantage
- No guarantee anymore that a class implementing
IMyThing
is aMonoBehaviour
! =>FindObjectsOfType
can not be used andGetComponent
, etc might fail on runtime - Every class has to implement according members itself
- Unity doesn't directly serialize interfaces
- No guarantee anymore that a class implementing
CodePudding user response:
You can create an interface in which you define your property. You then have your scripts inherited from this class.
When instantiating your objects you need to add them to a list.
public interface IExampleA
{
public bool isTrigger { get; set;}
}
public class B : IExampleA
{
}
class masterscript
{
public void function()
{
// Create objects that has class B
// if object has class B add it to a list
// do your loop
}
}