- Home /
Calling GetComponent on an instantiated prefab returns null,Calling GetComponent on an instantiated prefab
This seems to be a common problem but I haven't found a solution to it yet.
I'm trying to create an enemy that can shoot projectiles at the player, so the projectile is a prefab which has a script named "attack" with the public method "shoot", and the enemy script has a public variable with the prefab GameObject Attack. Whenever I instantiate a new Attack GameObject atk then call atk.GetComponent() it returns null.
This only happens specifically with instantiated prefabs. When I use an Attack GameObject that's already on the scene I'm able to get the attack script. It also seems to only apply to scripts, since calling GetComponent on any pre-built components like Rigidbody2D was successful.
Edit: example code that doesn't work
public class Enemy : MonoBehaviour
{
public GameObject attack; //the Attack prefab
void Start() {}
void Update() {}
void spawnAttack()
{
GameObject a = Instantiate(attack, transform.position, Quaternion.identity);
a.GetComponent<AttackScript>().shoot(new Vector2(10f, 10f)); // this gets null reference exception
}
}
public class AttackScript : MonoBehaviour
{
Rigidbody2D rb;
void Start()
{
rb = GetComponent<Rigidbody2D>();
}
void Update() {}
public void shoot(Vector2 direction) {
rb.velocty = direction;
}
}
code that does work:
// this works:
public GameObject attack; //the GameObject I dragged on-screen
void Start() {
attack.GetComponent<AttackScript>().shoot(new Vector2(10f, 10f));
}
// this also works:
public GameObject attack; //the Attack prefab
void spawnAttack() {
GameObject a = Instantiate(attack, transform.position, Quaternion.identity);
a.GetComponent<Rigidbody2D>().velocity = new Vector2(10f, 10f);
}
Try forcing the type of the prefab to have a Attack
component
public class Enemy : $$anonymous$$onoBehaviour
{
public AttackScript attack; //the Attack prefab
void spawnAttack()
{
AttackScript a = Instantiate(attack, transform.position, Quaternion.identity);
a.shoot(new Vector2(10f, 10f));
}
}
It looks like this would just create a new instance of the script object. I want to instantiate a new attack GameObject with attached sprite, collider, etc. Is there a way to force the type without sacrificing that?
No, you will provide the prefab in the inspector, and calling Instantiate
will duplicate the whole object with all the other components and children.
Answer by Bunny83 · Nov 08, 2019 at 07:28 PM
Well the exact NullReference Exception would actually help. Because it's most likely not the call to shoot()
that is causing the NullReference exception but inside shoot your access to velocity because your variable "rb" is null.
You initialize "rb" inside Start. However Start is called before the next Update callback is called. So it will of course not be called between your call of Instantiate and your shoot() call. Therefore rb is still null when you call shoot(). You should use Awake to initialize such internal references. However it would actually be easier to make the rb variable public and assign the reference in the inspector of the prefab. That way you don't need the GetComponent call at all.
Note that Awake will be called immediately when the object is created. So it will be called from inside the Instantiate call or when created dynamically from inside the AddComponent call. That means Awake will be finished before Instantiate returns and therefore before you call shoot().
Note that if this doesn't solve your issue, then your AttackScript is not attached to the root object of your prefab. GetComponent will only look for components on that gameobject, not for components on nested child objects.
That was exactly it, thank you! I added the Rigidbody as a public variable and that solved the issue.