NullReferenceException ?? [SOLVED]

Okay. I am having little problem. When I call a function that is an RPC but I don’t call it over the network. I call it locally, what it should do is disable one canvas, and enable another. It keeps throwing a nullreferenceexception error although BOTH items are assigned in the editor.

Here is script 1 which calls this function

using UnityEngine;

public class Missile : Photon.MonoBehaviour {

    Vector3 properRotation;

    float speed = 1.1f;
    public GameObject target;
    bool shouldGo;
    void Start()
    {
        shouldGo = true;

        if (PhotonNetwork.player.ID == 1001)
        {
            properRotation = new Vector3(transform.rotation.x, -90, transform.rotation.z);
            transform.eulerAngles = new Vector3(properRotation.x, properRotation.y, properRotation.z);
        }
        else
        {
            properRotation = new Vector3(transform.rotation.x, 90, transform.rotation.z);
            transform.eulerAngles = new Vector3(properRotation.x, properRotation.y, properRotation.z);
        }
    }

    void Update () {
        if (shouldGo)
        {
            transform.position = Vector3.MoveTowards(transform.position, target.transform.position, speed * Time.deltaTime);
        }
    }

    void OnCollisionEnter(Collision col)
    {
        if (col.gameObject == target.gameObject)
        {
            PlayerNetworkController network = new PlayerNetworkController();
            network.winGame(); //HERE IS WHERE IT IS CALLED
            shouldGo = false;
            networkView.RPC("hitPlanet", PhotonTargets.Others, null);
        }
    }
}

And here is where the function is

using UnityEngine;

public class PlayerNetworkController : Photon.MonoBehaviour {
    public Canvas Main;
    public Canvas Win;

    void Start(){
    }

    public void lose()
    {
        photonView.RPC("winGame", PhotonTargets.Others, null);
        LeaveRoom();
    }

    public void LeaveRoom()
    {
        PhotonNetwork.LeaveRoom();
    }

    void OnLeftRoom()
    {
        PhotonNetwork.LoadLevel(Application.loadedLevel);
    }

    [PunRPC]
    public void winGame()
    {
        Main.GetComponent<Canvas>().enabled = false;
        Win.GetComponent<Canvas>().enabled = true;
    }

    [PunRPC]
    void hitPlanet()
    {
        PhotonNetwork.LeaveRoom();
    }
}

Any ideas on why this isn’t working? Thanks!

Main & win are canvas, can you try Main.enabled=false ?

Yes, I have tried this before. It doesn’t work.

Well, Main and Win are null, how do you assign them ?

In the editor. Both canvases are the child of the prefab the script is attached to that requires them. I have run multiple tests. They are still correctly assigned through out the entire process.

Have you try to assign them at runtime with the Start function ?

Using GameObject.Find()?

Hmm. I suppose. I’ll give it a shot and see what happens!
E: Nope, it still throws the same error

Can you show us the gameObject in question in the hierarchy at runtime ?

This is the canvas when the prefab first spawns in

and this is the script when the prefab first spawns in

Note the second players planet object does not effect the problem.

You instanciate a new Object : PlayerNetworkController network =new PlayerNetworkController();

So in the network variable, there is not reference to the canvas.

How the gameObject with the script Missile is instantiated ?

Hmm possibly. I will take a look at the missile after its instantiated and see whats going on there.

Here is the script that instantiates the missile

using UnityEngine;
using UnityEngine.UI;

public class LaunchRocket : MonoBehaviour {

    public static bool shouldSelectPlanet;
    public GameObject selectedPlanet;
    public Text missileText;
    int check = 0;

    public GameObject myPlanet;

    void Start()
    {
        myPlanet = GameObject.FindGameObjectWithTag("Player");
        missileText = GameObject.Find("LaunchRocketsText").GetComponent<Text>();
    }

    void Update()
    {
        if (myPlanet.GetComponent<PlayerUnits>().missiles >= 1)
        {
            missileText.text = "Launch Rocket - " + myPlanet.GetComponent<PlayerUnits>().missiles.ToString();
            missileText.GetComponentInParent<Button>().interactable = true;
        }
        else
        {
            if (MissileFactory.canCreateRockets)
            {
                missileText.GetComponentInParent<Button>().interactable = true;
                missileText.GetComponent<Text>().text = "Create a rocket";
            }
            else
            {
                missileText.GetComponentInParent<Button>().interactable = false;
                missileText.GetComponent<Text>().text = "Create a missile launch bay!";
            }
        }

      
        if (shouldSelectPlanet == true && Input.GetMouseButtonDown(0))
        {
            Ray ray = Camera.main.GetComponent<Camera>().ScreenPointToRay(Input.mousePosition);
            RaycastHit hit;
            if (Physics.Raycast(ray, out hit, Mathf.Infinity))
            {
                if (check == 0)
                {
                    switch (hit.transform.tag)
                    {
                        case "Player":
                            GameManager.news = "You can not destroy your own planet!";
                            break;
                        case "Enemy":
                            selectedPlanet = hit.transform.gameObject;
                            GameManager.news = "Click this planet again to verify you wish to destroy it!";
                            check++;
                            break;
                        default:
                            GameManager.news = "Please select a planet to destroy!";
                            break;
                    }
                }
                else if (check == 1 && hit.transform == selectedPlanet.transform)
                {
                    LaunchRocketAtPlanet();
                    check = 0;
                    shouldSelectPlanet = false;
                }
                else
                {
                    check = 0;
                    GameManager.news = "Please select a planet to destroy!";
                }
            }
        }
      
    }

    public void LaunchRocketAtPlanet()
    {
        GameObject missile = PhotonNetwork.Instantiate("Missile", transform.position, Quaternion.identity, 0) as GameObject; //MISSILE IS CREATED HERE
        missile.GetComponent<Missile>().target = selectedPlanet;
        myPlanet.GetComponent<PlayerUnits>().missiles -= 1;
        GameManager.isLaunchingMissile = false;
    }

    public static void CreateMissile()
    {
        GameObject myPlanet;
        myPlanet = GameObject.FindGameObjectWithTag("Player");
        if (myPlanet.GetComponent<PlanetController>().metal >= 1500 &&
            myPlanet.GetComponent<PlanetController>().water >= 800 &&
            myPlanet.GetComponent<PlanetController>().lightPoints >= 10 &&
            myPlanet.GetComponent<PlayerUnits>().C_missile == 1)
        {
            myPlanet.GetComponent<PlayerUnits>().missiles++;

            myPlanet.GetComponent<PlanetController>().lightPoints -= 10;
            myPlanet.GetComponent<PlanetController>().water -= 800;
            myPlanet.GetComponent<PlanetController>().metal -= 1500;
        }
    }
}

You can add a Property to your Missile class :

public class Missile : Photon.MonoBehaviour {
[LIST=1]
    Vector3 properRotation;

   GameObject player;

    float speed = 1.1f;
    public GameObject target;
    bool shouldGo;

[/LIST]
Then when you instanciate your Missile you can add the player who lunch it :

  public void LaunchRocketAtPlanet()
    {
        GameObject missile = PhotonNetwork.Instantiate("Missile", transform.position, Quaternion.identity, 0) as GameObject; //MISSILE IS CREATED HERE
        missile.GetComponent<Missile>().target = selectedPlanet;
      
missile.GetComponent<Missile>().player = myPlanet;
myPlanet.GetComponent<PlayerUnits>().missiles -= 1;
        GameManager.isLaunchingMissile = false;
    }

Then

 void OnCollisionEnter(Collision col)
    {
        if (col.gameObject == target.gameObject)
        {
            PlayerNetworkController network = this.player.GetComponent<PlayerNetworkController>();
            network.winGame(); //HERE IS WHERE IT IS CALLED
            shouldGo = false;
            networkView.RPC("hitPlanet", PhotonTargets.Others, null);
        }
    }

Yep, this is exactly what I did after reading your last post saying it creates a new script of that type therefore leaving both canvases un referenced.

thank you very much :slight_smile:

You are welcome !