Help with synchronizing script function calls

Hey,

I’m very much new to Unity and not too familiar with how things work. I wouldn’t even say that I’m an intermediate at programming altogether, please don’t be too harsh on me. I’m currently working on creating my first small project Top-Down 2D game. I’ve handled the basics like movement, following camera, a small basic map however I’ve encountered a first logic problem which I’ve been stuck on for some time now, namely, I’m trying to implement a “quiz system”, sort of like a multiple choice quiz system. I wrote a data structure class to store the questions and answers.

I wrote a script that handles activating the canvas(since it’s initially disabled) when the player interacts with the 2D quiz game object sort of like QuizPanel. There is a method(ActivateQuiz) called here which is part of another script(QuizManager) for activating the actual quiz(populating questions and answers into the data structure etc.).

There’s a second script QuizManager like I mentioned, that handles populating the quiz. This script is tied as a component of the canvas itself. The logic works that in the Start method of QuizManager the questions and answers get added into the data structure(quizList) that I mentioned. The method for activating the quiz(ActivateQuiz), that I mentioned previously, which gets invoked by the previous script(QuizPanel), is inside of this script(QuizManager).

This is where the issue happens.

In the ActivateQuiz method I first check whether all questions have been answered previously. This logic serves the sole purpose so that after all questions have been answered correctly at least once the quiz has a screen where it says something like “congratulations you’ve completed this quiz, move on to the next quiz panel”.

Afterwards comes the logic for taking the questions from quizList data structure and filling the Toggles, question text etc.

To get back on track.

I have an index for each question and I do a check here. A pretty basic if statement like:

if QuestionIndex >= QuizList.count
return

… here’s the problem

this if is always triggered, therefor the return happens.

The questions in the Start method weren’t populated into the QuizList before this check happens hence why it “seems” as if all questions were already answered.

To me this looks like a synchronization issue.

How do I know this? I set breakpoints and attached a debugger to unity. I pressed play and did the interacting with the 2D Game Object. The script for activating the canvas itself is setup so that it if the player is in range of the 2D Quiz panel game object and a button on the keyboard was pressed the ActivateQuiz method of QuizManager is called.

I’d really appreciate any help so please if you think you can, don’t hesitate to write a reply.

Good to see you working on structuring your code. One suggestion I always make is not to “plop” business logic (your game in the case) in the middle of methods. When possible define things like conditions in private methods (public if needed). So instead of if(QuestionIndex >= QuizList.Count) you would define a method or property named something like GameEnded. It would contain that same logic but the big benefit is (as is the case here) you can add more logic to that method and anything relying on it is corrected.

It makes the code testable without directly playing the game in many cases as well.

So you may need to add “&& QuizListCount > 0” to your condition to test if the QuizList has elements yet. You can obviously add addition Boolean variables like _gameStarted and set, clear and check them as well.

Not sure what you mean by 'synchronising". Not really a thing in code. Stuff happens one by one, one after another, particularly in the single-thread nature of Unity’s core functionality. And sometimes you need to make these one-by-one things happen in the right order.

Hard to answer without seeing the code. But consider that you have Awake that happens before Start. Ideally you do self-initialisation in Awake, and any initialisation that cares about other objects being read in Start.

Thank you!

The root issue still lies with the timing of the Start() method, especially when ActivateQuiz() gets called before quizList is populated. The issue I’m encountering happens because ActivateQuiz is being called before the Start() method of QuizManager completes, meaning that the questions are not added to quizList in time.

Your mention of Awake is entirely new to me. I didn’t know about Awake.

I think the solution will after all be moving Quiz Initialization out of Start() of QuizManager so that the quiz data is explicitly initialized before player interaction can happen. However I’m not sure where to put it and how to restructure the code yet.

“Not sure what you mean by 'synchronising”. Not really a thing in code." - ooooh my friend, you’re very much wrong to say this. In operating systems(which I know we’re not programming but still) we’d need to synchronize access between competing threads that could access shared resources at unpredictable times.

“sometimes you need to make these one-by-one things happen in the right order.” - this is ultimately what I’m trying to achieve.

“Single-threaded execution: Unity’s main game loop is inherently single-threaded, so there’s no need to worry about thread contention like in multi-threaded operating systems.” You learn something new every day. I thought there we multiple threads racing for it.

Honestly new coders (and sometimes long time coders) have very weird assumptions about how code works, so that was me trying to remove the mystique behind it. I assumed the term was being used for lack of a better understanding as to how code executes, but you’re right.

You definitely should make yourself familiar with the order of execution chart: Unity - Manual: Order of execution for event functions

But yeah there’s no threading going on in normal Unity stuff. Unity’s core is single-threaded and accessing it outside the main thread will also throw errors. Even async C# code in Unity is bound to the main thread by a custom synchronisation context.

Unity wouldn’t be a very useful engine if threading was getting in the way of our day-to-day usage.

There are several factors which led me to figure out what the problem is(quizList not being populated when the method ActivateQuiz is called leading to a sort of check like 0 >= 0 in the if and then the return getting triggered every time). I set multiple breakpoints in several method call and looked at which breakpoint was triggered in what order.

“So you may need to add “&& QuizListCount > 0” to your condition to test if the QuizList has elements yet.” - I actually thought of something like this, but I did a different approach, here’s what I did:

Added a flag isQuizInitialized bool(set it to false initially) to ensure the quiz data had to have been initialized before any interaction. There’s an if inside ActivateQuiz which prevents the further execution of this method from continuing unless the isQuizInitialized bool was true at that point. When the quiz data is filled into quizList in Start method, I set the bool to true. This makes it so that it’s 100% that the data was loaded before the execution of the code inside ActivateQuiz.

The problem with this approach however is:

If the isQuizInitialized flag is checked and found to be false, and the method ActivateQuiz simply returns, the quiz will never actually get initialized(questions, answers etc. displayed) later when the quiz data is ready. In this case, just checking the flag once would not help us achieve the desired outcome. We’re not giving the quiz a chance to “try again” after the data has been initialized.

I thought maybe doing an approach which involves continuously checking the condition in a loop until it becomes true, but since Unity is single threaded this is just nonsense and altogether doing this is not a good approach. It’s just wasting CPU cycles.

First, recognize (and I’ll guess that you do) that thousands of developers are writing similar code with order dependency involved. So you should look for an elegant, reusable solution that serves your needs.

There isn’t any code posted so I can’t make specific suggestions but I will say for my latest project (a VRChat world) I’ve come up with a framework that solves the start-up problem and permits me to control the order of initializations.

I don’t think you need to go to this extreme as VRChat doesn’t give us access to Awake. The non-deterministic order of calls to Start was a major problem.

You can create Init methods or a class (I used the name Initable) and subclass the classes that need that functionality from it. Again you probably don’t need to do this but I did.

There are “timed” call backs and often there are perfectly fine spots for “hooks” into required processes. VRChat is multiplayer so there is OnPlayerJoined, etc.

In the end I’m saying there is a “non-weird” solution. Give it more thought and search around a bit. One idea that pops into my head is that ActivateQuiz (should be part of Quiz class I imagine) could see if it is ready to go. If not it loads the quiz questions.

Diagram a little pseudocode to visualize what needs to occur without having to think in C# terms.

I don’t understand your specific problem but both unity and unreal in general have some areas where the code will not execute when you were expecting it to execute because it depends of other factors, like for example loading of an asset from the web, just to have a really obvious example.

you can go around these limitations by using events and callbacks and stuff like that where pieces of code will be executed when you are sure that the assets you are using are ready