0
\$\begingroup\$

I'm working on a Tower Defence style game, and wondering how best to handle the "resources" part. I have multiple enemies on screen at a time, and when an enemy dies, it updates a resource that allows the player to build more towers

var tower = Instantiate(buildables[0], center, Quaternion.identity);
var controller = tower.GetComponent<TowerController>();
controller.OnKilledEnemy += (sender, args) =>
{
    int.TryParse(goldAmount.text.Replace(",", ""), out var curr);
    curr += args.gold;
    goldAmount.text = $"{curr:n0}";
};

But if 2 enemies die in the same frame, wouldn't the value there miss an update?

What ways are there in Unity/C# to mitigate this problem?

\$\endgroup\$
4
  • \$\begingroup\$ Why do you think that a C# event (I assume controller.OnKilledEnemy is one) would only be possible to trigger once per update? But besides that, it's not a good idea to use the string representation of the gold amount as its primary storage method. It would be far better to have a separate int variable to keep track of the current gold amount. \$\endgroup\$
    – Philipp
    Mar 29, 2021 at 10:46
  • \$\begingroup\$ And display elements should only exactly that: display values. Not used for calculating or relied on how much gold you have. \$\endgroup\$
    – Zibelas
    Mar 29, 2021 at 10:47
  • \$\begingroup\$ I agree about using a central place to sort the value, however I think it could still have the same problem? I think from my game, a tower can only attack 1 enemy at a time, but I was thinking multiple controllers could fire the event at the same time, causing the issue? Or is the C# event system smart enough to avoid that? \$\endgroup\$
    – TMH
    Mar 29, 2021 at 10:49
  • \$\begingroup\$ It's not smart enough to avoid that, it is dumb enough to avoid that. See my answer for details. \$\endgroup\$
    – Philipp
    Mar 29, 2021 at 11:07

1 Answer 1

3
\$\begingroup\$

When a C# event gets invoked 2 times, then it will get executed 2 times. It doesn't happen in parallel, it happens sequentially when you call .Invoke, and after all the event handlers were processed, the thread of execution continues after the .Invoke call. There is nothing to worry about here.

Your concerns might be justified if you were using a multi-threaded game engine where methods can actually be executed multiple times in parallel. In that case it would actually be possible for two threads running on two CPU cores to read the same value at the same time and then writing back the same value at the same time. That's called a race condition and is a frustrating source of impossible to reproduce bugs. But thankfully, Unity by default runs all game mechanics on a single thread. Everything gets processed in order. So it's simply not possible for an event to get fired twice "at the exact same time". What actually happens is:

  1. Update()-method of tower 1 is executed
  2. OnKilledEnemy is invoked and the event handler is executed
  3. Update()-method of tower 2 is executed
  4. OnKilledEnemy is invoked and the event handler is executed

I wrote "Unity by default" above, because with the new Jobs system it is actually possible to implement game mechanics in a multi-threaded manner. When you do use jobs and do schedule them in parallel, then you need to keep in mind that any data shared between jobs might be subject to race conditions. But if you stick to the idiomatic programming patterns recommended for the job system, this should rarely be the case, because the job system tries its best to stop you from doing that.

\$\endgroup\$
1
  • \$\begingroup\$ Ahh that's awesome, I didn't realise everything in Unity was single threaded (ignoring Jobs). \$\endgroup\$
    – TMH
    Mar 29, 2021 at 11:45

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .