0
\$\begingroup\$

I have been struggling with this NullReferenceExpection error.

When I don't add anything and just use this version of the code. The game adds a tower, upgrades a tower and takes money for it.

It worked all fine until I tried to add a menu that opens up and then you can choose a tower type you can buy.

So after I add all of this I get a NullReferenceExpection at return tower == null && gameManager.Gold >= cost; and at gameManager.Gold -= tower.GetComponent<TowerData>().CurrentLevel.cost;. The game also doesn't take any money from purchases and you can spawn near infinite amounts of towers on one spot.

//tower = (GameObject)

theTowerMenu.gameObject.SetActive (false);

transform.position = new Vector3(openSpot.transform.position.x, openSpot.transform.position.y, transform.position.z

If i take 'tower = (GameObject)' out of comments I get "error CS0030: Cannot convert type void' toUnityEngine.GameObject'".

The current script:

using UnityEngine;
using System.Collections;

public class PlaceTower : MonoBehaviour {

public GameObject towerPrefab;
private GameObject tower;

public GameObject openSpot;

private GameManagerBehavior gameManager;

public GameObject theTowerMenu;

// Use this for initialization
void Start () {
    gameManager = GameObject.Find ("GameManager").GetComponent<GameManagerBehavior>();
}

// Update is called once per frame
void Update () {

}

private bool canPlaceTower() {
    int cost = towerPrefab.GetComponent<TowerData> ().levels[0].cost;
    return tower == null && gameManager.Gold >= cost;
}

void OnMouseUp () {
    if (canPlaceTower ()) {
        //tower = (GameObject)
        theTowerMenu.gameObject.SetActive (false);
        transform.position = new Vector3(openSpot.transform.position.x, openSpot.transform.position.y, transform.position.z);
        Instantiate (towerPrefab, transform.position, Quaternion.identity);

        AudioSource audioSource = gameObject.GetComponent<AudioSource> ();
        audioSource.PlayOneShot (audioSource.clip);

        gameManager.Gold -= tower.GetComponent<TowerData>().CurrentLevel.cost;
    } else if (canUpgradeTower ()) {
        tower.GetComponent<TowerData> ().increaseLevel ();
        AudioSource audioSource = gameObject.GetComponent<AudioSource> ();
        audioSource.PlayOneShot (audioSource.clip);
        gameManager.Gold -= tower.GetComponent<TowerData> ().CurrentLevel.cost;
    }

}

private bool canUpgradeTower() {
    if (tower != null) {
        TowerData towerData = tower.GetComponent<TowerData> ();
        TowerLevel nextLevel = towerData.getNextLevel ();
        if (nextLevel != null) {
            return gameManager.Gold >= nextLevel.cost;
        }
    }
    return false;
}
}

Please help. I've been stuck with this for a long time.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ I'm not sure about the logic but you have declared tower as a private and I cant see anywhere where you are setting it. \$\endgroup\$
    – Uri Popov
    Commented May 13, 2016 at 7:53

2 Answers 2

3
\$\begingroup\$

You are creating a tower prefab with Instantiate (towerPrefab, transform.position, Quaternion.identity);, but you don't do anything with the GameObject it returns. The result is that your newly created tower is just an independent GameObject in your scene with no relation at all to your PlaceTower game object which created it.

It seems like you want the newly created tower assigned to the private GameObject tower; variable so you can reference it at a later point in the script:

tower = Instantiate (towerPrefab, transform.position, Quaternion.identity) as GameObject;

You might also want to make the tower a child-object of the PlaceTower object by adding the line tower.transform.SetParent(transform) below the previous one.

\$\endgroup\$
3
  • \$\begingroup\$ I'm sorry I fell asleep. Wow. Thank you very much! I have a question: Why should I set the tower as a child-object of PlaceTower? \$\endgroup\$ Commented May 13, 2016 at 13:52
  • 1
    \$\begingroup\$ @SleepySleeper Just feels right, IMO. The game-mechanical effect is that it moves the Tower when the PlaceTower is moved and it destroys the Tower when the PlaceTower is destroyed. Reagarding your workflow in the editor: it makes the tower appear as a child of the place in the scene graph while in play mode, so it's easier for you as a developer to spot which tower belongs to which place. \$\endgroup\$
    – Philipp
    Commented May 13, 2016 at 13:56
  • \$\begingroup\$ I see. Thank you for answering. I really appreciate it. I'm still kind of new to C# and Unity. \$\endgroup\$ Commented May 13, 2016 at 14:05
2
\$\begingroup\$

With your current logic you have no choice but to run into a null reference exception.
You never assign anything to tower. The check canPlaceTower is only returning true if tower is null but in the code of the if statement you use tower: tower.GetComponent<TowerData>().CurrentLevel.cost;.
That can't work. If you want to create a new tower instance you have to create from one a prefab or something else. One option would be to do it like this:

//instead of this:
//tower = (GameObject)
//use this:
tower = MonoBehaviour.Instantiate(Resources.Load("Path/To/towerPrefab")) as GameObject;
//Set position and rotation next.

There are other options like using the existing towerPrefab:

tower = (GameObject)Instantiate(towerPrefab, transform.position, Quaternion.identity);

Which looks like what you are looking for according to your line Instantiate (towerPrefab, transform.position, Quaternion.identity);where you miss the assignment to tower.

\$\endgroup\$
5
  • \$\begingroup\$ I want to instantiate a copy of the object stored in towerPrefab to create a tower, and store it in tower so I can control it in the game. Your line created 5 more errors. Thanks anyway. \$\endgroup\$ Commented May 13, 2016 at 8:05
  • 1
    \$\begingroup\$ What does Convert.ToString do here? You already have a string literal here, so what are you converting it to? \$\endgroup\$
    – Philipp
    Commented May 13, 2016 at 8:07
  • 2
    \$\begingroup\$ @SleepySleeper Please help us helping you and tell us what new errors you get with that line. \$\endgroup\$
    – Philipp
    Commented May 13, 2016 at 8:09
  • 1
    \$\begingroup\$ @Philip: My mistake, I copied that line from my own project and there I needed that. So I removed it here. Thanks for the hint! \$\endgroup\$
    – Skalli
    Commented May 13, 2016 at 8:12
  • \$\begingroup\$ I'm sorry, but he updated his comment and I used the old line and I got a lot of errors. After I used the new and current one this happened: I couldn't even place a tower after clicking the area where I can place towers, and clicking the tower. \$\endgroup\$ Commented May 13, 2016 at 13:56

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .