Too subjective and argumentative
Why can't I find a GameObject with FindGameObjectsWithTag
Hello:
So I am having problems getting my code to read the correct amount of a specific game object in the scene. The list count or array length always returns zero. It should be showing at least 1 object and it is not even showing that.
if (GameObject.FindGameObjectsWithTag("RocketUI") != null)
{
foreach (GameObject score in GameObject.FindGameObjectsWithTag("RocketUI"))
{
Debug.LogError("Stepping in...");
pScores = score.GetComponent<ScoreCounter>();
characterScores.Add(pScores);
}
Debug.LogError(characterScores.Count + " RocketUI objects found.");
}
else
{
Debug.LogError("Cannot find RocketUI objects.");
}
The code always enters the first condition, so it is obviously not null. However, it never adds anything to the list (characterScores). Also, it seems to not run the Foreach loop at all because that Debug.LogError never runs either. The only thing that shows in the console is the second debug which shows "0 RocketUI objects found." This doesn't really make any sense and I am trying to figure out what is going on. I have been working on this for two days now and am quite frustrated.
What this is supposed to be doing is initializing a reference list of UI objects that are recording scores, then add those scores together and compare them to a score threshold that tells it when to spawn a boss in the level. However, the code cannot locate the object. Here is a pic of the object in the scene I am trying to get:
And yes, that object does have the correct tag assigned, else the code couldn't meet the first condition. I already checked if there were duplicates (there was one but deleting it didn't fix anything) so I am at a loss on what is going on here and what to do. If someone could please help, I would greatly appreciate it. Thank you.
From the docs:
Tags must be declared in the tag manager before using them. A UnityException will be thrown if the tag does not exist or an empty string or null is passed as the tag.
Can you link your object's Tag and the tag manager?
Also, is there a reason you're getting those objects via tag and not something a little more reliable / performant? It's pretty rare that using any variant GameObject.Find
is a good idea.
The reason I am using a .Find is because the objects the spawner is looking for are instantiated dynamically from code. They are not actually in the scene. Part of the reason has to do with how we built our couch multiplayer, we wanted to use the same objects without having to manually place anything through multiple scenes, to save time since we have very very tight deadlines. (tbh, when the game was first being, none of us has any clue on what we were doing, it is our first game. Unfortunately, now we don't have time to go back and rewrite everything more efficiently). Plugging in the object into a field in the inspector wouldn't work because it would be a different instance of what the correct object should be, and it depends on which player has been loaded into the scene. Unfortunately, it is much too long to explain what we were trying to do here. All I am trying to do is find a game object after is instantiated so the code can monitor the score and add it to everyone else's score so we can use a single number to deter$$anonymous$$e when a boss spawns.
Tried the code and it works for me, what if you delete the first if and replace it with the foreach loop ins$$anonymous$$d? also could you provide the entire code if it doesn't work so we can see what pScores is and try it. It's pretty strange though because it's working fine for me, try pausing the game as well and see if the gameobjects lose their tag or are being deleted entirely or something.
Here you go:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class BossSpawner : $$anonymous$$onoBehaviour {
[SerializeField] private int scoreThreshold;
[SerializeField] private List<GameObject> bosses;
private GameObject hudObject;
private List<ScoreCounter> characterScores = new List<ScoreCounter>();
private ScoreCounter pScores;
private int baseScore;
private int totalScore;
private int iteration;
private void Start ()
{
baseScore = 0;
iteration = 0;
if (GameObject.FindGameObjectsWithTag("RocketUI") != null)
{
foreach (GameObject score in GameObject.FindGameObjectsWithTag("RocketUI"))
{
Debug.LogError("Stepping in...");
pScores = score.GetComponent<ScoreCounter>();
characterScores.Add(pScores);
}
Debug.LogError(characterScores.Count + " RocketUI objects found.");
}
else
{
Debug.LogError("Cannot find RocketUI objects.");
}
// StartCoroutine(Score$$anonymous$$onitor());
}
// Update is called once per frame
void Update () {
}
private IEnumerator Score$$anonymous$$onitor()
{
yield return new WaitForSeconds(0.1f);
int scorePools = characterScores.Count;
int i = 0;
while (i < scorePools)
{
baseScore += characterScores[i].GetComponent<ScoreCounter>().characterScore;
i++;
}
totalScore = baseScore;
if (totalScore == (scoreThreshold * scorePools))
{
SpawnBoss();
}
}
private void SpawnBoss()
{
iteration++;
GameObject bossObject = Instantiate(bosses[Random.Range(0, characterScores.Count)]) as GameObject;
bossObject.transform.position = transform.position;
bossObject.transform.rotation = transform.rotation;
}
}
Answer by TarwaterPV · Apr 25, 2018 at 11:43 PM
Ok, I decided to just rewrite the entire script and came up with a far more simpler solution. I decided to have the score counters send their points to the monitor directly via events instead. Then the monitor uses a coroutine to check when the threshold has been reached. So far it works good. Thank you everyone for your assistance.
Oh, here is the code if anyone is curious, it is a much more simple set up:
using System.Collections;
using System.Collections.Generic;
using UnityEngine;
public class ScoreMonitor : MonoBehaviour {
[SerializeField] private int bossScoreThreshold;
[SerializeField] private List<GameObject> bosses = new List<GameObject>();
static public ScoreMonitor monitor;
private int iterator;
private bool setCoroutine;
private int totalScore;
public int TotalScore { set { totalScore = value; } }
private int playerAmount;
public int PlayerAmount { set { playerAmount = value; } }
// Use this for initialization
private void Awake()
{
monitor = this;
}
void Start ()
{
iterator = 1;
totalScore = 0;
setCoroutine = true;
StartCoroutine(MonitorScore());
}
private void OnEnable()
{
ScoreCounter.Score += AddScore;
BossHealth_Offline.Death += BeginCoroutine;
}
private void OnDisable()
{
ScoreCounter.Score -= AddScore;
BossHealth_Offline.Death -= BeginCoroutine;
}
private void AddScore(int score)
{
totalScore += score;
}
private IEnumerator MonitorScore()
{
while (setCoroutine)
{
if (totalScore >= ((bossScoreThreshold * playerAmount) * iterator))
{
SpawnBoss(Random.Range(0, bosses.Count));
}
yield return new WaitForSeconds(0.1f);
}
}
private void SpawnBoss(int boss)
{
iterator++;
setCoroutine = false;
GameObject enemyBoss = Instantiate(bosses[boss]) as GameObject;
enemyBoss.transform.position = transform.position;
enemyBoss.transform.rotation = transform.rotation;
}
private void BeginCoroutine(bool start)
{
setCoroutine = start;
StartCoroutine(MonitorScore());
}
}
Glad it worked out :), also for future reference, if you instantiate an object, you can instantly set it to a variable as well. So if you used Instantiate, you could've also added it to the list from there :).
Answer by Anne-Pier · Apr 25, 2018 at 09:36 PM
You could try using GameObject.Find("ScoreCount") instead if you only have 1 object with this tag, or even store it in a variable. It's weird that it doesn't work because it goes into the first if, try creating a new script and build it up and see when it goes wrong if you're really interested, or try it on an empty scene with the same script and see what happens. Debugging like this should get you to the problem.
Yeah, the problem with using just a .Find("ScoreCount") is that it needs to look for the possibility of there being up to four Score Count objects due to multiplayer, hence why I need a list.
Also, this is a new script, I built it from scratch lol. I could try rebuilding it again, not for sure that will work. It is dependent upon a UI being present though so it will be hard to test it in a new scene. I will see what I can do.
Follow this Question
Related Questions
Get Childrens to new array from perents array. 1 Answer
How Do I Create a List of Two Strings? C# 1 Answer
How can I save this objects ? 0 Answers
Need help to generate a random assortment of 4 buttons - C# 0 Answers
compare string to string array[] 2 Answers