- Home /
How do I reference a GameObject after finding its collider with Physics.OverlapSphere()?
Currently I have a Player game object placed in the scene with a script that generates TerrianCubes (just built in Cubes) underneath the player, places some other WorldFeatures (spheres) randomly around the scene, and then places TerrainCubes forming a path connecting that WorldFeature back to the player. It's rudimentary. The path isn't always player navigable, but it does what I want which is to start the scene with a bunch of Terrain Cubes connecting WorldFeatures back to the Player.
Now I'm trying to add a script to the TerrainCubes so that they instantiate with different colors. My goal is to have TerrainCubes with no neighbors start with a random color and for those with neighbors to derive their color from those neighbors. The code runs (I can play the Scene), but only a few blocks around the Player change color and I get this error msg ("NullReferenceException: Object reference not set to an instance of an object.")
Here's the DefineTerrainScript I'm using for that:
using UnityEngine;
using System.Collections;
using System.Collections.Generic;
public class DefineTerrainScript : MonoBehaviour {
int rColor = 0,
gColor = 0,
bColor = 0,
aColor = 0;
Collider[] hitTerrainCubes = Physics.OverlapSphere(new Vector3(0.5f,0.5f, 0.5f), 1f);
// Use this for initialization
void Start () {
if (hitTerrainCubes.Length == 0){
rColor = Random.Range (0,3);
gColor = Random.Range (0,3);
bColor = Random.Range (0,3);
aColor = Random.Range (0,3);
}
else {
for (int i = 0; i < hitTerrainCubes.Length; i++){
GameObject hitTerrainCube = hitTerrainCubes[i].transform.gameObject;
rColor += hitTerrainCube.GetComponent<DefineTerrainScript>().rColor;
gColor += hitTerrainCube.GetComponent<DefineTerrainScript>().gColor;
bColor += hitTerrainCube.GetComponent<DefineTerrainScript>().bColor;
aColor += hitTerrainCube.GetComponent<DefineTerrainScript>().aColor;
}
}
this.gameObject.renderer.material.color = new Color(rColor%4,
gColor%4,
bColor%4,
aColor%4);
}
I had some trouble finding the center and radius of the current TerrainCube to use for Physics.OverlapSphere so I just put in fixed numbers for now :(
My understanding is that the TerrainCubes will instantiate in order, so that later TerrainCubes will be able to see earlier ones. Here's my GenerateTerrainScript for reference:
public GameObject terrainCube;
public GameObject player;
public float gridX;
public float gridZ;
public float spacing;
public int startingFeatures;
public GameObject worldFeatures;
public float worldSize;
// Use this for initialization
void Start () {
Vector3 playerStart = new Vector3(player.transform.position.x, player.transform.position.y, player.transform.position.z) * spacing;
AddInitialTerrain(playerStart);
for (int i = 0; i < startingFeatures; i++){
Vector3 pos = (Vector3)PlaceWorldFeatures(worldFeatures);
AddInitialTerrain(pos);
ConnectAtoB(pos, playerStart);
}
}
// Update is called once per frame
void Update () {
//SearchForThisHere(emptySpaces, player);
//FillEmptySpace();
}
// Adds terrain around worldFeatures at start of new level
private void AddInitialTerrain(Vector3 pos){
pos.x -= (int)(gridX/2);
pos.y--;
pos.z -= (int)(gridX/2);
for(int z = 0; z < gridZ; z++){
for(int x = 0; x < gridX; x++){
Vector3 placeHere;
placeHere.x = pos.x + x;
placeHere.y = pos.y;
placeHere.z = pos.z + z;
Instantiate(terrainCube, placeHere, Quaternion.identity);
}
}
}
// Instantiates worldFeatures and returns position for adding terrain around.
private Vector3? PlaceWorldFeatures(GameObject placeThis){
Vector3 pos = new Vector3(Mathf.Round(Random.Range(-worldSize, worldSize)),
Mathf.Round(Random.Range(-worldSize, worldSize)),
Mathf.Round(Random.Range(-worldSize, worldSize))) * spacing;
Instantiate(placeThis, pos, Quaternion.identity);
return pos;
}
private void ConnectAtoB(Vector3 a, Vector3 b){
Vector3 newB = new Vector3(b.x-1, b.y-1, b.z-1);
while(a != newB){
if(a.x < newB.x){a.x++;}
if(a.x > newB.x){a.x--;}
if(a.y < newB.y){a.y++;}
if(a.y > newB.y){a.y--;}
if(a.z < newB.z){a.z++;}
if(a.z > newB.z){a.z--;}
Instantiate(terrainCube, a, Quaternion.identity);
}
}
Comments about best practices, optimization, and alternative code are appreciated.
Didn't have time yet to figure out the problem but a few remarks:
1) calling GetComponent is relatively slow so it's usually better to ins$$anonymous$$d of
rColor += hitTerrainCube.GetComponent().rColor;
gColor += hitTerrainCube.GetComponent<DefineTerrainScript>().gColor;
bColor += hitTerrainCube.GetComponent<DefineTerrainScript>().bColor;
aColor += hitTerrainCube.GetComponent<DefineTerrainScript>().aColor;
to do
DefineTerrainScript dtScript = hitTerrainCube.GetComponent();
rColor += dtScript.rColor;
gColor += dtScript.gColor;
bColor += dtScript.bColor;
aColor += dtScript.aColor;
2) What kind of colors are you trying to get ? The GRBA values of a Color should be from 0 to 1 (new Color(0, 0, 0) => black, new Color(1, 1, 1) => white) but you are randomizing from 0 to 3 and then adding those values together even.
Thanks for the suggestions, Nose$$anonymous$$ills. Updated the GetComponent suggestion to this:
DefineTerrainScript dtScript = hitTerrainCube.GetComponent<DefineTerrainScript>();
rColor += dtScript.rColor;
gColor += dtScript.gColor;
bColor += dtScript.bColor;
Note that when I actually assign the Color to the gameObject, I modulus the added up values so that each ends up between 0 and 3:
gameObject.renderer.material.color = new Color(rColor%4,
gColor%4,
bColor%4);
It continues to work. I'll take your word on the optimization benefits for now, although I'd appreciate if you could link or otherwise point me to resources/search terms so I can read up on it.
As far as what colors I'm ai$$anonymous$$g for, nothing really. I put together this code as a test run for figuring out how to define a terrainCube based on its neighbors. Color combining just seemed like the easiest starting point. I just started plugging numbers in until I was getting output that wasn't all black or white or grayscale.
I tried initializing to random floats between 0 and 1 after reading your comment and ran into two problems. First, I was only getting grayscale blocks. Second, I got a new error "transform.rotation assigned is not valid (0.0, 0.0, 0.0, NaN)". That error resolved when I went back to assigning a random Int between 0 and 3. Thoughts on either of those issues?
Thanks again.
Answer by robertbu · May 02, 2014 at 11:09 PM
You need to move the OverlapSphere() into Start(). That is you declare the variable:
Collider[] hitTerrainCubes;
Then in Start():
hitTerrainCubes = Physics.OverlapSphere(new Vector3(0.5f,0.5f, 0.5f), 1f);
While you appear to be doing everything in Start(), any time object move or are removed, you need to call OverlapSphere() again.
Updated to this, which I believe takes your suggestion into account, while also moving from fixed values for OverlapSphere() to values derived from gameObject:
public class DefineTerrainScript : $$anonymous$$onoBehaviour {
int rColor = Random.Range (0,3),
gColor = Random.Range (0,3),
bColor = Random.Range (0,3);
Collider[] hitTerrainCubes;
// Use this for initialization
void Start () {
hitTerrainCubes = Physics.OverlapSphere(gameObject.transform.position,
gameObject.transform.localScale.x);
if (hitTerrainCubes.Length > 0){
rColor = 0;
gColor = 0;
bColor = 0;
for (int i = 0; i < hitTerrainCubes.Length; i++){
GameObject hitTerrainCube = hitTerrainCubes[i].transform.gameObject;
DefineTerrainScript dtScript = hitTerrainCube.GetComponent<DefineTerrainScript>();
rColor += dtScript.rColor;
gColor += dtScript.gColor;
bColor += dtScript.bColor;
}
}
this.gameObject.renderer.material.color = new Color(rColor%4,
gColor%4,
bColor%4);
}
}
Things seem to work fine. I have a full range of colored blocks that seem to be affected by their neighbors (although I'm not sure how to debug this to be sure), but I still get the "NullReferenceException: Object reference not set to an instance of an object" error message.
I also tried assigning values to the array during Awake() which ends up creating cubes that are all in grayscale and I still get the NRE error. I'm assu$$anonymous$$g this has something to do with a difference in the ti$$anonymous$$g between Awake() and Start() but I'm still fuzzy on the details of that.
Your answer
![](https://koobas.hobune.stream/wayback/20220613144118im_/https://answers.unity.com/themes/thub/images/avi.jpg)