- Home /
Referencing non static variables from another script? C#
I'm going crazy over here. All I want to do is reference a variable in one script from another. This variable can't be static though. I've gone through a million examples (most in Javascript, and I'm not so good at translating). Nothing is working. Here's an example of what I mean:
In a script called "PlayerScript" attached to "ThePlayer" game object:
public class PlayerScript: MonoBehaviour {
float Health = 100.0f;
}
What, very specifically, would I put into another script to get at that Health variable?
Notice that the scripting reference has C#, JS and Boo examples. You can toggle which language you want to get help for by selecting from the drop down on the right side near code snippets.
Answer by Statement · Jan 14, 2011 at 09:39 AM
I doubt you've gone through a million examples. See GetComponent docs.
1 - Make Health public.
public class PlayerScript: MonoBehaviour {
public float Health = 100.0f;
}
2 - Access it.
public class Accessor : MonoBehaviour {
void Start()
{
GameObject thePlayer = GameObject.Find("ThePlayer");
PlayerScript playerScript = thePlayer.GetComponent<PlayerScript>();
playerScript.Health -= 10.0f;
}
}
Basically there are two steps involved.
A. You need a reference to the game object that hold the script, or component that is placed on the same object of your script. This can be found with GameObject.Find, accessing transform children, (or just call GetComponent on the running script, see #B).
B. You use GetComponent on either the game object or component, to access your script.
@The OP: Note that you don't actually have to make 'Health' public. If you only want to read from it but not write to it, you can expose its value through an accessor or property. (Which you can still do if you want to write to it as well, of course.)
But for the sake of learning, and keep progress pace s$$anonymous$$dy, you won't miss out much on just using public fields for now.
Thanks Statement! I really did try a whole slew of examples, but I couldn't really find any that spelled it out as well as you did here. I'm pretty new at C# and Unity, so the syntax of this stuff is melting my brain a little bit. I don't fully understand how this works, but I can work toward understanding it now that I've got a working example. Thanks again!
Statement, so in my game I am trying to make a coin currency system. I have been trying to find out how I could take the variable "coins", which is the amount of coins you collect throughout the level, and add it to the variable "totalCoins"(totalCoins = totalCoins + coins;) ,which is the coins you have collected in other levels. Looking at this sounds super easy, but I would like to then take these variables and display it at my $$anonymous$$ain$$anonymous$$enu scene. I have one C# script that is in the level that counts the coins you collect with a GUI.Label. In my $$anonymous$$ain$$anonymous$$enu scene I have another scene that is supposed to display all of your coins with a different GUI.Label. Do you know what I could do? NOTE: I can add the scripts if needed I guess.
Answer by MFKJ · May 14, 2015 at 03:34 PM
Simple no more extra lines
public class PlayerScript: MonoBehaviour {
public float Health = 100.0f;
}
here you can access
public class Accessor : MonoBehaviour {
void Start()
{
GameObject.Find("ThePlayer").GetComponent<PlayerScript>().Health -= 10.0f;;
}
}
@$$anonymous$$F$$anonymous$$J - Statement gives a cleaner way to do this.
This is exactly what I needed, thank you. Simple, effective. Only thing I have to do is make sure it works when I go to use it.
O$$anonymous$$, but what about if "Player" is a crate, where there could be a hundred in your level, and you're only trying to affect the health of that specific crate you've shot from inside a raycast check that you first need to do to check if you've even shot the crate in the first place?
I mean, here's what I have for checking the I've shot the crate:
if (Physics.Raycast(playerCam.transform.position, playerCam.transform.forward, out hit, 500, layer$$anonymous$$ask))
{
if (hit.collider.gameObject.CompareTag("Crate"))
{
Debug.Log("Crate Was Hit");
}
}
I don't know how to use the code you've suggested because I don't have a single crate object in the game with a single name that I can easily reference like in the example above (which would of course be fine for on the player). I can't just put "crate" because there's more than one in the level; and I can't obviously write down every single possible crate name I have in my level either (not in any way I know of that wouldn't be crazy). I have a hundred crates and I only want to affect the specific one I'm shooting, and whatever I check and do needs to be done so inside the raycast stuff too (as far as I'm aware). So how would I do that?
This dose not seem to be working for me I just get this error: Assets\weaponSwiching.cs(27,17): error CS0029: Cannot implicitly convert type 'int' to 'bool'
Note: I am a noob I could be doing something completely stupid here
This is my code: GameObject.Find("first person player").GetComponent().Speed = heavyWeightSpeed;;
Look at GetComponent again. You wrote GetComponent().Speed
You need to mention the script you're actually referencing in there for it to work. It should be like this:
GetComponent<yourScriptNameSpelledInExactlyTheSameWay>().Speed
so your completed variable should look a bit like this:
GameObject.Find("first person player").GetComponent<theScriptYourAreReferencing>().Speed = heavyWeightSpeed;
and this will set the variable speed of whatever script you're referencing to heavyWeightSpeed.
Answer by rolandcahen · Feb 26, 2012 at 10:51 PM
This point is very important and not done in Unity.
Any real time program should easily allow to share real time variables between any script.
But at the moment is is a real hassle, and never works unless you are a professionnel developer. I have been studying for more than a year and am ashamed I canot achieve such a simple task. Scripting is one thing, beeing a developer is another.
Game designers and non developers users feel excluded from Unity mainly because such functionalities are not simply accessible to them and not clearly explained by examples.
100% agree.
It should be so simple to do this--it is in something like Game $$anonymous$$aker Studio for example--but here it seem absurdly convoluted and/or complicated.
And even with the example above, I still can't figure out how to affect only a single instance of whatever object in my game rather than a random one or all of the objects with the same tag. All I want to do is check what I've shot using a raycast--and there could be multiple instances of the same object in the level so I can't just use "name" or "FindGameObjectWithTag" (which is what most examples show)--and then reduce the health of the specific instance of the object I've shot.
@impurekind you can absolutely affect a single instance of a copied prefab. The Raycast function allows you to pass in a "RaycastHit" variable which contains data on the object that was hit. Let's pretend you named this variable "Hit". All you have to do is check if (hit.transform.GetComponent() != null). Or if you're looking for tags you can check if (hit.transform.gameObject.CompareTag("YourTag")). Then you simply access YourScriptHere again using GetComponent() and reduce it's health. GetComponent() only returns the one instance of the script which is on the object it derives from. In our case, hit.transform.gameObject is the parent, and this object is the one that was hit by the Raycast.
Also, you can share realtime variables between any script. It takes a few lines to set it up, and you have to do it for each script, but it's only a little bit of a hassle in my opinion. The same function (GetComponent) can allow you to access any script on any object. You can store that script as a variable (with a type of YourScriptHere) and then simply edit it's components by writing yourScript.myVariable = 20, etc. The fields on the other script must be public. That's about it, there's no trick. You just have to manually add each script you want to edit at the start of the scene (likely on the Awake() function) and then later access it through the variable you stored it in.
Your other option is static variables, which allow you to read information at any point from any script without an instance--you can access it just by typing YourScriptHere.staticVariable. The downside is that static fields cannot be modified and static functions cannot access non-static information unless it is passed in as an expression.
It takes a few lines to set it up, and you have to do it for each script != you can share realtime variables between any script. You spend your time figuring out how to pass variable instead of spending it on actual game.
Answer by Jeremy-Borton · Dec 14, 2021 at 01:45 AM
I don't know if this will help, but I've created a single Damage script that my obstacles, good and bad and player uses. And all it has is a float for crashDamage. That's it. Then in my individual game object main scripts that have crazy names for this bad guy, and that obstacle (having different behaviors), when I have a collision, I just search for the Damage script, get its Damage component and then minus my individual armor from that component's crashDamage.
Using a single script with a common name makes it easy to reference with get component when my main scripts have all kinds of names. My radar picks up the closest object and then I search that object for the common name script and apply its variable to my crazy named objects if need be.