[SOLVED] C# - Referencing Instantiated Objects?

I’m working on randomly generating some stuff in my game. So far, it’s going well! I’m able to select from a list of terrains based on biome type when I move into a new place. Now, I’m looking at scattering objects randomly around this newly-created terrain. For the moment, I’m just using cubes, but I’ve built what I believe will be necessary to do this with all kinds of things (trees, rocks, patches of flowers, whatever).

The only problem is, I’m having trouble referencing the new terrain object in order to give it to the script that will spawn the other objects on it. So here’s what I have. I have three scripts attached to a singleton I’m using as basically my ‘movement handler’ object. The first one’s short, it’ll be a reference wrapper for objects I may want to place.

using System.Collections;
using System.Collections.Generic;
using UnityEngine;

public class AllObjects : MonoBehaviour {

    // Here we store all possible objects, so we can attach them via the editor
    public GameObject[] cubes;

    public Dictionary <string, GameObject[]> items = new Dictionary <string, GameObject[]> ();

    void Awake ()
    {
        items.Add ("cubes", cubes);
    }
}

What this does is let me say, hey, choose a prefab from AllObjects.cubes and spawn that one. Which is great! That part’s working. Next, I have the spawner script that actually places the objects for me.

using UnityEngine;
using System.Collections;

public class SpawnObjects : MonoBehaviour
{
    public Terrain terrain; // add current terrain
    public GameObject objectToPlace; // this object will be placed on terrain
    public int numberOfObjects; // number of how many objects will be created
    public int posMin; // minimum y position
    public int posMax; // maximum x position
    public bool posMaxIsTerrainHeight; // the maximum height is the terrain height
    private int numberOfPlacedObjects; // number of the plaed objects
    private int terrainWidth; // terrain size x axis
    private int terrainLength; // terrain size z axis
    private int terrainPosX; // terrain position x axis
    private int terrainPosZ; // terrain position z axis

    // Create objects on the terrain with random positions
    public void PlaceObject()
    {
        terrainWidth = (int)terrain.terrainData.size.x; // get terrain size x
        terrainLength = (int)terrain.terrainData.size.z; // get terrain size z
        terrainPosX = (int)terrain.transform.position.x; // get terrain position x
        terrainPosZ = (int)terrain.transform.position.z; // get terrain position z
        if(posMaxIsTerrainHeight == true)
        {
            posMax = (int)terrain.terrainData.size.y;
        }

        int posx = Random.Range(terrainPosX, terrainPosX + terrainWidth); // generate random x position
        int posz = Random.Range(terrainPosZ, terrainPosZ + terrainLength); // generate random z position
        float posy = Terrain.activeTerrain.SampleHeight(new Vector3(posx, 0, posz)); // get the terrain height at the random position
        if(posy < posMax && posy > posMin)
        {
            Instantiate(objectToPlace, new Vector3(posx, posy, posz), Quaternion.identity); // create object
            numberOfPlacedObjects++;
        }

        // numberOfPlacedObjects is smaller than numberOfObjects
        if(numberOfPlacedObjects < numberOfObjects)
        {
            PlaceObject(); // place another one
        }
    }
}

This one should let me feed it the terrain object, the object to spawn, and the number of them that I want, and it’ll scatter them randomly across the terrain. I believe that this is also working great, though I haven’t really gotten to test it due to the last script, which has an error I can’t figure out. Here’s my main handler script:

using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;


public class Environment : MonoBehaviour {

    static Environment Instance;

    public GameObject grassterr;
    public GameObject dirtterr;
    public GameObject pathterr;
    public GameObject makeTerr;
    public System.Random rnd = new System.Random();

    Biomes biomes;
    SpawnObjects spawner;
    AllObjects items;

    private Scene myScene;
    private Scene newScene;
    private string curName;
    private string newName;
    private string newTerr;
    private int oldx;
    private int oldy;
    private int newx;
    private int newy;
    private GameObject[] posTerrs;

    string[][] wilderness = new string[][] { // Set up biome type grid
        new string[] {"grass", "dirt", "path"},
        new string[] {"dirt", "path", "grass"},
        new string[] {"path", "grass", "dirt"}
    };
      

    void Awake() { // Make this a singleton (only one instance of this script allowed, ever)
        if (Instance == null)
        {
            DontDestroyOnLoad (gameObject); // Keep this script around!
            Instance = this;
        }
        else
        {
            Destroy (gameObject); // Delete if we already have one
        }
    }

    // Use this for initialization
    void Start () {
        SceneManager.sceneLoaded += OnSceneLoaded;

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

    void OnSceneLoaded(Scene scene, LoadSceneMode mode) {
        biomes = GetComponent<Biomes> ();
        spawner = GetComponent<SpawnObjects> ();
        items = GetComponent<AllObjects> ();
        if (scene.name == "mainmenu") {
          
        } else {
            curName = scene.name;
            string[] coords = curName.Split('.'); // Convert the scene name to its x and y coordinates
            newx = int.Parse (coords [0]);
            newy = int.Parse (coords [1]);
            newTerr = wilderness[newx][newy]; // Determine the necessary biome as a string
            posTerrs = biomes.terrains[newTerr]; // Get the list of possible terrain objects associated with our biome
            int r = rnd.Next(posTerrs.Length); // Pick a terrain object from the list
            makeTerr = posTerrs[r];
            GameObject createdTerr = Instantiate (makeTerr, new Vector3(0,0,0), Quaternion.identity); // Place the terrain in the new scene
            spawner.terrain = createdTerr;
            spawner.numberOfObjects = rnd.Next (100);
            spawner.objectToPlace = items.cubes [0];
            spawner.PlaceObject (); // Place some cubes on the new terrain
        }
      
    }

    public void ChangeScene(int x, int y) { // Called when moving to a new tile in the wilderness
        myScene = SceneManager.GetActiveScene (); // Get the current scene
        curName = myScene.name; // Scenes where this function might run are named 'x.y', so for example 1.2 or 5.3
        string[] coords = curName.Split('.'); // Convert the scene name to its x and y coordinates
        oldx = int.Parse (coords [0]);
        oldy = int.Parse (coords [1]);
        newx = oldx + x; // Determine where we're moving to
        newy = oldy + y;
        newName = newx.ToString () + "." + newy.ToString (); // Get the name of the new scene
        SceneManager.LoadScene (newName, LoadSceneMode.Single); // Move into the next scene
    }
      
}

So the problem here is in line 78, the Unity editor says ‘Cannot implicitly convert type UnityEngine.GameObject' to UnityEngine.Terrain’'. I tried changing the ‘GameObject’ declaration for the variable createdTerr to ‘Terrain’ instead and it gives the exact same error, so I’m a bit at a loss. Any ideas?

spawner.terrain = (Terrain) createdTerr; ?

The line you’re suggesting changing is actually after the error, so I don’t think that would fix it. It did give me an idea, though. I tried changing line 78 to:

            spawner.terrain = Instantiate (makeTerr, new Vector3(0,0,0), Quaternion.identity); // Place the terrain in the new scene

But this gives the same error, no change.

Oh! I believe I resolved it - this led me to looking closer at HOW to use Instantiate, and I made it Instantiate as Terrain, which of course then threw errors since makeTerr is a ‘GameObject’, so I went through and changed all references to makeTerr, posTerrs, and the biomes lists to ‘Terrain’ instead of ‘GameObject’ and the error is gone. :slight_smile: It now correctly scatters cubes on my shiny new terrain!

1 Like