Gameobject not instantiating at parent local?
Hello, it's me! I am having a few problems with chunks of my world generating on top of eachother, even though the chunks are apart.
Firstly here is the current code using System.Collections; using System.Collections.Generic; using UnityEngine;
public class WorldGenerator : MonoBehaviour
{
public int sizeX;
public int sizeZ;
public int groundHeight;
public float terDetail;
public float terHeight;
int seed;
public GameObject[] blocks;
public GameObject Biome;
public GameObject Chunk;
void Start()
{
seed = Random.Range(100, 9999);
//terDetail = Random.Range(11, 18);
GenerateTerrain();
}
void GenerateTerrain()
{
for (int x = 0; x < sizeX; x++)
{
for (int z = 0; z < sizeZ; z++)
{
int maxY = (int)(Mathf.PerlinNoise((x / 2 + seed) / terDetail, (z / 2 + seed) / terDetail) * terHeight);
maxY += groundHeight;
GameObject grass = Instantiate(blocks[0], new Vector3(x, maxY, z), Quaternion.identity) as GameObject;
grass.transform.SetParent(Biome.transform);
for (int y = 0; y < maxY; y++)
{
int dirtLayers = Random.Range(3, 11);
if (y >= maxY - dirtLayers)
{
GameObject dirt = Instantiate(blocks[1], new Vector3(x, y, z), Quaternion.identity) as GameObject;
dirt.transform.SetParent(Biome.transform);
}
else
{
GameObject stone = Instantiate(blocks[2], new Vector3(x, y, z), Quaternion.identity) as GameObject;
stone.transform.SetParent(Biome.transform);
}
}
}
}
}
}
Following that, I tried the Following to get it to instantiate :
Biome.transform.SetParent(Chunk.transform);
//Biome is where the gameobjects I instantiate goes
Biome.transform.localPosition = new Vector3(0, 0, 0);
//Chunk is the location of which these should be initiated
I have tried much, but still have no idea? Anyone able to assist? Thanks <3
Answer by streeetwalker · Apr 03, 2020 at 07:59 PM
Hi @Willexwun, I think it is the order of operations that is causing the problem. When you try to instantiate at a position, and then parent, the coordinates can change depending on the scale and position of the parent. I believe you are better off if you just instantiate anywhere, and then set the object's parent, and then use localPosition to set it's position relative to the parent. I think if you use that order, it will work.
*** Well, after our conversations, yes the above is the problem (the rationale is wrong, but the order of operations is correct) - because you instantiate at the same World x and z position, you cannot set the local position directly in the Instantiate statement. You have to do that after you instantiate, either that or add the parent offset to the instantiate position parameter. See the following code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BiomeMaker : MonoBehaviour {
public int sizeX;
public int sizeZ;
public int groundHeight;
public float terDetail;
public float terHeight;
int seed;
public GameObject[] blocks;
public GameObject Chunk;
void Start() {
for( int i = 0; i < 2; i++ ) {
seed = Random.Range( 100, 9999 );
GameObject biome = new GameObject( "biome_" + i );
biome.transform.position = new Vector3( sizeX * blocks[0].transform.localScale.x * i, 0, 0);
biome.transform.SetParent( Chunk.transform );
GenerateTerrain( biome );
}
}
void GenerateTerrain( GameObject biome ) {
// the problem was you were still generating the blocks for
// each biome at the same world x and z positions
// instead you need to add this offset to each block x
float offsetX = biome.transform.position.x;
for( int x = 0; x < sizeX; x++ ) {
for( int z = 0; z < sizeZ; z++ ) {
int maxY = (int) ( Mathf.PerlinNoise( ( x / 2 + seed ) / terDetail, ( z / 2 + seed ) / terDetail ) * terHeight );
maxY += groundHeight;
GameObject grass = Instantiate( blocks[0], new Vector3( x + offsetX, maxY, z ), Quaternion.identity ) as GameObject;
grass.transform.SetParent( biome.transform );
for( int y = 0; y < maxY; y++ ) {
int dirtLayers = Random.Range( 3, 11 );
if( y >= maxY - dirtLayers ) {
GameObject dirt = Instantiate( blocks[1], new Vector3( x + offsetX, y, z ), Quaternion.identity ) as GameObject;
dirt.transform.SetParent( biome.transform );
} else {
GameObject stone = Instantiate( blocks[2], new Vector3( x + offsetX, y, z ), Quaternion.identity ) as GameObject;
stone.transform.SetParent( biome.transform );
}
}
}
}
}
}
@streeetwalker So I did some re-modeling of the code (sort of) and this is what I came up with.
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class WorldGenerator : $$anonymous$$onoBehaviour
{
public int sizeX;
public int sizeZ;
public int groundHeight;
public float terDetail;
public float terHeight;
int seed;
public GameObject[] blocks;
public GameObject Biome;
public GameObject Chunk;
void Start()
{
seed = Random.Range(100, 9999);
//terDetail = Random.Range(11, 18);
GenerateTerrain();
}
void GenerateTerrain()
{
Biome.transform.SetParent(Chunk.transform);
Biome.transform.localPosition = new Vector3(0, 0, 0);
for (int x = 0; x < sizeX; x++)
{
for (int z = 0; z < sizeZ; z++)
{
int maxY = (int)($$anonymous$$athf.PerlinNoise((x / 2 + seed) / terDetail, (z / 2 + seed) / terDetail) * terHeight);
maxY += groundHeight;
GameObject grass = Instantiate(blocks[0], new Vector3(x, maxY, z), Quaternion.identity) as GameObject;
grass.transform.SetParent(Biome.transform);
for (int y = 0; y < maxY; y++)
{
int dirtLayers = Random.Range(3, 11);
if (y >= maxY - dirtLayers)
{
GameObject dirt = Instantiate(blocks[1], new Vector3(x, y, z), Quaternion.identity) as GameObject;
dirt.transform.SetParent(Biome.transform);
}
else
{
GameObject stone = Instantiate(blocks[2], new Vector3(x, y, z), Quaternion.identity) as GameObject;
stone.transform.SetParent(Biome.transform);
}
}
}
}
}
}
And it still appears like this -
Green is grass, as the two overlay. Any advice? Also, thanks for the quick response.
I took your code, and I can't get it to mess up - it works perfectly every time, and the grass is always on top. You must have something else going on. Are not generating multiple biomes in the same position with different ground heights?
@streeetwalker The plan is to generate two biomes, [same code] at two different locations. It will always instantiate both biomes at (0,0,0). It works for one, but not for more than one. Current order in Hierarchy (So you have another look)
Chunk (0,0,0) -Biome -Cave
Chunk2 (24, 0, 0) -Biome -Cave
The cave has the same [transform.localposition || transform.setparent] code that the biome has, and the cave moves to the chunk location.