- Home /
Setting parent in instantiated class
I am trying to get bullets to fire from a parented position. In the Weapon.cs Awake() function I create 2 gunports, pass the parent transform and a Vector3 to offset the position from the parent. When I run the code I get the following error from GunPort.cs:
NullReferenceException GunPort..ctor (UnityEngine.Transform _owner, Vector3 _offsetPosition) (at Assets/GunPort.cs:37) Starfighter.Awake () (at Assets/Starfighter.cs:63)
This error points to where I set the transform.parent to the passed _owner.transform. I have done something similar with parenting a camera to physical object with success and I dont know why there is a problem with the way I have done it here. The _owner is not null as it suggests which I verified from using the statement Debug.Log(_owner.ToString());. Please excuse the Itallic text it is not intentional. The only difference is that my GunPort does not have a physical object, its invisible, as intended.
Weapon.cs:
void Awake () {
gunPort = GetComponent<GunPort>();
gunPorts = new GunPort[2];
gunPorts[0] = new GunPort(transform, new Vector3(-10, 0, 0));
gunPorts[1] = new GunPort(transform, new Vector3(10, 0, 0));
}
void CheckFiringPrimaryWeapon()
{
if(shipControls.IsFiringPrimary)
{
Bullet clone;
clone = Instantiate(bullet, gunPorts[0].Position, transform.rotation) as Bullet;
clone = Instantiate(bullet, gunPorts[1].Position, transform.rotation) as Bullet;
}
}
GunPort.cs:
public class GunPort : MonoBehaviour {
private Transform owner;
public Vector3 Position
{
get { return transform.position; }
}
public GunPort(Transform _owner, Vector3 _offsetPosition)
{
transform.parent = _owner.transform;
transform.localPosition =
(Vector3.right * _offsetPosition.x) +
(Vector3.up * _offsetPosition.y) +
(Vector3.forward * _offsetPosition.z);
}
}
Answer by syclamoth · Sep 27, 2011 at 06:26 AM
You shouldn't be using the Constructor on objects which derive from MonoBehaviour! The problem is that the object gets 'created' in a different way from how you would expect it to. Use Instantiate, and then pass in variables with an Init(Transform owner, Vector3 offset) method. Also, you don't need to use _owner.transform in your parenting line. _owner.transform will always return _owner, since it is already a transform! You may as well use
transform.parent = _owner;
It is more efficient, since it does not use component lookups like Component.transform does.
Ah, I see, thanks. Is there any way to instantiate the object without it needing to be attached to a GameObject, RigidBody, etc? As the GunPort will be invisible.
There is no need to attach a renderer to a gameObject, if you need it to be invisible! Just go GameObject -> Create Empty, and put your behaviours on that. If you don't need any of that GameObject stuff at all, then there's no need to inherit from $$anonymous$$onoBehaviour at all!
Answer by centaurianmudpig · Sep 27, 2011 at 02:59 PM
I think I get what you are saying though I am having some trouble trying to implement it. I'm quite new at unity so I hope you will bear with me. I created an empty GameObject, renamed it to GunPort, and attached my GunPort script to it.
In my Main.cs file I added:
public GameObject port;
Then attached the GunPort GameObject to it within the Unity Editor Inspector.
In the Awake() function I Instantiated the GunPorts as follows (where Init replaces the constructor from the OP in GunPort.cs):
gunPorts = new GunPort[2];
gunPorts[0] = Instantiate(port) as GunPort;
gunPorts[0].Init(transform, 1, new Vector3(10, 0, 0));
gunPorts[1] = Instantiate(port) as GunPort;
gunPorts[1].Init(transform, 1, new Vector3(-10, 0, 0));
The problem I have is that the Instantiate() does not return anything, as I get the error:
NullReferenceException: Object reference not set to an instance of an object Starfighter.Awake () (at Assets/Starfighter.cs:66)
The error happens on the Init() call, debugging shows that gunPorts[0] is null. I'm not sure what I have done wrong.
Answer by centaurianmudpig · Sep 27, 2011 at 02:58 PM
OK, I figured out where I went wrong. I should have created port as GunPort and not a GameObject. Thanks for your help in this.
Just fyi: Instantiate clones whatever object you provide as source as long it's derived from UnityEngine.Object. Instantiate will always return the same type that you provide. When you clone a Component like a script it automatically clones the owning GameObject and all attached components / subobjects. When cloning a GameObject it does the same but it will return a reference to the new GameObject.
However, if you want to create an empty GameObject with your script attached you can simply do:
GunPort newGunPort = (new GameObject()).AddComponent<GunPort>();
The GameObject constructor also allows to automatically add components by their type-object:
new GameObject("GO-name",typeof(GunPort));
But if you want a reference to the attached script you would have to call GetComponent so it's even more complicated:
GunPort newGunPort = (new GameObject("GO-name",typeof(GunPort))).GetComponent<GunPort>();