- Home /
GameObject.FindGameObjectWithTag not finding the tagged objects.
Alright, so I'm trying to make a simple spaceship game with enemies n' stuff, including meteors. What I've done is I've put different empty GameObjects arount the 'map' from which the meteors will spawn. I assign the meteor prefab, and from there try to find it's transform and image through FindGameObjectsWithTag, however it doesn't seem to be finding anything. Here's my code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MeteorBehaviour : MonoBehaviour
{
public GameObject meteor;
private Transform meteorTransform;
public Transform meteorImage;
private float moveSpeed;
private float spinSpeed;
// Use this for initialization
void Start()
{
if(meteor != null)
{
meteorImage = GameObject.FindGameObjectWithTag("Meteor Image").GetComponent<Transform>();
meteorTransform = GameObject.FindGameObjectWithTag("Meteor").GetComponent<Transform>();
}
moveSpeed = 0.05f;
spinSpeed = -50;
//Debug.Log();
}
// Update is called once per frame
void Update()
{
Vector2 meteorDirection = new Vector2(35, 43);
if (meteor != null)
{
meteorTransform.transform.Translate(meteorDirection * moveSpeed * Time.deltaTime);
if(meteorImage != null)
{
meteorImage.transform.Rotate(Vector3.forward, spinSpeed * Time.deltaTime);
}
Vector3 meteorPos = Camera.main.WorldToViewportPoint(meteor.transform.position);
if (meteorPos.x <= 0f || meteorPos.y <= 0f && meteor != null && meteor != null)
{
Destroy(meteor);
}
if (meteorPos.x >= 1f || meteorPos.y >= 1f && meteor != null && meteor != null)
{
Destroy(meteor);
}
}
}
}
Hi well i see why it doesn't work, because your if Statement is unreachable, if you want to add $$anonymous$$eteor GameObject on Runtime. You need to define your Public $$anonymous$$eteor GameObject, bevor pressing Play. You Have now two Options
Nr1 = Take Out your if Statement in the Starte Line like :
void Start()
{
meteorImage = GameObject.FindGameObjectWithTag("$$anonymous$$eteor Image").GetComponent<Transform>();
meteorTransform = GameObject.FindGameObjectWithTag("$$anonymous$$eteor").GetComponent<Transform>();
moveSpeed = 0.05f;
spinSpeed = -50;
//Debug.Log();
}
Nr2 = You put your If Statement in you Update Section like:
void Update()
{
{
meteorImage = GameObject.FindGameObjectWithTag("$$anonymous$$eteor Image").GetComponent<Transform>();
meteorTransform = GameObject.FindGameObjectWithTag("$$anonymous$$eteor").GetComponent<Transform>();
}
Vector2 meteorDirection = new Vector2(35, 43);
if (meteor != null)
{
meteorTransform.transform.Translate(meteorDirection * moveSpeed * Time.deltaTime);
if(meteorImage != null)
{
meteorImage.transform.Rotate(Vector3.forward, spinSpeed * Time.deltaTime);
}
Vector3 meteorPos = Camera.main.WorldToViewportPoint(meteor.transform.position);
if (meteorPos.x <= 0f || meteorPos.y <= 0f && meteor != null && meteor != null)
{
Destroy(meteor);
}
if (meteorPos.x >= 1f || meteorPos.y >= 1f && meteor != null && meteor != null)
{
Destroy(meteor);
}
}
}
Well this is what i came up with in the end..
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class $$anonymous$$eteorBehaviour : $$anonymous$$onoBehaviour
{
public GameObject meteor;
Transform meteorTransform;
public Transform meteorImage;
private float moveSpeed;
private float spinSpeed;
void Start()
{
meteorImage = GameObject.FindGameObjectWithTag("$$anonymous$$eteor Image").GetComponent<Transform>();
meteorTransform = GameObject.FindGameObjectWithTag("$$anonymous$$eteor").GetComponent<Transform>();
moveSpeed = 0.05f;
spinSpeed = -50;
}
void Update()
{
Vector2 meteorDirection = new Vector2(35, 43);
if (meteor != null)
{
meteorTransform.transform.Translate(meteorDirection * moveSpeed * Time.deltaTime);
if(meteorImage != null)
{
meteorImage.transform.Rotate(Vector3.forward, spinSpeed * Time.deltaTime);
}
Vector3 meteorPos = Camera.main.WorldToViewportPoint(meteor.transform.position);
if (meteor != null) {
if (meteorPos.x <= 0f || meteorPos.y <= 0f) {
Destroy (meteor);
}
if (meteorPos.x >= 1f || meteorPos.y >= 1f) {
Destroy (meteor);
}
}
}
}
}
I just tried it and it still didn't work, thanks for the answer tho :)
Are there multiple GameObjects who share the same tag?
No, there's only this one meteor and it's image, both assigned to a different tag.
and just to be sure, have you created your own tag and asigned them to you gameobject?
Yup, created a $$anonymous$$eteor and a $$anonymous$$eteor Image tag, and then assigned them to their corresponding game object.
@IliyanVT18 I'm a bit confused with your question.
Is the
$$anonymous$$eteorBehaviour
script attached on each of the GameObjects from which the meteors will spawn?You say that you try to find it's transform and image through FindGameObjectsWithTag (plural objects) but then in your code you don't use
FindGameObjectsWithTag
butFindGameObjectWithTag
You say that you assign the meteor prefab, but you don't Instantiate the meteor prefab anywhere in your code.
IF you had instantiated the meteor prefab in the scene, why would you be wanting to find its Transform using`FindGameObjectWithTag`? You would already have a reference to the instance in the scene.
FindGameObjectWithTag
is used to find GameObjects that are already in the scene. So, if that were the case, why would you want the meteor prefab, which you don't even Instantiate?
$$anonymous$$y guess is that your code is not finding any meteors in the scene, because there are no meteors in the scene.
It would be very helpful to you if you took some Unity tutorials: https://unity3d.com/learn/tutorials https://unity3d.com/learn
I didn't make it clear in the question. I have a separate meteor spawner script which instantiates the meteor prefab, here it is:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class $$anonymous$$eteorSpawner : $$anonymous$$onoBehaviour
{
public GameObject[] spawnPoints = null;
public GameObject meteor = null;
int max$$anonymous$$eteorsOnScreen = 1;
public int current$$anonymous$$eteorsOnScreen = 0;
public float interval = 10f;
int position;
Transform point;
// Use this for initialization
void Start()
{
if (spawnPoints == null && meteor != null)
{
spawnPoints = GameObject.FindGameObjectsWithTag("Spawn Points");
}
}
// Update is called once per frame
void Update()
{
InvokeRepeating("spawn$$anonymous$$eteor", 0.0f, interval);
}
void spawn$$anonymous$$eteor()
{
position = (int)Random.Range(0, spawnPoints.Length - 1);
Transform point = spawnPoints[position].GetComponent<Transform>();
if (spawnPoints != null && current$$anonymous$$eteorsOnScreen < max$$anonymous$$eteorsOnScreen)
{
Vector3 spawn = new Vector3(point.position.x, point.position.y, 0.0f);
Instantiate(meteor, spawn, Quaternion.identity);
current$$anonymous$$eteorsOnScreen++;
}
}
}
The meteor behaviour script is attached to an empty game object in the scene, called meteor controller. There I put both the meteor behaviour and spawner scripts, and assigned the mandatory prefabs and transforms to them.
The main problem is that you are instantiating the meteors by calling InvokeRepeating("spawn$$anonymous$$eteor", 0.0f, interval);
from inside the $$anonymous$$eteorSpawner.Update()
. Since all Start()
methods are called before Update()
, there will be no meteors spawned yet, when $$anonymous$$eteorBehaviour.Start()
executes, as GameObject.FindGameObjectWithTag
is called inside Start()
. Another problem is that you don't know which of the 2 scripts $$anonymous$$eteorSpawner
and $$anonymous$$eteorBehaviour
will be executed first. They are both on the same GameObject, and even if you put InvokeRepeating("spawn$$anonymous$$eteor", 0.0f, interval)
inside $$anonymous$$eteorSpawner.Start()
(and you should - see below). $$anonymous$$eteorBehaviour.Start()
might execute before $$anonymous$$eteorSpawner.Start()
, so the problem won't go away. You could of course, set the Script Execution Order of the two scripts, so that $$anonymous$$eteorSpawner
executes before $$anonymous$$eteorBehaviour
. However, I always prefer to use setting of the Script Execution Order as a last resort, only if I can't find a better solution. So, personally, I would rather have a reference assigned of the $$anonymous$$eteorSpawner
inside $$anonymous$$eteorBehaviour
:
private $$anonymous$$eteorSpawner meteorSpawner// use GetComponent<$$anonymous$$eteorSpawner>() to get reference
and then use meteorSpawner.meteor
to access the meteor. Anyway, it's up to you, setting of the Script Execution Order will work too. Also, as I said above, maybe you should consider calling InvokeRepeating("spawn$$anonymous$$eteor", 0.0f, interval)
from inside Start()
, rather than Update()
. Otherwise, you'll be spawning 1 meteor every 10 seconds, at every frame. e.g. if FPS = 60, after 1 second you will have started InvokeRepeating
60 times, and you'll be spawning 60 meteors every 10 seconds. Imagine after 10 seconds, you'll spawn 600 meteors every seconds, etc.
EDIT: Having said that, and thinking "out of the box". I believe that it would be a better solution if you attached the $$anonymous$$eteorBehaviour
script directly on the meteor prefab. So, that each meteor handled its own movement. You could also setup 6 trigger colliders around the play area, to act as the boarders of the game. So, you could then use OnTriggerEnter
to destroy the meteors, ins$$anonymous$$d of having code inside Update()
.
Thank you very much for the answer, but I just found a very simple fix to this problem. I just modified slightly the $$anonymous$$eteorBehaviour script so that it's in the meteor object itself. Here's the fixed code:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class $$anonymous$$eteorBehaviour : $$anonymous$$onoBehaviour
{
private GameObject meteor;
private Transform meteorTransform;
private Transform meteorImage;
private float moveSpeed;
private float spinSpeed;
$$anonymous$$eteorSpawner meteorSpawner;
// Use this for initialization
void Start()
{
moveSpeed = 0.05f;
spinSpeed = -50;
meteor = gameObject;
meteorTransform = gameObject.GetComponent<Transform>();
meteorSpawner = GameObject.FindGameObjectWithTag("$$anonymous$$eteor Controller").GetComponent<$$anonymous$$eteorSpawner>();
meteorImage = transform.Find("meteor-sprite");
//Debug.Log();
}
// Update is called once per frame
void Update()
{
Vector2 meteorDirection = new Vector2(35, 43);
if (meteor != null)
{
if (meteorTransform != null)
{
meteorTransform.transform.Translate(meteorDirection * moveSpeed * Time.deltaTime);
}
if (meteorImage != null)
{
meteorImage.transform.Rotate(Vector3.forward, spinSpeed * Time.deltaTime);
}
Vector3 meteorPos = Camera.main.WorldToViewportPoint(meteor.transform.position);
if (meteorPos.x <= 0f || meteorPos.y <= 0f && meteor != null && meteor != null)
{
Destroy(meteor);
if (meteorSpawner != null)
{
meteorSpawner.current$$anonymous$$eteorsOnScreen--;
}
}
if (meteorPos.x >= 1f || meteorPos.y >= 1f && meteor != null && meteor != null)
{
Destroy(meteor);
if (meteorSpawner != null)
{
meteorSpawner.current$$anonymous$$eteorsOnScreen--;
}
}
}
}
}
And thanks for the InvokeRepeating fix, that was another problem I was having just now.
I just posted an answer about attaching the script directly to the gameobject. We're connected XD Also thanks for the collider boundary idea. Gonna use it in 3D Games
Answer by ivt18 · Nov 19, 2017 at 05:38 PM
Finally found an ez fix, I just modified the MeteorBehaviour script slightly so that it could be in the meteor gameobject itself. Another problem I was having was with the MeteorSpawner (mentioned in one of the comments), where I would invoke meteors from Update();, rather than from Start();. Thanks to everybody who helped out in this thread. Here are the two fixed scripts: MeteorBehaviour:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MeteorBehaviour : MonoBehaviour
{
private GameObject meteor;
private Transform meteorTransform;
private Transform meteorImage;
private float moveSpeed;
private float spinSpeed;
MeteorSpawner meteorSpawner;
// Use this for initialization
void Start()
{
moveSpeed = 0.05f;
spinSpeed = -50;
meteor = gameObject;
meteorTransform = gameObject.GetComponent<Transform>();
meteorSpawner = GameObject.FindGameObjectWithTag("Meteor Controller").GetComponent<MeteorSpawner>();
meteorImage = transform.Find("meteor-sprite");
//Debug.Log();
}
// Update is called once per frame
void Update()
{
Vector2 meteorDirection = new Vector2(35, 43);
if (meteor != null)
{
if (meteorTransform != null)
{
meteorTransform.transform.Translate(meteorDirection * moveSpeed * Time.deltaTime);
}
if (meteorImage != null)
{
meteorImage.transform.Rotate(Vector3.forward, spinSpeed * Time.deltaTime);
}
Vector3 meteorPos = Camera.main.WorldToViewportPoint(meteor.transform.position);
if (meteorPos.x <= 0f || meteorPos.y <= 0f && meteor != null && meteor != null)
{
Destroy(meteor);
if (meteorSpawner != null)
{
meteorSpawner.currentMeteorsOnScreen--;
}
}
if (meteorPos.x >= 1f || meteorPos.y >= 1f && meteor != null && meteor != null)
{
Destroy(meteor);
if (meteorSpawner != null)
{
meteorSpawner.currentMeteorsOnScreen--;
}
}
}
}
}
MeteorSpawner:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class MeteorSpawner : MonoBehaviour
{
public GameObject[] spawnPoints = null;
public GameObject meteor = null;
int maxMeteorsOnScreen = 1;
public int currentMeteorsOnScreen = 0;
public float interval = 10f;
int position;
Transform point;
// Use this for initialization
void Start()
{
if (spawnPoints == null && meteor != null)
{
spawnPoints = GameObject.FindGameObjectsWithTag("Spawn Points");
}
InvokeRepeating("spawnMeteor", 0.0f, interval);
}
void spawnMeteor()
{
position = (int)Random.Range(0, spawnPoints.Length - 1);
Transform point = spawnPoints[position].GetComponent<Transform>();
if (spawnPoints != null && currentMeteorsOnScreen < maxMeteorsOnScreen)
{
Vector3 spawn = new Vector3(point.position.x, point.position.y, 0.0f);
Instantiate(meteor, spawn, Quaternion.identity);
currentMeteorsOnScreen++;
}
if (currentMeteorsOnScreen > maxMeteorsOnScreen)
{
Destroy(meteor);
}
}
}
Hope this helps anybody else having problems.