Finding the gameobject a gameobject is placed on? (C#)

First off, I have already posted this to Unity Answers, but I thought I would post it here too since this is more scripting than anything else :slight_smile:

Hey everyone. I have a big problem with my upgrade turret script.
First, I’ll tell you how I’ve got things set up.

  • I have 256 nodes on my map. (The nodes are places I can place my turrets.) They all have a script attached to them. This script is for placing a turret on the selected node and handling the upgrades of each turret.

  • Second, I have a script which checks if the player pressed a upgradable turret and starts a function in the script.

My problem is that when I select a upgradable turret and press the upgrade button, the new turret is placed on node 1 of 256. And not the node the upgradable turret is placed on. This is because my script is using GameObject.FindObjectOfType(); And this will always return node 1 of 256.

So I need to know how I can find the node the turret is placed on and place the new turret there.

Here are the scripts I’m using:

Node.cs:

    using UnityEngine;
    using UnityEngine.EventSystems;
    using UnityEngine.UI;

    public class Node : MonoBehaviour {

    public Color hoverColor;
    public Vector3 positionOffset;
    public GameObject UpgradeTurret1UI;
    public bool Upgraded;
    public GameObject TurretLevel2Prefab;

    [Header ("Optional")]
    public GameObject turret;

    private Renderer rend;
    private Color StartColor;
    BuildManager buildManager;

    void awake()
    {
        UpgradeTurret1UI = GameObject.Find("UpgradeNormalTurretLvl2");
    }

    void Start()
    {
        rend = GetComponent<Renderer> ();
        StartColor = rend.material.color;
        buildManager = BuildManager.instance;

        UpgradeTurret1UI.SetActive (false);
    }

    public Vector3 GetBuildPosition()
    {
        return transform.position + positionOffset;
    }

    void OnMouseUp ()
    {
        if (EventSystem.current.IsPointerOverGameObject()) 
            return;

        if (!buildManager.CanBuild)
            return;

        if (turret != null) 
        {
            Debug.Log("Turret already placed here.");
            if (turret.tag == "TurretTier1") {
                Turret1Upgrade ();
            } else
                return;
        }

        //build a turret
        buildManager.BuildTurretOn (this);
    }

    void OnMouseEnter ()
    {
        if (EventSystem.current.IsPointerOverGameObject()) 
            return;
       

        if (!buildManager.CanBuild)
            return;
       
        GetComponent<Renderer> ().material.color = hoverColor;
    }

    void OnMouseExit()
    {
        rend.material.color = StartColor;
    }

    public void ExitButtonPressed()
    {
        UpgradeTurret1UI.SetActive (false);
        Time.timeScale = 1;
    }
     
    public void Turret1Upgrade()
    {
        Debug.Log ("This is a Standard Turret.");
        UpgradeTurret1UI.SetActive (true);
        Time.timeScale = 0;
        return;
    }

    public void UpgradeButtonPressed()
    {
        if (MoneyManager.money >= 60) {
            Instantiate (TurretLevel2Prefab, transform.position, transform.rotation);
            MoneyManager.money -= (60);
            Upgraded = true;
            Debug.Log ("UpgradeButton pushed.");
            UpgradeTurret1UI.SetActive (false);
            Time.timeScale = 1;
            Debug.Log ("Working...");

        } else
            Debug.Log ("Not enough cash to upgrade this turret.");
            return;
    }
     }

Here is my “ClickTurret1.cs” script:

         using UnityEngine;
        using System.Collections;

        public class ClickTurret1 : MonoBehaviour {

    private Node node;

    void Awake()
    {
        node = GameObject.FindObjectOfType<Node>();
    }
    void OnMouseUp()
    {
        node.Turret1Upgrade ();
    }
        }

And lastly, if its needed, this is my BuildManager script this determining where to place the turret based of which node is pressed.
“BuildManager.cs”:

       using UnityEngine;


        public class BuildManager : MonoBehaviour {

    public static BuildManager instance; 


    void Awake ()
    {
        instance = this;
    }

    public GameObject standardTurretPrefab;
    public GameObject SateliteTurretPrefab;
    public GameObject MissileLauncherPrefab;
        public GameObject DrillGoldDiggerPrefab;
    public GameObject TeslaCoilPrefab;
    public MoneyManager moneyManager;
    public GameObject turret;
    private TurretBlueprint turretToBuild;

    public bool CanBuild{ get { return turretToBuild != null;}}


    public void SelectTurretToBuild(TurretBlueprint turret)
    {
        turretToBuild = turret;
        return;
    }

    public void BuildTurretOn(Node node)
    {
        if (MoneyManager.money <= turretToBuild.cost) 
        {
            Debug.Log ("Not enough money");   
            return;
        }
        MoneyManager.money -= (turretToBuild.cost);
        GameObject turret = (GameObject)Instantiate (turretToBuild.prefab, node.GetBuildPosition (), Quaternion.identity);
        node.turret = turret;
    }

        }

Any help would be very very appreciated. Thanks in advance.

  • Joe

change ClickTurret1.cs to this:

private Node node;

public Node Node
{
        get { return node;}
        set  { node = value;}
}

// Delete your Awake function its not needed

Then In Build Manager:

GameObject turret = (GameObject)Instantiate (turretToBuild.prefab, node.GetBuildPosition (), Quaternion.identity);
        node.turret = turret;
ClickTurret1 turretScript = turret.GetComponent<ClickTurret1>();
turretScript.Node = node;

The same error still occures, don’t I have to change anything in the node.cs script?

Well the idea was that instead of ClickTurret1 looking for the game Object node (and always finding the first node) When you instantiate a new turret your passing in Node variable. Which i assume is the correct node the turret is being built on. You then assigning node.turret = to the turret you just made. I just added code so the turret you just made is being assigned to the node you passed in. If its not working then there is an error somewhere else, probably in node.cs

To be honest I think the main problem is your Node shouldn’t have anything to do with upgrading turrets. Its job should be to catch mouse events on an empty lots and tell the build manager to build a turret here. The only thing a node class should have is a boolean variable called IsEmpty. This will start out true, and get set to false when a turret is built on it. That way it can know when it handles any errant Mouse events that something is already built here. You can set it to false if a turret is removed from some kind of selling.

After you have a turret created it should catch the mouse clicks on itself and be in charge of upgrading itself. I would move all Turret Upgrading code into ClickTurret itself. Each turret should be calling the money manager to see if there is enough money to upgrade, and can change its own sprite image to the new upgraded look etc.

If turrets in your game can be destroyed (through enemy actions, or player selling them off ) You can have the build manager keep track of which turrets are on which nodes. Then when a turret is destoryed it can inform the Node that the turret thats on it is gone.

Overall if you can set up a system so
Node: Handles events that happen to it. Informs the build Manager about information and receives information from build manager
Turret ; handles events that happen to it. Informs the build manager about information and receives information from the build manager

Node and Turret never talk to each other or have any interactions, in the long run your code will be easier to manage as you add more complications to your game. Currently you have 3 way triangle of interaction between all 3 objects that will just lead to logical errors and hard to track down bugs.

I agree with takatok, use the click events. Try this:

  1. Add a “Physics Raycaster” to your camera
  2. Create an empty game object and add two components: Event System and Standalone Input Module
  3. Create a script and add the following code. Add this script to each Node GameObject.
using UnityEngine;
using UnityEngine.EventSystems;

public class ClickDragController : MonoBehaviour, IPointerClickHandler
{
    public void OnPointerClick(PointerEventData eventData)
    {
        Debug.Log("Clicked " + gameObject.name);
    }
}

This should display the name of the gameobject that you click. You can edit this to act as needed on each Node GameObject.

Make sure your turrets on the ignore raycast layer. Right now it may be blocking you from clicking on the node its on.

I will try this when I get home today, thanks guys.

Guys I was just thinking, why do I even need the node in my upgrade script?
Can I just have the upgrades as children of the turret and set them active as I upgrade them?

You really don’t, as long as you have something that takes care of handling the mouse clicks on your empty world and figuring out where that was so you can correctly build a turret there.

But I dont even need to know where I clicked! Do I? If I click a turret, the new upgraded turret is just going to be placed on top of the old one…

what happens when there is no turrets. I meant you need something to handle building the brand new ones