Scripts Works on one scene but error in another [duplicate] - c#

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 4 years ago.
So I'm getting an error which says
Object reference not set to an instance of an object Explode.LateUpdate () (at Assets/Scripts/Explode.cs:40)
I'm not sure why I get this error as everything works fine and I have the exact same script in a different scene without the error message. I'd love any help please.
I'm exploding my player with different coloured boxes.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class Explode : MonoBehaviour {
[System.Serializable]
public class ExplodeColours
{
public Color32[] Colours;
}
public static bool explode, explodeOnce;
public ParticleSystem Explodes;
private ParticleSystem explosionSystem;
public Transform player;
public List<ExplodeColours> ColoursList;
// Use this for initialization
void Start () {
PlayerPrefs.SetInt("SelectedChar", 0);
PlayerPrefs.Save();
explodeOnce = false;
explode = false;
}
// Update is called once per frame
void Update () {
if (explode == true)
{
explodeOnce = true;
PlayerExplode();
}
}
void LateUpdate()
{
if (explode)
{
ParticleSystem.Particle[] Particles = new ParticleSystem.Particle[explosionSystem.main.maxParticles];
//ParticleSystem.Particle[] Particles = new ParticleSystem.Particle[Explodes.main.maxParticles];
int NumParticlesAlive = explosionSystem.GetParticles(Particles);
for (int i = 0; i < NumParticlesAlive; i++)
{
Particles[i].startColor = (ColoursList[PlayerPrefs.GetInt("SelectedChar")].Colours[Random.Range(0, ColoursList[PlayerPrefs.GetInt("SelectedChar")].Colours.Length)]);
}
explosionSystem.SetParticles(Particles, NumParticlesAlive);
explode = false;
}
}
void PlayerExplode()
{
explosionSystem = Instantiate(Explodes, player.position, player.rotation);
explosionSystem.Play();
}
}

If this is line 40 (I had to count):
ParticleSystem.Particle[] Particles = new ParticleSystem.Particle[explosionSystem.main.maxParticles];
Then explosionSystem or main or maxParticles is null. I'm going to close this as a duplicate, this error is so common and the way to resolve it is easy.
But a break point on the line of code, when the code control halts, check which object is null and make sure its set.
EDIT:
Use the GetComponent to initialize the explosionSystem variable in the Start function.First, find the GameObject the ParticleSystem is attached to the use GetComponent to get the ParticleSystem.
private ParticleSystem explosionSystem;
void Start()
{
GameObject obj = GameObject.Find("NameOfObjectParticleSystemIsAttachedTo");
explosionSystem = obj.GetComponent<ParticleSystem>();
}
Also, inside the for loop, you tried to use Particles's startColor property without initializing each one. You can do that with Particles[i] = new ParticleSystem.Particle();.
Change:
for (int i = 0; i < NumParticlesAlive; i++)
{
Particles[i].startColor
= (ColoursList[PlayerPrefs.GetInt("SelectedChar")].Colours[Random.Range(0, ColoursList[PlayerPrefs.GetInt("SelectedChar")].Colours.Length)]);
}
to
for (int i = 0; i < NumParticlesAlive; i++)
{
Particles[i] = new ParticleSystem.Particle();
Particles[i].startColor
= (ColoursList[PlayerPrefs.GetInt("SelectedChar")].Colours[Random.Range(0, ColoursList[PlayerPrefs.GetInt("SelectedChar")].Colours.Length)]);
}

To avoid the null reference error, make sure all variables (which are using) has values other wise at least assign default values in constructor level

Related

ERROR: NullReferenceException: Object reference not set to an instance of an object UNITY 3D GALLERY PROJECT [duplicate]

This question already has answers here:
What is a NullReferenceException, and how do I fix it?
(27 answers)
Closed 2 months ago.
I am learning to use Unity, I am currently doing the "Personal 3D Gallery Project" , here is the link if you want to take a look at it: https://learn.unity.com/project/create-a-personal-3d-gallery-project-with-unity?uv=2019.4
However, instead of displaying works of art in my gallery, I am displaying planets and my objective is that when the player approaches one of the planets, a text with information about that given planet pops out. In order to this, I am using the proximity script provided in the Unity website with a few changes. Everything seems to be working fine but when I approach the planets the text does not show and I keep receiving this error:
NullReferenceException: Object reference not set to an instance of an object
Proximity.Start () (at Assets/Scripts/Proximity.cs:32)
Apparently the problem is on line 32 but I can't figure out what's causing it. I am going to be attaching images for a better understating of the problem and my code.
I would really appreciate your help since this is for a final project, thank you so much in advance.
Here is my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class Proximity : MonoBehaviour
{
public string newTitle;
public string newNumber;
public string newInfo;
private Transform other;
private Text myTitle;
private Text myNumber;
private Text myInfo;
private float dist;
private GameObject player;
private GameObject message1;
private GameObject message2;
private GameObject message3;
private bool check;
// Start is called before the first frame update
void Start()
{
player = GameObject.FindWithTag("Player");
other = player.GetComponent<Transform>();
message1 = GameObject.FindWithTag("PlanetTitle");
message2 = GameObject.FindWithTag("PlanetNumber");
message3 = GameObject.FindWithTag("PlanetInfo");
myTitle = message1.GetComponent<Text>();
myTitle.text = "";
myNumber = message2.GetComponent<Text>();
myNumber.text = "";
myInfo = message3.GetComponent<Text>();
myInfo.text = "";
check = false;
}
// Update is called once per frame
void Update()
{
if (other)
{
dist = Vector3.Distance(transform.position, other.position);
print("Distance to player: " + dist);
if (dist < 4)
{
myTitle.text = newTitle;
myNumber.text = newNumber;
myInfo.text = newInfo;
check = true;
}
if (dist > 4 && check == true)
{
Start();
}
}
}
}
This is what I'm trying to do
But this is how it looks when I approach the planet (or moon in this case)
Here is my inspector, just in case the issue could be there
I checked my code multiple times and compared it to the original, I think I made all the necessary changes but clearly there is something wrong with it.
myTitle is not initialised before you are setting the property text on it. Initialise it by assigning the required components in Awake.
void Awake()
{
player = GameObject.FindWithTag("Player");
other = player.GetComponent<Transform>();
message1 = GameObject.FindWithTag("PlanetTitle");
message2 = GameObject.FindWithTag("PlanetNumber");
message3 = GameObject.FindWithTag("PlanetInfo");
myTitle = message1.GetComponent<Text>();
myNumber = message2.GetComponent<Text>();
myInfo = message3.GetComponent<Text>();
}
void Start()
{
myTitle.text = "";
myNumber.text = "";
myInfo.text = "";
check = false;
}

Gameobject destroy fails inside destructor

I have an object, which contains a list of GameObjects. I wish to destroy all of these GameObjects in its destructor.
However, when I attempt to call GameObject.Destroy() from inside the destructor, it seems to halt execution (the line after GameObject.Destroy() never executes, but the line before it does)
If i copy and paste exactly the same code into a function called not_a_destructor() and call that instead, it works perfectly. What gives? I've got it working, but I would really like to understand what's going on.
Destructor and not_a_destructor() code:
// Destructor DOES NOT work
~MoveAction(){
for(int i = 0; i < arrows.Count; i++){
Debug.Log("wasd");
GameObject.Destroy(arrows[i]);
Debug.Log("asdf");
}
}
// Identical code, calling not_a_destructor() works perfectly
public void not_a_destructor(){
for(int i = 0; i < arrows.Count; i++){
Debug.Log("PRETEND DESTRUCTOR!");
GameObject.Destroy(arrows[i]);
Debug.Log("GameObject destroyed successfully");
}
}
As requested in comments, a full copy of the class:
public class Action
{
public int type;
public string debug_string;
public GameObject ui_pill; // Only present for Actions created on the client
}
public class MoveAction : Action
{
public int type = ActionType.MOVE;
public MapHex origin;
public List<MapHex> route; // Intermediate hexes travelled through during the move (includes target_hex)
public Fleet fleet;
private List<GameObject> arrows = new List<GameObject>(); // Arrows for the graphical representation of the pending move on the tactical map
public MapHex target_hex {
get {
return route[route.Count - 1];
}
}
public string debug_string {
get {
return "MOVE ACTION WITH FLEET: " + fleet.name;
}
}
public MoveAction(Fleet _fleet, List<MapHex> _route){
fleet = _fleet;
route = _route;
origin = fleet.planned_position;
update_arrows_from_route();
}
public void update_arrows_from_route(){
Material default_material = new Material(Shader.Find("Sprites/Default"));
// Create one arrow for every hex we will pass through.
MapHex last = fleet.planned_position;
foreach (MapHex hex in route){
// Create arrow from last to hex
GameObject arrow_gameobj = new GameObject();
arrow_gameobj.name = "move_order_arrow";
LineRenderer line_renderer = arrow_gameobj.AddComponent<LineRenderer>();
line_renderer.material = default_material;
line_renderer.SetColors(fleet.owner.color, fleet.owner.color);
line_renderer.positionCount = 2;
arrow_gameobj.layer = layers.tactical_map;
Vector3[] line_points = new Vector3[]{last.position, hex.position};
line_renderer.SetPositions(line_points);
line_renderer.startWidth = 0.1f;
line_renderer.endWidth = 0.1f;
arrows.Add(arrow_gameobj);
last = hex;
}
}
public void not_a_destructor(){
for(int i = 0; i < arrows.Count; i++){
Debug.Log("PRETEND DESTRUCTOR!");
GameObject.Destroy(arrows[i]);
Debug.Log("GameObject destroyed successfully");
}
}
~MoveAction(){
for(int i = 0; i < arrows.Count; i++){
Debug.Log("wasd");
GameObject.Destroy(arrows[i]);
Debug.Log("asdf");
}
}
Its probable best to use more of Unity and less of C#, there is a good callback called OnDestroy() which would be a fine place to destroy all the arrows. If execution of your unity code depends on running a finalizer on something, this is a very strong code smell.
Unless you are using IO in a way that REQUIRES an action to happen in a finalizer (possibly things like releasing an IO resource), its best to leave them empty, and put Unity code inside Unity callbacks

how to access a variable in another script in a unity project [duplicate]

This question already has answers here:
How to access a variable from another script in another gameobject through GetComponent?
(3 answers)
Closed 2 years ago.
I have one script that instantiates coins and another one for the coin itself. So once the coin itself is collected by the player, it should disappear and tell the first script to instantiate another. I tried many times to access booleans across separate scripts like so...
//script 1
public script2name scriptVar;
void start()
{
scriptVar.GetComponent<script2name>();
}
void func()
{
if (scriptVar.boole1 == true)
{ //create another coin
}
}
//script 2 (script2name)
public bool Boole1 = false;
void func()
{
// picks up coin
Boole1 = true;
}
I tried this however there was no response in the system, I never got another coin, it simply does not work.
So I guess the only variable that is really transferrable from script to script in unity is the integer. So instead of basing it off of a true or false value, your script must trace an integer count from a separate script. Heres how your coin problem can be fixed...
The GameObject that holds script2 in this example will be necessary in the Find(""). We'll use 'GamNme' for our example.
//script1
public script2name Var;
void start()
{
Var = GameObject.Find("GamNme").GetComponent<script2name>();
}
void func()
{
//picks up coin
Var.count = 1;
}
//script2
public int count = 0;
void func()
{
if (count == 1)
{
//instantiate new coin and reset the counter
count = 0;
}
}

MissingReferenceException error when using StartCoroutine - Unity

I've been building a quiz game that randomly picks a gameobject from a list and after a question is completed it reloads the scene for a new question however, it states this error:
MissingReferenceException: The object of type 'GameObject' 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.
GameManager.Start () (at Assets/Scripts/GameManager.cs:30)
And this is the code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;
using UnityEngine.SceneManagement;
public class GameManager : MonoBehaviour {
public static int betul1 = 0;
public static int betul2 = 0;
public static int salah1 = 0;
public static int salah2 = 0;
public GameObject[] questions;
private static List<GameObject> unansweredQuestions;
private GameObject currentQuestion;
[SerializeField]
private float transitionTime = 1f;
void Start()
{
if (unansweredQuestions == null || unansweredQuestions.Count == 0)
{
unansweredQuestions = questions.ToList<GameObject>();
}
GetQuestion();
currentQuestion.SetActive(true);
}
void GetQuestion()
{
int randomNumber = Random.Range(0,unansweredQuestions.Count);
currentQuestion = unansweredQuestions[randomNumber];
}
IEnumerator NextQuestion()
{
unansweredQuestions.Remove(currentQuestion);
//currentQuestion.SetActive(false);
yield return new WaitForSeconds(transitionTime);
SceneManager.LoadScene(SceneManager.GetActiveScene().buildIndex);
}
public void Yes()
{
if (betul1 == 1 && betul2 == 1)
{
Debug.Log("Congratulations! You're correct!");
StartCoroutine(NextQuestion());
}
if (salah1 == 1 && salah2 == 1)
{
Debug.Log("Sorry! You're wrong!");
StartCoroutine(NextQuestion());
}
if (betul1 == 1 && salah2 == 1)
{
Debug.Log("Your answer is invalid. Please fix it.");
}
if (betul2 == 1 && salah1 == 1)
{
Debug.Log("Your answer is invalid. Please fix it.");
}
}
}
I'm not sure what's wrong about it. I'm still relatively new to Unity so I would really appreciate it if you could point out what's causing this. Thank you in advance.
The error explains it all. On the first run of your game you'll find that GameManager.cs is attached to a valid GameObject and running fine. But when you reload a new scene all objects in a scene are destroyed and the second scene is loaded.
So there is no more GameManager context. The GameObject which your GameManager.cs script was associated with is destroyed. Since all data in GameManager.cs is static, I would suggest making it a static class or, if you want to keep the object around, use DontDestroyOnLoad
If you don't destroy any objects,
maybe some of the objects in the unansweredQuestions list are destroyed when you reload the scene.
So when you get the reference from GetQuestion(), it returns a reference to destroyed object. So when you try to set it active it throws this exception.
You can easily fix this by checking currentQuestion for null after getting it in GetQuestion().
But its better to fix the cause of the destroying of objects.
Try removing the currentQuestion from the unansweredQuestions, right after you get it in GetQuestion().
If there are other scripts accessing questions list, the problem may be there.
If the objects that are in questions list are destroyed, the objects in unansweredQuestions will be destroyed too.
*Edit. ok so nvm the GameManager. the error is on line 30, denoted by your output.
line 30 is:
currentQuestion.SetActive(true);
this error is saying that currentQuestion is empty. if your reloading the scene you will need to set this to a question, in void Start() before trying to set it to active.

Multiple references to a Ball object in Unity

I am making a game like pong with multiple power-ups. One of them is to have a "Triple Ball" power-up. I tried just creating another reference of the ball, but that doesn't seem to work. I figured this would work because I mostly work with Java where I can just create another instance. Here is how I tried to do it, I tried testing through just clicking a button:
public class TripleBall : MonoBehaviour {
public Ball firstBall;
private int amountOfBalls = 2;
private Ball[] ballArray;
private bool start, avail, located;
void Start () {
ballArray = new Ball[amountOfBalls - 1];
for (int i = 0; i < ballArray.Length; i++)
ballArray[i] = new Ball();
}
// Update is called once per frame
void Update () {
if (Input.GetKeyDown(KeyCode.B))
start = true;
if (start)
{
//Begin locator: Makes it so when the balls spawn they spawn where the first ball
if (!located) {
for (int i = 0; i < ballArray.Length; i++)
{
ballArray[i].transform.position = firstBall.transform.position;
}
located = true;
}
//End locator : if statement and loop
}
}
}
But it seems I can't do this because Ball is of type MonoBehavior.
Question: Is there any way to do this the way I planned or any way at all? Thanks in advanced!
You really don't use new to create an instance. The only place you are right in your code is using new to initialize array. After that, you are supposed to use GameObject.AddComponent to create a new instance instead of the new keyword. This is because Ball class derives from the MonoBehaviour.
You Ball class derives from MonoBehaviour.
public class Ball : MonoBehaviour
{
}
Here is your code fixed:
private Ball[] ballArray;
void Start()
{
ballArray = new Ball[amountOfBalls - 1];
for (int i = 0; i < ballArray.Length; i++)
ballArray[i] = gameObject.AddComponent<Ball>();
}
Assuming that your Ball class looks like the code below and does not inherit from MonoBehaviour:
public class Ball
{
}
Then code in your question would be valid and using new is the right way.
You need to use instantiate. It is derived from Unity's Object class, so assuming "ball" inherits from either Object or GameObject, this is what you want. You can find more info about it here: http://docs.unity3d.com/ScriptReference/Object.Instantiate.html

Categories

Resources