Getting a NullReferenceException when trying to Instantiate a GameObject - c#

I'm programming a JRPG off of a tutorial online to try and learn Unity and C# code. This is a program for creating a menu of enemy units to attack:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
//using UnityEngine.Experimental.UIElements;
public class CreateEnemyMenuItem : MonoBehaviour {
[SerializeField]
private GameObject targetEnemyUnitPrefab;
[SerializeField]
private Sprite menuItemSprite;
[SerializeField]
private Vector2 initialPosition, itemDimensions;
[SerializeField]
private KillEnemy killEnemyScript;
private void Awake()
{
GameObject enemyUnitsMenu = GameObject.Find("EnemyUnitsMenu");
GameObject[] existingItems = GameObject.FindGameObjectsWithTag("TargetEnemyUnit");
Vector2 nextPosition = new Vector2(this.initialPosition.x + (existingItems.Length * this.itemDimensions.x), this.initialPosition.y);
GameObject targetEnemyUnit = Instantiate(this.targetEnemyUnitPrefab, enemyUnitsMenu.transform) as GameObject;
targetEnemyUnit.name = "Target" + this.gameObject.name;
targetEnemyUnit.transform.localPosition = nextPosition;
targetEnemyUnit.transform.localScale = new Vector2(0.7f, 0.7f);
targetEnemyUnit.GetComponent<Button>().onClick.AddListener (() => selectEnemyTarget());
targetEnemyUnit.GetComponent<Image>().sprite = this.menuItemSprite;
killEnemyScript.menuItem = targetEnemyUnit;
}
public void selectEnemyTarget()
{
}
}
At line 29 (where targetEnemyUnit is instantiated) during game tests I get a NullReferenceException error which I figure means Instantiate isn't working (it also highlights here but doesn't in Visual Studio). I'm working largely off of a tutorial but this matches and I'm not sure what exactly I'm doing wrong here.

Either targetEnemyUnitPrefab was not set in the inspector, in which case you just need to click on the GameObject that contains this script, in the inspector drag and drop your prefab into 'targetEnemyUnitPrefab' or enemyUnitsMenu was not tagged properly, in which case click on the 'GameObject' that is supposed to be tagged and make sure in the top right of the inspector it is tagged as 'EnemyUnitsMenu'
note when you create a new tag and have a game object selected it doesn't apply the tag, you have to go back to the game object and select it from the bottom of the drop down.
GameObject targetEnemyUnit = Instantiate(this.targetEnemyUnitPrefab, enemyUnitsMenu.transform) as GameObject;

okay you have a private object as a prefab ->
private GameObject targetEnemyUnitPrefab <-
and you didnt put anything in that prefab so its nothing. so you are getting nullreference exception because of it.
make a public game object prefab and drag your prefab on it.
Or make something like this before instatiate the object ~ targetEnemyUnitPrefab= GameObject.Find("targetEnemyUnitPrefab");~ or whatever tag it has.
have a nice day.

Related

Unity Transform not updating position realtime

I am trying to create a simple scriptable object for my shoot ability. I have that aspect working, but as I try to set my Transform to my player, it does not update the shoot position. I am very new to C#, and this script isnt complete. I still need to add the functionality to destroy the created objects. Any help would be greatly appreciated. I suspect I need to add an update function but im am not certain how to do this.
using UnityEngine.InputSystem;
using UnityEngine.AI;
using UnityEngine;
namespace EO.ARPGInput
{
[CreateAssetMenu]
public class Shoot : Ability
{
public Transform projectileSpawnPoint;
public GameObject projectilePrefab;
public float bulletSpeed = 10;
public float bulletLife = 3;
public override void Activate(GameObject parent)
{
var projectile = Instantiate(projectilePrefab, projectileSpawnPoint.position, projectileSpawnPoint.rotation);
projectile.GetComponent<Rigidbody>().velocity = projectileSpawnPoint.forward * bulletSpeed;
Destroy(projectile, bulletLife);
void OnCollisionEnter(Collision collision)
{
Destroy(projectile);
}
}
}
}
I'm still new to Unity and coding also, so take my advice with a load of salt :P.
It may be best to have a transform on your character (say just past the barrel of the player's gun) that you can put as the projectileSpawnPoint. In your code the projectileSpawnPoint is never set. Your first line of code in the "Activate" method should be something like:
public override void Activate(GameObject parent)
{
projectileSpawnPoint = playerGunBarrelTransform.transform.position;
var projectile = Instantiate(projectilePrefab, projectileSpawnPoint.position, projectileSpawnPoint.rotation);
projectile.GetComponent<Rigidbody>().velocity = projectileSpawnPoint.forward * bulletSpeed;
Destroy(projectile, bulletLife);
For destroying the projectile afterward you can keep it as you have it in OnCollision. howeer, with bullets in particular, since they tend to be instantiated A LOT and then destroyed afterward it would be best to use an object pooler for them to instantiate several of them on start and then disable and enable them as needed so you can resuse them instead of making new ones every time.
you have to create a new script that derives from Monobehaviour for your projectiles. attach that script to the projectile prefab and place the OnCollisionEnter method in that script. now your projectiles should get destroyed when touching another collider. make sure that there is a rigidbody component attached to the projectile.

Score Count not working on a prefab

This is semi complicated of a question but I'll do my best to explain it:
I am making this mobile game in which you have to shoot four cubes. I'm trying to make it so when the cubes are shot by a bullet, they're destroyed and a UI text says 1/4, to 4/4 whenever a cube is shot. But it's being really weird and only counts to 1/4 even when all four cubes are shot and destroyed. I put these two scripts on the bullets (I made two separate scripts to see if that would do anything, it didn't)
And to give a better idea of what I'm talking about, here's a screenshot of the game itself.
I've been using Unity for about 6 days, so I apologize for anything I say that's noob-ish.
EDIT
So I combined the two scripts onto an empty gameobject and here's the new script:
using UnityEngine;
using System.Collections;
using UnityEngine.UI;
public class GameManagerScript : MonoBehaviour {
public GameObject cubes;
public Text countText;
public int cubeCount;
public Transform target;
// Use this for initialization
void Start () {
}
void OnTriggerEnter(Collider other)
{
cubes = other.gameObject;
}
// Update is called once per frame
void Update () {
cubes.transform.position = Vector3.MoveTowards(transform.position, target.position, 1f * Time.deltaTime);
if (cubes.gameObject.tag == "BULLET")
{
cubeCount = cubeCount + 1;
countText.text = cubeCount + "/4";
cubes.SetActive(false);
}
}
}
ANOTHER EDIT
I tried everything, so is there a way to detect when all the children in a parent on the Hierarchy are destroyed? Instead of counting up? This can give a better idea:
So I want to be able to detect when Cube, Cube1, Cube2, and Cube3 have all been destroyed.
The answer is pretty simple: Since every individual bullet has that script, each bullet has its own score.
For something like a score you want a single spot to store it, e.g. a script on an empty gameobject that serves as game controller. Just access that in the collision and increase the score (maybe have a look on singletons here).
You can combine those two scripts and actually it might be better to not have this on the bullet, but on the target because there are probably less of them which will save you some performance. (And it does more sense from a logical point of view.)
Edit:
I assume you create the bullets using Instantiate with a prefab. A prefab (= blueprint) is not actually in the game (only objects that are in the scene/hierarchy are in the game). Every use of Instantiate will create a new instance of that prefab with it's own version of components. A singleton is a thing that can only exist once, but also and that is why I mention it here, you can access it without something like Find. It is some sort of static. And an empty gameobject is just an object without visuals. You can easily create one in unity (rightclick > create empty). They are typically used as container and scriptholders.
Edit:
What you want is:
An empty gameobject with a script which holds the score.
A script that detects the collision using OnTriggerEnter and this script will either be on the bullets or on the targets.
Now, this is just a very quick example and can be optimized, but I hope this will give you an idea.
The script for the score, to be placed on an empty gameobject:
public class ScoreManager : MonoBehaviour
{
public Text scoreText; // the text object that displays the score, populate e.g. via inspector
private int score;
public void IncrementScore()
{
score++;
scoreText.text = score.ToString();
}
}
The collision script as bullet version:
public class Bullet : MonoBehaviour
{
private ScoreManager scoreManager;
private void Start()
{
scoreManager = GameObject.FindWithTag("GameManager").GetComponent<ScoreManager>(); // give the score manager empty gameobject that tag
}
private void OnTriggerEnter(Collider other)
{
if(other.CompareTag("Target") == true)
{
// update score
scoreManager.IncrementScore();
// handle target, in this example it's just destroyed
Destroy(other.gameObject);
}
}
}

Object Shoots On x-z Axis

I actually have 2 issues. The first problem I have is that when I start my game all 4 cannons do their animation sequence for no reason, nothing happens. I'd like this to not happen. The second problem I have is the cannon ball that shoots out spawns on the floor and flies along the floor. Here is the code for the firing sequence:
using UnityEngine;
using System.Collections;
public class Cannon : MonoBehaviour {
public AudioClip sound;
public GameObject prefab;
public GameObject ejectPoint;
void Start () {
prefab = Resources.Load ("Cannon_Ball") as GameObject;
}
public void Fire () {
GameObject Cannon_Ball = Instantiate (prefab) as GameObject;
Cannon_Ball.transform.position = transform.position + ejectPoint.transform.forward * 2;
Rigidbody rd = Cannon_Ball.GetComponent<Rigidbody> ();
rd.velocity = ejectPoint.transform.forward * 130;
AudioSource.PlayClipAtPoint(sound, transform.position, 1);
GetComponent<Animation> ().Play ();
}
}
Here is a GIF of the problem:
fix 1: Uncheck 'Play Automatically' or find equal option in your Animator. I think after you start game, your Animator change his state from "Start" to "Shoot" because of bad conditions setting or even totally lake of conditions . If you paste here screenshot of your animator, that would be useful.
If you want to fix your second problem you should watch this video:
BRICK SHOOTER - Official Unity Tutorial

Audio doesn't play when instantiate new object

I'm facing audio problems in my project. There are three paddle game objects and one cube. Cube has Rigidbody2d or BoxCollider2d. And there is also a button script attach to cube which has button function when we click on button cube Kinematic becomes false and drop on the paddle. When it's collide with any paddle cube destroy and instantiate again with new prefab. When Cube is falling sound is play and cube is destroy. New cube is instantiate when again click on button then error came.
MissingReferenceException: The object of type AudioSource has been destroyed but you are still trying to access it. Your script should either check if it is null or you should not destroy the object.
Scripts on all paddles:
public class Paddle : MonoBehaviour
{
[SerializeField]
private AudioSource source;
[SerializeField]
private AudioClip hit;
[SerializeField]
private BoxCollider2D collide;
[SerializeField]
private GameObject Clone;
void Awake()
{
collide.isTrigger = true;
}
void OnTriggerEnter2D(Collider2D target)
{
source.PlayOneShot(hit);
Destroy(target.gameObject);
Instantiate(Clone, new Vector3(0f, 4.51f, 0f), Quaternion.identity);
}
}
Cube Script:
public class Cube : MonoBehaviour
{
[SerializeField]
private AudioSource source;
[SerializeField]
private Rigidbody2D body;
[SerializeField]
private AudioClip play;
private Button bt;
private float pos;
public bool check;
void Start()
{
bt = GameObject.FindGameObjectWithTag("Button").GetComponent<Button>();
bt.onClick.AddListener(Fire);
body.isKinematic = true;
}
void Update()
{
if (check)
{
return;
}
Vector3 temp = transform.position;
pos = Camera.main.ScreenToWorldPoint(Input.mousePosition).x;
temp.x = Mathf.Clamp(pos, -6.25f, 6.25f);
body.position = temp;
}
public void Fire()
{
GameObject.FindGameObjectWithTag("Player").GetComponent<Cube>().check = true;
GameObject.FindGameObjectWithTag("Player").GetComponent<Rigidbody2D>().isKinematic = false;
source.PlayOneShot(play);
}
}
Cube image:
Paddles image:
New Export package:
https://drive.google.com/file/d/0B1H5fdK2PJAnSXVPdmE5Z3J1SUU
Problem in Video:
https://drive.google.com/file/d/0B1H5fdK2PJAnYzRfVnlQT1FyTlE
Your linked package works fine, it does play the sound every time I launch and destroy a cube.
Nonetheless, you should remove the method on destroy. Unity does not throw any error nor warning when a non-persistent listener is null, kinda weird but this is how it is. You should remove it manually:
void OnDestroy(){
bt.onClick.RemoveListener (Fire);
}
But your package does not throw any error when I run it.
Though, I would rethink your approach, instead of the cube assigning its Fire method to the Button event, I would have a script on the button containing the Fire method as well as the AudoiSource and clip. Then on Start, the Cube would pass itself so that the button could access its Cube and Rigidbody2D component.
Best would be to pass a class that contains those are members:
public class CubeArgument{
public readonly Rigidbody2D rg = null;
public readonly Cube cube = null;
public CubeArgument(Rigidbody2D rg, Cube cube){
this.rg = rg;
this.cube = cube;
}
}
then here goes your Cube start method:
void Start () {
bt = GameObject.FindGameObjectWithTag ("Button");
bt.GetComponent<ButtonController> ().Init(new CubeArgument(body, this));
body.isKinematic = true;
}
The ButtonController reference could even be made static since there is only one for the whole level.
and then on the button you have a ButtonController:
public class ButtonController : MonoBehaviour{
Cube currentCube = null;
Rigodbody2D currentRig = null;
public void Init(CubeArgument ca){
currentRig = ca.rg;
currentCube = ca.cube;
}
public void Fire(){
if(currentCube != null){ currentCube.check = true; }
if(currentRig != null) { currentRig.isKinematic = false; }
}
}
Fire is passed as listener to the Button onClick and this is it.
your problem can be from many different places. my guesses:
1)problem with your build: rebuild your code or export all of your package to new project and retest.
2)your target framework: latest version of unity(i have 5.1) just support to .net 3,5 and unity 4.x supports 2,5 i think. so chek your target framework to not to use functions that is not functional in your version
3)settings of your platform that your editor is running on: it can be volume of your platform to many other settings, first option to know that is run your project on other machine (maybe its a unity bug that part of code is not good for your hardware or driver on platform)
Edit: OP was using version 5.1.1. This error does not repeat after Unity 5.2.
Tried your package and it is working fine!
No errors. Audio played when instantiated.
Are you still facing errors? Weird, dude. Sounds like something is not clean enough.
Maybe there is some issue with your build.
Few things you could try:
1- Try restarting your Unity. Maybe this will force Clean things.
2- Create a new project and import your own package to test it!
3- I'm using Unity 5.3.0f4 what Unity version are you using? Try an update.
If none of above works, there is something wicked going on with your AudioSource reference and I can't help you with my actual knowledge. But still we can try to do different approaches for that.
Instead of physically referenced it (Dragging and dropping), do it at the start of your script.
Desperate approach 1
On Cube.cs:
First remove [SerializeField] located above of private AudioSource source; and add the following line on the Start() method:
source = gameObject.GetComponent<AudioSource> ();
Practically the same, but now the script is referencing the own object Audio Source for you. Do the same approach with Paddle.cs. [remember to check the audio name when applying the approach for Paddle script. On paddle the audio name is PlayOneShot (hit) not PlayOneShot (play)].
If this still trigger some error. Let's try another approach.
Desperate approach 2
On Cube.cs:
Remove/Comment the following line on Fire() method:
source.PlayOneShot (play);
Add the following line to Fire() method:
gameObject.GetComponent<AudioSource> ().PlayOneShot (play);
This will get your actual AudioSource on the go. Do the same approach on Paddle.cs [remember to check the audio name when applying the approach for Paddle script. On paddle the audio name is PlayOneShot (hit) not PlayOneShot (play)].

Unity3d MeshRender

I'm trying to use C# to disable and enable the MeshRender component in Unity3d however I am getting the following error,
error CS0120: An object reference is required to access non-static member `UnityEngine.GameObject.GetComponent(System.Type)'
The line of code I am using is below. I'm using this in the same function.
MeshRenderer showZone = GameObject.GetComponent<MeshRenderer>();
Also I'm posting here rather than Unity Answers as I get a far faster response here and it's always useful information regardless of the outcome.
You're having trouble with several problems. First, you are trying to use GetComponent<> on a class instead of an instance of an object. This leads directly to your second problem. After searching for a specific GameObject you're not using the result and you're trying to disable the renderer of the GameObject containing the script. Third, C# is case-sensitive, Renderer is a class while renderer is a reference to an instance of Renderer attached to the GameObject
This code snippet combines everything: find the GameObject and disable its renderer
GameObject go = GameObject.FindWithTag("zone1");
if (go != null) { // the result could be null if no matching GameObject is found
go.renderer.enabled = false;
}
You could use go.GetComponent<MeshRenderer>().enabled = false; instead of go.renderer. enabled = false; But by using renderer you don't need to know what kind of renderer is used by the GameObject. It could be a MeshRenderer or a SpriteRenderer for example, renderer always points to the renderer used by the GameObject, if there exists one.
My friend. Just try use lowercase gameObject instead of GameObject and renderer instead of Renderer
The main problem that you try access Static class variable, using the name of class instead of class instance.
Class names here are GameObject and Renderer
And instances are gameObject and renderer
MeshRenderer showZone = GetComponent<MeshRenderer>();
delete the 'GameObject.'
GameObject is a type. What you want is in an instance of a gameObject to call GetcComponent on. Thats what the error is about.
Which for note, this:
MeshRenderer showZone = GetComponent<MeshRenderer>();
is the exact same as this:
MeshRenderer showZone = this.GetComponent<MeshRenderer>();
You are calling GetComponent on the GameObject instance of which the script is attached to.
your code should look like this:
MeshRenderer showZone = GetComponent<MeshRenderer>();
Like others already wrote, you need to get an instantiated GameObject. You call the base class GameObject where only static functions can be called which do not need a GameObject in the SceneView.
gameObject IS AN instance.You get the instance of the GameObject the Monobehaviour is added to. Calling the function GetComponent without any object is the same as:
this
gameObject
GameObject IS NO instance.
Be careful at the first letter!
Look documentation:
using UnityEngine;
using System.Collections;
public class ExampleClass : MonoBehaviour {
void Example() {
renderer.enabled = false;
}
}
Link: http://docs.unity3d.com/ScriptReference/Renderer-enabled.html
Changing of programming languages upper-right.
2 ways you can solve the Problem either. You add the word static to the method that is calling your statement.
ex :
public static GetTheMesh(){}
I do not recommend on doing this cause. If you have other calls inside the method that needs to access Instance, this will cause you trouble.
Second way of fixing it is make a pointer or reference first before getting the component. Or use the GameObject.Find <= which is slow if.
showZone = GameObject.Find("TheGameObjectName").GetComponent<MeshRenderer>();
If you want to disable the renderer on this gameObject then use:
this.GetComponent<Renderer>().enabled = false;
If it's not this gameObject then use:
GameObject.FindGameObjectWithTag("your_tag").GetComponent<Renderer>().enabled = false;
Or you could give the object manually:
public GameObject go;
go.GetComponent<Renderer>().enabled = false;
https://docs.unity3d.com/ScriptReference/Renderer-enabled.html
you can use two types of peace of code for access MeshRenderer enable and disable
1> create GetMeshRenderer script (script name as you want) attached to empty game-object into the scene and assign Cube or sphere or any 3d object as u want to enable and disable.
************************************** Code ***************************
using UnityEngine;
using System.Collections;
public class GetMeshRenderer : MonoBehaviour
{
public MeshRenderer ShowZone;
void Start ()
{
}
// Update is called once per frame
void Update ()
{
if(Input.GetKey(KeyCode.Y))
{
ShowZone.enabled = true;
}
if(Input.GetKey(KeyCode.N))
{
ShowZone.enabled = false;
}
}
}
2>
attach below peace of code script to any 3d object like sphere ,cube
*************************** code ***************************
using UnityEngine;
using System.Collections;
public class GetMeshRenderer : MonoBehaviour
{
private MeshRenderer ShowZone;
// Use this for initialization
void Start ()
{
ShowZone = gameObject.GetComponent<MeshRenderer> ();
}
// Update is called once per frame
void Update ()
{
if(Input.GetKey(KeyCode.Y))
{
ShowZone.enabled = true;
}
if(Input.GetKey(KeyCode.N))
{
ShowZone.enabled = false;
}
}
}
Your problem is that you are using GameObject which is just a class that "describes" what it is. What you want, if this script is attached to the GameObject who's mesh renderer you want, is gameObject with a lowercase "g."
If you want to get the mesh renderer of another GameObject, you can find it by name with GameObject.Find("zone1"); (note the uppercase "G" in that one,) or you can give it a tag and find it with GameObject.FindGameObjectWithTag("zone1");
(You may or may not already know that but it doesn't hurt to provide the information.)
Edit:
Your other problem is that you must use renderer instead of Renderer because, like the GameObject "Renderer" with a capital "R" references a class, instead of a specific object.
the problem is GameObject is different from gameobject Gameobject is a class and gameobject is a instance of current gameobject or gameobject in which the script is attached
Replace the line
MeshRenderer showZone = GameObject.GetComponent<MeshRenderer>();
with
MeshRenderer showZone = gameobject.GetComponent<MeshRenderer>();
I think this will do,
Also note that in your Error statement ,it is saying that GameObject is a Class or a data type not an object
Do you see the gears? Yes? Click it and click remove component.
You can use the declaration:
other.gameobject.GetComponent< MeshRenderer>().Setactive (false);
One Line Reference...after the condition is fulfilled..
For more precise help regarding MeshRender, see the Unity Documentations..
I had same issue with my declaration and i just fixed it by changing "G" to "g" in gameObject and i declared it in Start so it is like...
MeshRenderer showZone = gameObject.GetComponent();

Categories