Unity: Instantiating prefab on GameObject - Error Object is null - unity3d

In my Unity game I have a vehicle prefab working with Edy's Vehicle Physics asset. I'm trying to instantiate a chosen vehicle prefab on the position and rotation of a GameObject.
When running my code in my scene to spawn a vehicle I get this error
ArgumentException: The Object you want to instantiate is null
ArgumentException: The Object you want to instantiate is null.
UnityEngine.Object.CheckNullArgument (System.Object arg, System.String message) (at C:/buildslave/unity/build/Runtime/Export/UnityEngineObject.cs:239)
UnityEngine.Object.Instantiate (UnityEngine.Object original, Vector3 position, Quaternion rotation) (at C:/buildslave/unity/build/Runtime/Export/UnityEngineObject.cs:151)
UnityEngine.Object.Instantiate[VehicleController] (EVP.VehicleController original, Vector3 position, Quaternion rotation) (at C:/buildslave/unity/build/Runtime/Export/UnityEngineObject.cs:206)
VehicleSpawner.spawnVehiclesInFirstGarage () (at Assets/Scripts/VehicleSpawner.cs:44)
HandleGarage.Start () (at Assets/Scripts/HandleGarage.cs:59)
Vehicle Prefab is empty because the vehicle will be chosen by the user in game. (Even if I select a vehicle prefab I still get same error)
My code for instantiating the vehicle prefab on the game object
public EVP.VehicleTelemetry telemetryComponent;
public EVP.VehicleController vehiclePrefab;
public GameObject spawnObject;
public void spawnVehiclesInFirstGarage ()
{
// Load saved JSON
string jsonData = SecurePlayerPrefs.GetString ("vehicleNames");
// Convert to Class
Database loadedData = JsonUtility.FromJson<Database> (jsonData);
// Loop through Owned Vehicles Garage
for (int i = 0; i < loadedData.vehicleNames.Count; i++) {
// Set up instantiate
var vehicle = Resources.Load("Prefabs/" + (loadedData.vehicleNames [i]));
vehiclePrefab = vehicle as EVP.VehicleController;
// Spawn vehicle on game object
EVP.VehicleController newVehicle = Instantiate(vehiclePrefab, spawnObject.transform.position, spawnObject.transform.rotation) as EVP.VehicleController;
telemetryComponent.target = newVehicle;
}
}

Possible Solutions
The vehiclePrefab = vehicle as EVP.VehicleController; could be causing problems, as logging var vehicle = Resources.Load("Prefabs/" + (loadedData.vehicleNames [i]));, already gives Sport Coupe (UnityEngine.GameObject), which is the correct type.
Instead of using as EVP.VehicleController, try:
// Set up instantiate
var vehiclePrefab = Resources.Load("Prefabs/" + (loadedData.vehicleNames [i])) as GameObject;
// Spawn vehicle on game object
GameObject newVehicle = Instantiate(vehiclePrefab, spawnObject.transform.position, spawnObject.transform.rotation);
EVP.VehicleController controller = newVehicle.GetComponent<EVP.VehicleController>();
telemetryComponent.target = newVehicle;
This is from Unity's documentation for loading prefabs via scripting.
From the error message, it seems that spawnVehiclesInFirstGarage() is being called in void Start(). If so, try putting it in the void Update(), adding a if( prefab != null && !isInstantiated) check.
Additional Troubleshooting (if the solutions don't work)
Try assigning a prefab via the inspector and see if you get the same problem.
On your existing code, try Debug.Log(vehiclePrefab).

Related

How to destroy instanciated game object and creat it again?

I'm making a solitaire game and I strugle with one functionality.
In time of player is clicking on deck cards appears in discard pile. They are created in factory :
[SerializeField]private GameObject prefab;
public void Create(Transform parent, float zOffset, float yOffset, CardModel model, bool isCovered, bool isLast, string pileName, GameObject curretPile, ActionsManager manager)
{
GameObject instance = Instantiate(prefab, new Vector3(parent.position.x, parent.position.y - yOffset, parent.position.z - zOffset), Quaternion.identity, parent);
this.model = model;
this.view = instance.GetComponent<CardView>();
this.controller = GetComponent<CardController>();
instance.GetComponent<CardController>().SetModel(this.model);
instance.GetComponent<CardController>().SetView(view);
string spriteName = (instance.GetComponent<CardController>().ReturnValue()).ToString() + instance.GetComponent<CardController>().ReturnSuit();
Sprite faceingSprite = uncoverSprite.Find(item => item.name == spriteName);
instance.GetComponent<CardController>().SetUncoveredSprite(faceingSprite);
instance.GetComponent<CardController>().SetPileName(pileName);
instance.GetComponent<CardController>().SetIsCoveredBool(isCovered);
instance.GetComponent<CardController>().SetIsLastInPile(isLast);
instance.GetComponent<CardController>().SetActionsManager(manager);
instance.GetComponent<CardController>().SetCurrentPile(curretPile);
When all cards are created to discard pile and player click again on deck it sends action with demand of the list of card from discard pile, they are returning to deck and they are destroy in discard pile.
public void OnCardDemand()
{
List<CardModel> list = ReturnList();
RemoveAllElementsFromList();
if(OnDeckSend != null)
{
OnDeckSend(list);
}
CardController[] cards = gameObject.GetComponentsInChildren<CardController>();
foreach(CardController card in cards)
{
Destroy(card.gameObject);
}
}
Cards should be instatiated again after clicking on deck pile but there is an error :
MissingReferenceException: The object of type 'SpriteRenderer' has been destroyed but you are still trying to access it.
How can I destroy cards without any error?
It's a deck of cards - I wouldn't try to continuously create and destroy them, just assign new transform parents and set local positions to zero if you want to move them. I'd also recommend using SetActive(false) instead of destroying, then you can use SetActive(true) to "create" them back - this is along the lines of an object pool.
Ultimately the problem is that you've cached a reference to a Component on the GameObject that you're deleting, Wherever you're using the SpriteRenderer you need a null check, or else you need a more sophisticated way to unsubscribe that reference in OnDestroy for the GameObject your destroying.

Is there a way to make an instantiated text follow a game object?

I'm currently experiencing a coder's block right now as I'm trying to instantiate text on a game object, specifically a Zombie prefab. I've gotten down the enemy's position for the text to be spawned but can't seem to make it follow the zombie's movement as it walks towards the player.
This is my 'Word Spawner' script.
public GameObject wordpb; // my word prefab
public Transform canvas; // connected to a canvas ui that has world camera set
public EnemyOne enemy;
public DisplayWord Spawn()
{
Vector2 targetPos = new Vector2(enemy.transform.position.x, enemy.transform.position.y);
GameObject wordobj = Instantiate(wordpb, targetPos, Quaternion.identity, canvas);
DisplayWord displayWord = wordobj.GetComponent<DisplayWord>();
return displayWord;
}
and this is where the DisplayWord class is derived from.
public Text text;
public void SetWord(string word)
{
text.text = word;
}
public void ThrowLetter()
{
text.text = text.text.Remove(0, 1);
text.color = Color.red;
}
public void ThrowWord()
{
Destroy(gameObject);
}
My best guess is that I should be implementing a void Update method in which I use transform.Translate? Or should I put a placeholder that acts as a child class to my Zombie prefab and attach the DisplayWord script there? Please help a poor soul out.
How does the text relate to the Zombie game object? Knowing what the text is for in relation to the zombie might inform the best way to make it follow the game object.
If the text is something like a worldspace nametag, instead of translating in Update you could make the text a child of the game object it needs to follow. It might not be the most elegant solution but if you give each text its own worldspace canvas you could assign the text as a child of the zombie, or, if you know you'll always have text following a zombie, you could just add a worldspace canvas and text to the zombie prefab...
To instantiate as a child you'd need to rework your word prefab to be its own worldspace canvas with your text as its child.
You can assign a parent when you instantiate:
wordobj = Instantiate(wordpb, enemy);
Or set the parent after instantiation:
wordobj.transform.SetParent(enemy.gameObject.transform, true);
The second parameter in SetParent is 'worldPositionStays', and controls whether the child object keeps its world position (true) or whether it's transform is evaluated relative to its new parent's transform. You could make it work either way: if you leave it 'true' you don't need to change the rest of your code, but I think if you make it false you don't need to get the enemy GameObject's position... The same is true for Instantiate when a parent is assigned but no transform position/rotation. So I think you could skip the step of finding the enemy's position and rewrite your Spawn code to:
public GameObject wordpb; // my word prefab
public EnemyOne enemy;
public DisplayWord Spawn()
{
GameObject wordobj = Instantiate(wordpb, enemy, false);
DisplayWord displayWord = wordobj.GetComponent<DisplayWord>();
return displayWord;
}
You'd need to assign the newly instantiated canvas's worldspace camera to make this work...

ArgumentException: GetComponent requires that the requested component 'GameObject' derives from MonoBehaviour or Component or is an interface

I tried to make a system so that it would analyse all of the children of a given parent and based on one of the children whom is active, decide upon what the forward and right of that child is:
Vector3 camF = new Vector3(0,0,0);
Vector3 camR = new Vector3(0,0,0);
//Assign active camera to current cam.
GameObject[] cameras = GetComponentsInChildren<GameObject>();
foreach (GameObject currentCam in cameras)
{
if (currentCam.activeInHierarchy)
{
camF = currentCam.transform.forward;
camR = currentCam.transform.right;
}
}
While the game does boot, I cannot move my character, and keep on getting this error message:
ArgumentException: GetComponent requires that the requested component 'GameObject' derives from MonoBehaviour or Component or is an interface.
UnityEngine.GameObject.GetComponentsInChildren[T] (System.Boolean includeInactive) (at <58a34b0a618d424bb5fc18bb9bcdac20>:0)
UnityEngine.Component.GetComponentsInChildren[T] (System.Boolean includeInactive) (at <58a34b0a618d424bb5fc18bb9bcdac20>:0)
UnityEngine.Component.GetComponentsInChildren[T] () (at <58a34b0a618d424bb5fc18bb9bcdac20>:0)
PerspectiveControls.Update () (at Assets/Scripts/Character/PerspectiveControls.cs:32)
The problem is you're using GetComponent method but GameObject is not a component. On the other hand, transform contains all the children. So, in order to get children Transforms, you can use this:
foreach (Transform child in transform)
And in order to reach the GameObject, you can do this:
child.gameObject

Is there a way to specify where a game object spawns in the hierarchy in unity?

I have set up a random spawner that creates new game objects but they are being created outside of my canvas and therefore can't be seen when play the game. Is there any way to fix this? The objects 'neg thoughts' are UI Buttons and are being created outside of the canvas even though I need them to appear on screen so they can be used.
I did see a similar question but the suggestions didn't work for my problem.
this is very frustrating for me and any help would be awesome!
You can simply pass the parent into Instantiate
parent Parent that will be assigned to the new object
var newObj = Instantiate(prefab, parentTransform);
or with additional transforms
var newObj = Instantiate (prefab, position, rotation, parentTransform);
Or as others already said you can still do it afterwards at any time either by simply assigning a new transform.parent
newObj.transform.parent = parentTransform;
or using transform.SetParent
newObj.transform.SetParent(parentTransform, worldPositionStays);
The advantage of the later is that you have an optional parameter worldPositionStays
worldPositionStays If true, the parent-relative position, scale and rotation are modified such that the object keeps the same world space position, rotation and scale as before.
assigning a new
transform.parent = parentTransform;`
will always act the same way as
transform.SetParent(parentTransform);
since the default value for worldPositionStays (so if you don't explicitly pass it) is true.
So for the specific case of UI in a Canvas you could use
public TheSpawnComponent : MonoBehaviour
{
// Via the Inspector drag&drop any object here that is inside the canvas
// or the canvas itself
[SerializeField] private GameObject parentInCanvas;
[SerializeField] private Button buttonPrefab;
public void DoInstantiate()
{
var newButton = Instantiate (buttonPrefab, parentInCanvas);
//Todo Position and callback
}
}
Or if the spawner script is attached to an object inside the canvas anyway you could also spawn as child of this one directly using
var newButton = Instantiate(buttonPrefab, transform);
You can specify the transforms parent after you have created the game object.
spawnedObject.transform.parent = canvas.transform;
You have to use below code
public GameObject Prefab; // Object to Create
public Transform ParentOfObj;// Must Be inside the canvas or canvas it self
void Start()
{
GameObject g = Instantiate(Prefab) as GameObject;
g.transform.SetParent(ParentOfObj);
g.transform.localScale = Vector3.one;
}

Unity Spawning child with client authority

I'm currently learning how this whole networking thing works in unity. In my code I'm creating a spaceship made from multiple prefabs.
It all starts with a single Hardpoint. A Hardpoint can hold a single object, which will be instantiated later on in the loop.
In the PlayerController (the starting point) i have this code to spawn the first object, the cockpit:
[Command]
void CmdOnConnect() {
string json = GameObject.Find("TestPlayer").GetComponent<ComponentObject>().ToJSON();
CompressedComponent compressedComponent = JsonUtility.FromJson<CompressedComponent>(json);
gameObject.GetComponent<Hardpoint>().Hold(GameObject.Find("Component Repository").GetComponent<ComponentRepository>().cockpit[compressedComponent.componentNumber]);
gameObject.GetComponent<Hardpoint>().SpawnComponent();
gameObject.GetComponent<Hardpoint>().RollThroughDecompression(compressedComponent);
Camera.main.GetComponent<PlayerCamera>().player = gameObject;
}
Next up is the SpawnComponent() code, located in the Hardpoint script:
public void SpawnComponent() {
Clear();
CmdSpawn();
}
CmdSpawn, also located in Hardpoint:
[Command]
public void CmdSpawn()
{
Debug.Log("[COMMAND] Spawning " + holds.name);
heldInstance = Instantiate(holds, transform.position, transform.rotation) as GameObject;
heldInstance.transform.SetParent(transform);
NetworkServer.SpawnWithClientAuthority(heldInstance, transform.root.gameObject);
}
And finally RollThroughDecompression, which just calls the Decompress() function:
public void RollThroughDecompression(CompressedComponent c) {
heldInstance.GetComponent<ComponentObject>().Decompress(c);
}
And just to leave no information out, Decompress():
public void Decompress(CompressedComponent c) {
componentType = (Type)Enum.Parse(typeof(Type), c.componentType);
componentNumber = c.componentNumber;
UpdateHardPoints();
GameObject[] typeRepository = GetRepository(componentType);
//update children
int point = 0;
foreach (Transform child in transform)
{
Hardpoint hardpoint = child.GetComponent<Hardpoint>();
if (hardpoint != null) {
if (c.hardpoints[point] != null) {
//get the hardpoint's repository
GameObject[] hardpointRepo = GetRepository((Type)Enum.Parse(typeof(Type), c.hardpoints[point].componentType));
//set the hardpoint to hold this object
hardpoint.Hold(hardpointRepo[c.hardpoints[point].componentNumber]);
hardpoint.SpawnComponent();
hardpoint.RollThroughDecompression(c.hardpoints[point]);
point++;
}
}
}
}
Sorry the code's a little messy/confusing but I've been driven up the walls trying to figure out why newly spawned objects don't have client authority with the exception of the first object spawned (likely because it's called from the PlayerController). I've been stuck on this problem for days now. Newly spawned objects are being set as children of the local player object and are even spawned with NetworkServer.SpawnWithClientAuthority yet when testing:
Trying to send command for object without authority. when calling CmdSpawn().
NetworkManager:
The result i'm getting:
As you can see, the cockpit (very first part) gets spawned as expected. but parts mounted on those Hardpoints don't. To clarify, the EmptyHardpoint is just that. A hardpoint with no children, just an empty game object with the hardpoint script and playercontroller attached to it. The cockpit prefab also includes the img and hardpoints
I guess you have forget to add your child Spawn in the Spawn list of NetworkManager.