I have a game object. In the "Inspector" of the game object there are some scripts. Now I want to change a public variable that is attached to the script. How can I do this?
GameObject.Find("Wanderer").GetComponent<SteerForTeether>().TetherPosition = "whatever";
That should do it I suppose
A script attached to an object is a Component of the object. To access to a component, you need to call GetComponent<TYPE>() method from the game object. The type of the component would be same as the name of the script you are trying to reach.
Here's an example:
GameObject.Find("Player").GetComponent<PlayerController>().KillPlayer();
The name of the script, in this case, is PlayerController.cs. KillPlayer() is a public method defined in this script.
Related
public void AddComponent(Component component)
{
gameObject.AddComponent<component>();
}
the method is giving me
this error
and I'm wondering how to get it so it just works
You need let api know which type you want to add , this api not very smart to know your variable is what type. so just put in a type. not put in a variable.
SomeTypeOfCompoent : Compoent
{
}
gameObject.AddComponent<SomeTypeOfCompoent>();
If you just want a component to be added that is of the same type as the variable you're passing you can do:
gameObject.AddComponent<typeof(component)>();
Alternatively you could change the method to
public void AddComponent(Type type) {
gameObject.AddComponent<type>();
}
Since that would be using a Type parameter directly. To be honest though, if you're trying to do that, there's not really a need for your method at all. AddComponent already does that on it's own.
I suspect, however, that you're trying to copy the component including it's current data. If so, you can't do it in the way you are. Adding a component will just add that type of component with it's default settings. You can't Instantiate just a component either. Possible solutions for that are to Instantiate the entire gameobject it comes from, or make a method that adds a new component, then copies data one by one from the old component to the new one.
I know this can be done because the amazing plugin Odin, has some epic serialization tools.
I was hoping I could do this using Odin but even their [Serialize] tag doesn't work.
I want to serialize a new instance of a script inside of a Scriptable Object.
With Odin, you can serialize dictionaries, and if you serialize a dictionary which holds instance of an interface (script) it allows you to create a new instance of that script inside the dictionary like so:
Since its possible to store an instance of a script inside of a dictionary I am curious how this can be done on its own.
The script I want to save is a generic script with only functions and an empty constructor.
Do you know a why to serialize the instance of an interface (script) inside of a ScriptableObject?
Ideally I could create an attribute some how and just force it to serialize like so:
public class MyClass: MonoBehaviour
{
[ForceSerialize]
public IScript scriptToSerialize;
}
And then in the inspector I could just click the box and create a new instance of that script to be attached to the object.
You don't need any [Serialize] tag, MyClass simply has to inherit from Sirenix.OdinInspector.SerializedMonoBehaviour instead of MonoBehaviour.
These "Serialized" class (also exists for ScriptableObjects and the likes) need to be used in order for Odin's custom serialization to work, which would make your field appear in the inspector.
This script works for me:
using Sirenix.OdinInspector;
public class MyScript : SerializedMonoBehaviour
{
public IScript scriptToSerialize;
}
public interface IScript { }
I am working on a method where the player can customize their sprite. I have created an array in my manager script like so:
public Sprite[] spriteImages = new Sprite[5];
In this array, I intend to add 5 png files, that will be used to update the spriteRenderer sprite. I have two problems, I am struggling accessing the array in the sprite's script (which I believe is the best way to change the image). I am also struggling to actually work out how to change the sprites image. Currently I am using this code:
this.gameObject.GetComponent<SpriteRenderer> ().sprite = GameObject.Find ("UIManager").GetComponent<UIManager> ().spriteImages [0];
In my sprite list, I have put 5 png files (2D sprite textures), but when I run the program, it says 'object reference not set to an instance of an object'. Not sure why it gives this error when the array has sprites in?
The gameobject I am referring to 'UIManager' is in a different scene to the one I am using the find from. Is this invalid?
There are a few ways I can think of resolving your issue.
1) Singleton classes. Declare a static instance of your class in which the sprite array is kept i.e. uIManager class. You can make your class singleton using the method shown in link or else you can simply declare like this:
public class UIManager : MonoBehaviour {
UIManager static instance;
void Start() {
instance = this;
}
}
The good part is your can directly refer to your class like UIManager.instance and get all the public variables inside the class. Downside is if you have multiple scripts in same scene it will only refer to one of the instance and you will not be able to access other instances of the script which are present in scene. So this method can only be used for one instance per scene.
2) Saving a reference of your desired script in Unity Editor & by assigning it to public variable in the script. Consider you have Class A which does some calculation and you have Class B which stores some data; let's assume its Sprite array similer to your script. Now in Class A you require that sprite array for assigning. So what you can do is declare a public variable of Class B ie public ClassB classBInstance;. And you will be able to see empty the instance of ClassB field in unity editor. You can directly assign the required reference and voila you will be able to access variables of your class B.
3) Use unity API to find gameobject in which your class is attached.
These are some of the API I use regularly aside from above two method:
You can find single game object with name or will return the first
object with the name. GameObject.Find(string name)
This will return the game objects with a particular tag. You might
want to look into setting a game objects with a tag if you don't
know how to set them.
GameObject.FindGameObjectsWithTag(string tag)
This will return first game object with tag.
GameObject FindWithTag(string tag)
This API returns first gameobject of the desired type.
GameObject.FindObjectOfType(Type type)
This API will return all gamebjects with the given type.Here in both
the cases the type can be of Class type. And this will return all the
game objcts which has your class type attached.
GameObject.FindObjectsOfType(Type type)
4) Setting up your array as static, But if you do that then you will not be able to access it in unity editor and therefore wont be able to assign the Sprites in editor.
For your question I believe first method should more than do the trick.
The spriteImages variable is not declared as static and this means that you need an instance of UIManager to access the spriteImages variable in it. You can mark it as static and you won't need to provide instance of it to access it.
public static Sprite[] spriteImages = new Sprite[5];
That's one way to fix that error but I don't think you should use static for this. UIManager is likely a script attached to a GameObject so all you've got to do is find the GameObject the UIManager is attached to then get the UIManager component from it. That component is the script instance required to access the spriteImages variable without making it static.
private UIManager uIManager;
void Start()
{
//Find the GameObject then the script instance
GameObject uManagerObj = GameObject.Find("UIManager GameObject");
uIManager = uManagerObj.GetComponent<UIManager>();
//Now you can do this with the script instance
this.gameObject.GetComponent<SpriteRenderer>().sprite = uIManager.spriteImages[0];
}
Make sure to replace "UIManager GameObject" from the GameObject.Find function with the name of GameObject the UIManager script is attached to.
I'm using InvokeRepeating() to call a method in a game. I call InvokeRepeating() in the Start() method of one of the GameObject classes. To set the repeatRate parameter for InvokeRepeating(), I am passing it a public field called secondsBetweenBombDrops.
Unity ignores the value I specify for secondsBetweenBombDrops in the code and instead uses some default value (i.e. 1) when secondsBetweenBombDrops is declared without a static modifier:
public float secondsBetweenBombDrops = 10f;
void Start() {
InvokeRepeating("DropBomb", 1f, secondsBetweenBombDrops);
}
However, once I add the static modifier to secondsBetweenBombDrops, the code behaves as expected and the correct value of 10 is used:
public static float secondsBetweenBombDrops = 10f;
void Start() {
InvokeRepeating("DropBomb", 1f, secondsBetweenBombDrops);
}
Why does this field require the static modifier to use the appropriate value?
In the Unity inspector, the script component shows that secondsBetweenBombDrops is 1. This default value of 1 is present regardless of whether I instantiate the prefab on game start or create prefab instances while the game is running.
The double-edged sword of serialization
Unity wants to make things easier for everyone, including people with limited coding knowledge (beginners, designers).
To help them out, Unity displays data in the inspector. This allows the coder to code and the designer to design by tweaking the values without opening MonoDevelop/an IDE.
There are two ways to have values display in the inspector:
public int myVar = 10;
[SerializeField] private int myOtherVar = 0; // Can also be protected
The second one is better since it complies with encapsulation principle (variables are private/protected and modified via methods or properties).
When you display a variable in the Editor, the value given in the script is only used when dragging the script. Unity then serializes those values and does not care about any script modification anymore. This can lead to confusion if, for instance, myVar is set to 20 inside the script after the fact, it will not be used. The serialization is written in the scene file.
The two lines in the example work exactly in the same way.
Possible solutions
It is possible to get Unity to consider new values in a script by pressing Reset on the settings wheel of the script component. That will also reset all the other variables of the component, so only do this if that is intended.
Making the variable private and omitting the attribute [SerializeField] will disable the serialization process, so Unity will no longer look in the scene file for a value to display - instead, the value will be created at runtime by the script.
When adding a component to Unity, a new object of the type of the component is created. The values that are displayed are the serialized values from that object. For this reason, only member values can be displayed and static variables are not, as they are not serializable. (This is a .NET specification, not strictly specific to Unity.) Because Unity does not serialize static fields, this is why adding the static modifier seemed to solve the problem.
Explaining the OP
In the OP case, based on the comments, your public field was showing a value of 1 in the editor. You thought this value was a default one, when it was actually the value you most likely gave to the field when originally declaring it. After you added the script as a component, you made the value 10 and thought it was buggy as it was still using the value of 1. You should now understand that it was working just fine, as designed.
What does Unity serialize?
By default, Unity will serialize and display value types (int, float, enum and so on) as well as string, array, List and MonoBehaviour. (It is possible to modify their appearance with Editor scripts, but this is off-topic.)
The following:
public class NonMonoBehaviourClass{
public int myVar;
}
is not serialized by default. Here again, this is .NET specification. Unity serializes MonoBehaviour by default as part of the engine requirement (this will save the content to the scene file). If you wish to display a "classic" class in the editor, just say so:
[System.Serializable]
public class NonMonoBehaviourClass{
public int myVar = 10;
}
Obviously, you cannot add it to a game object so you need to use within a MonoBehaviour:
public class MyScript:MonoBehaviour{
public NonMonoBehaviourClass obj = new NonMonoBehaviourClass();
}
this will display the object in the inspector and allow modifications to the myVar variable in the instance of NonMonoBehaviourClass. And again, any changes to myVar within the script will not be considered after the value is serialized and stored to the scene.
Extra tips on displaying things in the inspector
To finish, interfaces are not displayed in the inspector either since they don't contain any variables - just methods and properties. In debug mode, properties are not displayed by default. You can change this mode using the button with three lines in the top right corner of the Inspector. The first two settings are Normal/Debug. The first one is the default one, the second will also display private variable. This is useful to watch their values but cannot be altered from editor.
So if you need an interface to be displayed, you would have to consider an abstract class as it offers a similar functionality (except for multi inheritance) but can be a MonoBehaviour.
References:
http://docs.unity3d.com/ScriptReference/SerializeField.html
http://docs.unity3d.com/Manual/script-Serialization.html
https://www.youtube.com/watch?v=9gscwiS3xsU
https://www.youtube.com/watch?v=MmUT0ljrHNc
Title explains it all, I want to know how to access variables from another script. I've searched online, but found nothing that's worked.
You could make a class, instantiate an object of the class and access propterties.
Or you could use static variables.
Or even beter, lets say you have a GameManager.cs script attached to an empty object called GameManager. And you want to access its variables form the LevelManager.cs script. You do this inside the LevelManager.cs
public GameManager gameManager;
Then you can drag and drop your GameManager empty object to this public field, and everytime you want to access a variable you type gamemanager.yourVariableHere
Or, if you dont want to drag and drop:
in the start method...
void Start()
{
gameManager = GameObject.Find("GameManager");
//this way it finds your object automatically
}
Hope it helped, good luck.
First you need to make your variables public. Then get the GameObject, get the Componend and access your variable.
var variable = GameObject.Find("name").GetComponent<ScriptClass>().yourVariable;
To add to the previous answer, if your class is a pure c# class and doesnt inherit from monbehaviour then must create an instance of class. If you want global access to certain variables you should look into static variables or implement a singleton pattern