Hi,
I’m a little unclear about GetComponent. I tried this script:
using UnityEngine;
using System.Collections;
public class TurnBlue : MonoBehaviour {
public int blue;
void Start() {
blue = GameObject.Find("Object1").GetComponent<BlueScript>().blue;
}
void OnTriggerEnter (Collider other) {
blue = 1;
renderer.material.color = Color.blue;
}
}
void Update () {
if(blue == 0)
{
renderer.material.color = Color.red;
}
}
}
In other words, I want this GameObject to set the value of “blue” in Object1 to 1 when the trigger is fired, but I also want it to listen for when “blue” in Object1 is set back to 0. I can only get this to work if I do this:
using UnityEngine;
using System.Collections;
public class TurnBlue : MonoBehaviour {
public GameObject myObject;
void Start() {
myObject = GameObject.Find("Object1");
}
void OnTriggerEnter (Collider other) {
myObject.GetComponent<BlueScript>().blue = 1;
renderer.material.color = Color.blue;
}
void Update () {
if(myObject.GetComponent<BlueScript>().blue == 0)
{
renderer.material.color = Color.red;
}
}
}
In other words, if I assign a variable to the GetComponent in the Start routine, it is unable to set, or check for updates to, the value of “blue” in “BlueScript” in “Object1”. But it is able to do it if I assign a variable to “Object1”, then call GetComponent on it each time I need it. My question is, is it okay to be calling GetComponent in an Update? Any clarification most appreciated.
EN
I think the problem with your first example is that int is a value type, but you’re trying to treat it as a reference type. (Look up ‘c# value reference’ for more info.)
Your second example looks fine (based on a quick look at least). The only potential issue (that I’m aware of at least) with using GetComponent() on a per-update basis is performance, but if you’re not seeing any performance problems, I wouldn’t worry about it. (I would guess you’d be unlikely to see any impact on performance unless you were performing such queries many, many times per update.)
That said, you can cache references to components for re-use (just like game objects), so if you’re sure the target object is going to be staying around, you can just grab the component in your Start() function and use it wherever and whenever needed.
‘int’ is a value type. All the fundamental inbuilt types + structs and enums are value types. Value types are passed by value not reference.
So in your first example when you get the value of blue from the component you are doing just that. Gettting the value, not a reference to the value. When you update yor blue instance variable you are updating that value only. It is not a reference to the blue variable in your component.
Classes are always passed by reference, so a reference you keep to your component will refer to your component.
So while your second example works I would do the following instead.
using UnityEngine;
using System.Collections;
public class TurnBlue : MonoBehaviour {
public BlueScript myBlueScript;
void Start() {
myBlueScript= GameObject.Find("Object1").GetComponent<BlueScript>();
}
void OnTriggerEnter (Collider other) {
myBlueScript.blue = 1;
renderer.material.color = Color.blue;
}
void Update () {
if(myBlueScript.blue == 0)
{
renderer.material.color = Color.red;
}
}
}
[edit: either I type really slow or Jesse posted just after I started typing :p]
… and thanks Eagle32, that makes a lot of sense, and I had tried that based on some examples I’d found. I tried again using your suggested code, but I get the following error:
Assets/TurnBlue.cs(8,16): error CS0246: The type or namespace name `BlueScript' could not be found. Are you missing a using directive or an assembly reference?
where line 8 is the variable declaration. Why is this?
EN
[edit: the script actually works though, despite the error.]
Looks correct to me. I copy and pasted it into my test project and made a dummy BlueScript script.
Do you actually have a script called BlueScript? I assume you do from your examples.
I can get that error is if I mess with the compilation order by putting BlueScript somewhere so that it gets compiled after TurnBlue, so that might be your problem (would probably also happen if BlueScript is a UnityScript script instead of a C# script).
If BlueScript is a UnityScript rather than a C# script put it in Standard Assets somewhere and make sure TurnBlue is not is Standard Assets.
If they’re both c# scripts just move them to the same location if they aren’t already as a test.
Perfect, that fixed it, I had switched around “myBlueScript” and “BlueScript” - dumb mistake. Sorry to waste your time there, but thanks so much for the examples and explanation about value versus reference types, it’s really clear to me now, and also explains a lot of problems I’ve had in the past. Excellent learning experience, many thanks! Hopefully it will help future forum-seraching self-learners like me
EN