Unity3D: Script variables inconsistences using OnTriggerEnter2D - c#

I have the object that have the script component.
public class TeleportReference : MonoBehaviour {
private GameObject reference;
void Start () {
reference = null;
}
public void SetReference(GameObject other){
reference = other;
}
public GameObject GetReference(){
return reference;
}
Now if I search for an object and test the script variables
GameObject test = GameObject.FindGameObjectWithTag("Water");
print(test);
print(test.GetComponent<TeleportReference>());
print(test.GetComponent<TeleportReference>().GetReference());
it works just fine and GetReference() return the variable I stored.
But now if I use it whithin OnTriggerEnter2D
private void OnTriggerEnter2D(Collider2D other)
{
if (other.tag == "Water")
{
print(other);
print(other.gameObject);
print(other.GetComponent<TeleportReference>());
print(other.GetComponent<TeleportReference>().GetReference());
}
}
GetReference() return null (or other variable that I used during Start() of TeleportReference class).
All other testing outputs remain the same.
Could anyone give a hint why this could happen? Does that mean that GetComponent created new instance of TeleportReference in second case?

GetComponent did not create a new instance of TeleportReference in second case. I have similar code in one of my projects and I haven't had any problems. So in this case I would look to see if the problem is somewhere else. Are you sure it's the same "Water" object? Do you have multiple objects with "Water" tag? Are you colliding before reference is assigned? There could be a myriad of things going on. Just test to narrow it down.
For example try performing an action on the other.gameObject object to verify it's the right object, like deactivating it. Also try using other.gameObject.GetComponent (not sure if this makes a difference).

Found the issue. It was in the order of assigning variables. That is - changes were made apperantly before Start() function was called. Thus at some point of the code the stored value was overritten back to null.
This works fine:
public class TeleportReference : MonoBehaviour {
private GameObject reference;
void Awake () {
reference = null;
}
public void SetReference(GameObject other){
reference = other;
}
public GameObject GetReference(){
return reference;
}
Thanks everyone for comments, that really helped me in debugging.

Related

How to access string in one script from another? [duplicate]

This question already has answers here:
In Unity, how can I pass values from one script to another?
(4 answers)
Closed 1 year ago.
Can you tell me how to access a variable of a script from another script ? I have even read everything in unity website but I still can’t do it. I know how to access another object but not another variable.
This is the situation :
I’m in script B and I want to access the variable X from script A. The variable X is boolean.
Can you help me ?
Btw i need to update X’s value costantly in script B , how do I do that ? Access it in Update function
If you could give me and example with these letters would be great !
Thank you
You first need to get the script component of the variable, and if they're in different game objects, you'll need to pass the Game Object as a reference in the inspector.
For example, I have scriptA.cs in GameObject A and scriptB.cs in GameObject B:
scriptA.cs
// make sure its type is public so you can access it later on
public bool X = false;
scriptB.cs
public GameObject a; // you will need this if scriptB is in another GameObject
// if not, you can omit this
// you'll realize in the inspector a field GameObject will appear
// assign it just by dragging the game object there
public scriptA script; // this will be the container of the script
void Start(){
// first you need to get the script component from game object A
// getComponent can get any components, rigidbody, collider, etc from a game object
// giving it <scriptA> meaning you want to get a component with type scriptA
// note that if your script is not from another game object, you don't need "a."
// script = a.gameObject.getComponent<scriptA>(); <-- this is a bit wrong, thanks to user2320445 for spotting that
// don't need .gameObject because a itself is already a gameObject
script = a.getComponent<scriptA>();
}
void Update(){
// and you can access the variable like this
// even modifying it works
script.X = true;
}
just for completing the first answer
there is no need for
a.gameObject.getComponent<scriptA>();
a is already a GameObject so this will do
a.getComponent<scriptA>();
and if the variable you are trying to access is in children of the GameObject you should use
a.GetComponentInChildren<scriptA>();
and if you need a variable of it or method you can access it like this
a.GetComponentInChildren<scriptA>().nameofyourvar;
a.GetComponentInChildren<scriptA>().nameofyourmethod(Methodparams);
You can use static here.
here is the example:
ScriptA.cs
Class ScriptA : MonoBehaviour{
public static bool X = false;
}
ScriptB.cs
Class ScriptB : MonoBehaviour{
void Update() {
bool AccesingX = ScriptA.X;
// or you can do this also
ScriptA.X = true;
}
}
OR
ScriptA.cs
Class ScriptA : MonoBehaviour{
//you are actually creating instance of this class to access variable.
public static ScriptA instance;
void Awake(){
// give reference to created object.
instance = this;
}
// by this way you can access non-static members also.
public bool X = false;
}
ScriptB.cs
Class ScriptB : MonoBehaviour{
void Update() {
bool AccesingX = ScriptA.instance.X;
// or you can do this also
ScriptA.instance.X = true;
}
}
for more detail, you can refer singleton class.

Passing values from one script to another without a game object in the scene

I’ve found a lot of information on passing parameters from one script to another when a game object is present in the hierarchy. My problem is that my Transform object is created on the fly using Instantiate(myPrefab). Is there any way to access the position of myPrefab game object from another script?
You could store a reference to the instantiated GameObject after it has been instantiated (see example below). If there are more GameObjects, use a list to store them instead.
Call the InstantiateGO() and GetGOPosition() where it makes sense for you.
public class YourClass: MonoBehaviour
{
public GameObject yourPrefab;
public GameObject yourGameObject;
// Use this for initialization
void Start ()
{
}
// Update is called once per frame
void Update ()
{
}
void InstantiateGO()
{
yourGameObject = Instantiate(yourPrefab); // assign the newly instantiated GameObject to yourGameObject
}
void GetGOPosition()
{
var x = yourGameObject.position;
//Do something here
}
}

How to call a public static variable from another class, change its value and then check that its changed from its original class [duplicate]

So im trying to change a variable in another script by touching a cube.
Current setup
1x Player
1x Enemy
Each with their own script Enemy_Stats & Character_Stats
As you can see in this little snippet it's quite a workaround to access the variable from another script.
void OnCollisionEnter(Collision collision)
{
if (collision.gameObject.tag == "Enemy")
{
collision.gameObject.GetComponent<Enemy_Stats>().Health =
collision.gameObject.GetComponent<Enemy_Stats>().Health
- gameObject.GetComponent<Character_Stats>().AttackDamage;
if (collision.gameObject.GetComponent<Enemy_Stats>().Health <= 0)
{
Destroy(collision.gameObject);
}
}
}
Iam new to Unity, but isn't there a way to just refer it with something like:
collision.Health?
How to access variables/functions from another Class. The variable or function you want to access or called must be public not private.
public class ScriptA : MonoBehaviour{
public int playerScore = 0;
void Start()
{
}
public void doSomething()
{
}
}
Access variable playerScore in ScriptA from ScriptB. First, find the GameObject that the script or component is attached to with the GameObject.Find function then use the GetComponent function to retrieve that script or component that is attached to it.
public class ScriptB : MonoBehaviour{
ScriptA scriptInstance = null;
void Start()
{
GameObject tempObj = GameObject.Find("NameOfGameObjectScriptAIsAttachedTo");
scriptInstance = tempObj.GetComponent<ScriptA>();
//Access playerScore variable from ScriptA
scriptInstance.playerScore = 5;
//Call doSomething() function from ScriptA
scriptInstance.doSomething();
}
}
No since Health is not part of the collision object, but Enemy_Stats. You can cache a Component (that's what Enemy_Stats is) if you use it multiple times to save you some typing (and some performance, but that is rather marginal for this example). Also you can cache "known" components like in this case Player_Stats. You can do this e.g. in Start or with a public variable and the inspector.
What you should probably do though is to make the enemy be responsible for his life and not the player, so move the Destroy-part to Enemy_Stats (into the Health property to be exact).
The first thing to make this shorter (and eventually faster) would be to store this: gameObject.GetComponent<Character_Stats>() on Start() in a private variable (you should avoid calling GetComponent on a frequent basis if you can avoid it).
For the Health variable, a way of avoiding GetComponent calls could be caching: you create a Dictionary<GameObject, Enemy_Stats> and read from that as soon as this gameobject collided once
At the very beginning i mean in Awake() method you can find a game-object with tag
and get it's Heath after that in Collision() method you should just decrease the health but, here the condition is there is only one enemy and only one player.

Unity: Generic Method to get or add a component

Every time I make a new Script in Unity, I always end up doing a bunch of checks for any components my script depends on, like:
SpriteRenderer sr = gameObject.GetComponent<SpriteRenderer>();
if(sr == null)
sr = gameObject.AddComponent<SpriteRenderer>() as SpriteRenderer;
So I decided to play around and make a generic method to do this with any Component, and I came up with the following code, which I simply added right to my own new Script.
T GetOrAddComponent<T>() where T : Component
{
T component = gameObject.GetComponent<T>();
if (component == null)
component = gameObject.AddComponent<T>() as T;
return component;
}
I've tried it and the function works well, but I'm wondering if there is any major downside to this approach, or if there is some other better way to complete the same task, possibly using a existing method I am unaware of or by creating the method in some other way.
The GetComponent method is actually rather taxing on the system. If you are developing for mobile, too many of them can cause a noticeable lag in load times.
I personally use RequireComponent method. Then the script would automatically add the component the moment it's added to the GameObject. Then I would manually drag the name of the component to the field on the script object in the inspector.
Example:
using UnityEngine;
// PlayerScript requires the GameObject to have a RigidBody component
[RequireComponent (typeof (RigidBody))]
public class PlayerScript : MonoBehavior {
[SerializeField]
private RigidBody rb;
...
}
First i recommend you to use "RequireComponent" :
[RequireComponent(typeof(SpriteRenderer))]
[RequireComponent(typeof(AnotherComponent))]
public class NetworkService : MonoBehaviour
{
private SpriteRenderer _sRenderer;
//strong way to never get a null reference.
#if UNITY_EDITOR
private void OnValidate()
{
if (null == _sRenderer)
_sRenderer = GetComponent<_sRenderer>();
}
#endif
the "OnValidate" method will be executed every time you make a change in the value of a parameter in the editor or load the script/component.
You could do it all in one if statement if you'd like:
SpriteRenderer sr;
if(gameObject.GetComponent<SpriteRenderer>())
sr = gameObject.GetComponent<SpriteRenderer>();
else
sr = gameObject.AddComponent<SpriteRenderer>() as SpriteRenderer;
You will potentially be making the GetComponent call twice, but if you like the code structure better so be it. I personally think the way you are doing it is best though.
Though to be even more concise, you can return the component directly instead of having to store it in the variable component
public T GetOrAddComponent<T>() where T : Component
{
if (gameObject.GetComponent<T>())
return gameObject.GetComponent<T>();
else
return gameObject.AddComponent<T>() as T;
}
And as long as you are doing this at scene load or in the start function, there really won't be any performance difference.
public static void GetOrAddComponent<T>(this GameObject model, Action<T> onSucess) where T: Component {
onSucess(model.GetComponent<T>() ?? model.AddComponent<T> () as T);
}
In the new version of Unity (With C# 8.0 and above) you can simply do this in one line.
[SerializeField] private SpriteRenderer spriteRenderer;
public SpriteRenderer GetSpriteRenderer => spriteRenderer ??= GetComponent<SpriteRenderer>() ?? gameObject.AddComponent<SpriteRenderer>();
The code above does three things.
Returns private local spriteRenderer component from the getter property if it's not null.
If spriteRenderer is null, then it proceed to assign the value by calling GetComponent() before returning.
If GetComponent() returns null, then the next operation will add sprite renderer component to the game object and assign to spriteRenderer before returning.
Here's an example using an extension method:
public static class MonoBehaviourGetOrAddComponent {
public static T GetOrAddComponent<T>(this GameObject self) where T : Component
{
T component = self.GetComponent<T>();
return component != null
? component : self.AddComponent<T>() as T;
}
}

How do I pass variable from one script to another C# Unity 2D?

For example I have a variable (public static float currentLife) in script "HealthBarGUI1" and I want to use this variable in another script.
How do I pass variable from one script to another C# Unity 2D?
You could do something like this, because currentLife is more related to the player than to the gui:
class Player {
private int currentLife = 100;
public int CurrentLife {
get { return currentLife; }
set { currentLife = value; }
}
}
And your HealthBar could access the currentLife in two ways.
1) Use a public variable from type GameObject where you just drag'n'drop your Player from the Hierarchy into the new field on your script component in the inspector.
class HealthBarGUI1 {
public GameObject player;
private Player playerScript;
void Start() {
playerScript = (Player)player.GetComponent(typeof(Player));
Debug.Log(playerscript.CurrentLife);
}
}
2) The automatic way is achieved through the use of find. It's a little slower but if not used too often, it's okay.
class HealthBarGUI1 {
private Player player;
void Start() {
player = (Player)GameObject.Find("NameOfYourPlayerObject").GetComponent(typeof(Player));
Debug.Log(player.CurrentLife);
}
}
I wouldn't make the currentLife variable of your player or any other creature static. That would mean, that all instances of such an object share the same currentLife. But I guess they all have their own life value, right?
In object orientation most variables should be private, for security and simplicity reasons. They can then be made accessible trough the use of getter and setter methods.
What I meant by the top sentence, is that you also would like to group things in oop in a very natural way. The player has a life value? Write into the player class! Afterwards you can make the value accessible for other objects.
Sources:
https://www.youtube.com/watch?v=46ZjAwBF2T8
http://docs.unity3d.com/Documentation/ScriptReference/GameObject.Find.html
http://docs.unity3d.com/Documentation/ScriptReference/GameObject.GetComponent.html
You can just access it with:
HealthBarGUI1.currentLife
I'm assuming that HealthBarGUI1 is the name of your MonoBehaviour script.
If your variable is not static and the 2 scripts are located on the same GameObject you can do something like this:
gameObject.GetComponent<HealthBarGUI1>().varname;
//Drag your object that includes the HealthBarGUI1 script to yourSceondObject place in the inspector.
public GameObject yourSecondObject;
class yourScript{
//Declare your var and set it to your var from the second script.
float Name = yourSecondObject.GetComponent<HealthBarGUI1>().currentLife;
}
TRY THIS!
//Drag your object that includes the HealthBarGUI1 script to yourSceondObject place in the inspector.
public GameObject yourSecondObject;
class yourScript{
//Declare your var and set it to your var from the second script.
float Name = yourSecondObject.GetComponent<HealthBarGUI1>().currentLife;

Categories