Quick disclaimer: I started programming in general and using Unity just a few days ago, so expect wrong lingo, severe misconceptions etc.
I’m trying to pass the value of an int array from a class (a) that handles the score information of the game over to a class (b) that handles the display of the score in the GUI. Here’s the relevant part of (a):
using System.Collections.Generic;
using UnityEngine;
using System;
public class ScoreTrack : MonoBehaviour
{
int score;
int[] scorelist;
public event Action<int[]> PassScoreValues01;
void Scoretrack()
{
++score;
scorelist = IntToIntArray(score);
int lengthOfList = scorelist.GetLength(0);
if (lengthOfList == 1)
{
PassScoreValues01?.Invoke(scorelist);
}
}
And here are the relevant sections of (b):
using UnityEngine;
using UnityEngine.UI;
public class OneIntegerGUI : MonoBehaviour
{
Image oneIntegerDisplay;
public Sprite numberOne;
public Sprite numberZero;
void Start()
{
FindObjectOfType<ScoreTrack>().PassScoreValues01 += ArrayCatcher;
oneIntegerDisplay = GetComponent<Image>();
SetNumber0();
}
public void SetNumber0()
{
oneIntegerDisplay.sprite = numberZero;
}
public void SetNumber1()
{
oneIntegerDisplay.sprite = numberOne;
}
void ArrayCatcher(int[] scoreList)
{
print("Display!");
if (scoreList[0] == 1)
{
SetNumber1();
}
}
}
There is no issue with (a); the Scoretrack()-Method gets called when it should be called, scorelist has the correct information ready and the if-statement that invokes the event gets properly executed.
However, the subscribed method in (b) isn’t called, not even the debug message is printed.
The weirdest part is that yesterday it DID work. Today I just added more of the same to (b): more Sprites, more methods for setting the sprites and more appropriate if-statements in ArrayCatcher. I also renamed ArrayCatcher. When I found out that nothing works I deconstructed it again, but now it’s still not working.
When is Scoretrack() being called? Is it during Start()? If so, it might be getting called before before OnIntegerGUI’s Start(). The execution order of the same method between one object and another is not guaranteed, so it could vary between when you first create a scene and when you reload it.
For the sake of debugging, I’d remove the ? from line 20. Conditional execution can help code be more robust in some situations, but it also makes things fail silently when they go wrong. Right now, if you don’t have any subscribers, you want an error to be thrown there, so that you know what’s happening.
Scoretrack() is being called via another event that it’s being subscribed to during Start(). The event fires every time the player scores, so technically Scoretrack isn’t being called before OneIntegerGUI’s Start() finished doing its thing, right?
Thanks for the debugging tip, I already did that while trying around and got a Null Reference Error. So the issue has to be that the subscription fails, somehow?
I just made a new “OneIntegerGUI”-script with the same code, attached it to the same Object and removed the old script aaaand now the subscription is executed and everything works nicely.
+1 to this, I was making the same guess As a rule of thumb, try to avoid methods like FindObjectOfType and this kind of stuff. They are slow and not accurate
I’m concerned that it will stop working again, since you said it worked at first before as well.
The advice to avoid FindObjectOfType is a good idea as well, but I’d have to know more about your goals and code structure to give more specific recommendation.
Not related to this particular problem, but if I’m guessing at what you’re doing here, you should totally be using an array and a parameter in your subscribed function? e.g.:
public Sprite[] numbers; //assign all in Inspector, with the 0 as the first one
public void SetNumber(int num) {
oneIntegerDisplay.sprite = numbers[num];
}
....
SetNumber(scoreList[0]);
Yes, after restarting Unity it didn’t work again, at first… until I removed and re-attached the script to the object. The object in question is an image object, the only child to the GUI Canvas. Maybe that helps to understand what’s causing the problem?
Regarding the project: I’m just doing a quick flappy bird clone to get the hang of some basics. But I did some custom pixel art as well and wanted to display the score with my own number assets.
I found out that in order to implement this via a text object I’d have to use a custom font file, and I couldn’t figure out how to convert my tiny pixel art numbers into a font while still looking as intended. So I came up with the idea to display the score with my custom number assets via code:
Scoretrack() keeps track of the current score, converts it to an array in the right order (I found a method for that online) and sends the score array to appropriate GUI scripts based on the length of the array. The GUI scripts then handle displaying the wanted numbers.
That’s probably an inherently inefficient way to achieve a nicely looking score display, but I figured it wouldn’t take too long and it won’t impact performance in any way because… it’s still just a flappy bird clone.
It’s also the first time I actively used an array variable, so I just didn’t see the code you pointed out, but that totally makes sense! Thanks!
I also wouldn’t mind reading up on alternatives to FindObjectOfType, but I don’t think this particular project needs a more efficient way to handle things.
It’s not necessarily about efficiency, but reliability. This is why I had to ask whether you had any other objects of that type in the scene - it would just find one of them, and you can’t rely/predict which one it would find.
This article has a list of alternative ways to find references to objects.