Async methods and Update()

My game is turn based. Between turns I want to display what’s going on (AI being calculated, Blue units being moved, Range of Influence being calculated, etc.):

The problem is that these are async methods and I wonder if they’re going away and Update() and Draw() aren’t being called until they return.

For example, here’s a method with a boolean that’s supposed to cause text to be updated on the screen (above) when it hits Draw():

  private async Task CalculateCourierPathsBlue()
        {
            IEnumerable<CountPaths.MyPathNode> tPointList;
            List<PointI> tList;

            TabDisplayCalculatingBlueCourierRoutes  = true;


            for (int i = 0; i < BlueArmy.Count; i++)
            {
                BlueArmy[i].CourierRoutes.Clear();
                BlueArmy[i].TotalOrdersDelayTime = 0;
            }

            for (int i = 1; i < BlueArmy.Count; i++)
            {

                tPointList = CountPaths.IsPathFromA2B(true, (int)BlueArmy[i].Location.X, (int)BlueArmy[i].Location.Y,
                    (int)BlueArmy[ConvertID2Index(true, BlueArmy[i].CommandingUnit)].Location.X,
                    (int)BlueArmy[ConvertID2Index(true, BlueArmy[i].CommandingUnit)].Location.Y, true, true, true);

                if (tPointList != null)
                {
                    tList = Defense.ConvertPathNodes2PointList(tPointList);
                    BlueArmy[i].CourierRoutes.Add(tList);
                    BlueArmy[ConvertID2Index(true, BlueArmy[i].CommandingUnit)].CourierRoutes.Add(tList);
                }
            } // for i

            TabDisplayCalculatingBlueCourierRoutes = false;

        } // CalculateCourierPathsBlue

And this method gets called like this:

   public async void CalculateCourierPaths()
        {
            Task CalculateCourierPathsRedTask = Task.Run(() => { CalculateCourierPathsRed(); });
            Task CalculateCourierPathsBlueTask = Task.Run(() => { CalculateCourierPathsBlue(); });

            CalculateCourierPathsRedTask.Wait();
            CalculateCourierPathsBlueTask.Wait();

        } // CalculateCourierPaths

Any thoughts on making sure that Update() and Draw() get called while these Async methods are off doing their thing?

Thanks for all the help!

You are calling Task.Wait right after Task.Run. There is no time for anything to run in between those two. You would need to call wait at a later time.

Are you sure it makes sense to go multi-threaded for this? The code in the loop doesn’t look that expensive, unless the blue army is really large.

You know, you may be right. It may not be necessary to go multi-threaded. At first, I thought it was going to far too time consuming (between turns). It’s running about 30 seconds for really big battles (both armies about 50 units; the real time consumption is calling A* n2 times to calculate ‘courier routes’ from HQs to the units.

It is nice, however, that the AI does it’s calculations asynchronously while the user is making his moves. It proves the AI isn’t cheating. :wink:

Actually I multi-threaded all my path finding in one of my games since I do not know how long it will take, and I wanted to have hundreds of units, all units moved using the same logic as the player, so the AI gave orders to all other units by planning all the positions for all units to move and what to do, the main loop just interpolated the positions as it needed to do and it worked really nice, this was for a kind of RTS thing.
Whenever a unit will be obstructed by another it will wait or redo the path finding depending on how long it waited.

By the way , some paths took more than 1 frame to 3-5 frames in rendering time, if you think about 60 FPS, so this was needed to have everything moving.

I could easily have 1000 units running in parallel and the more threads I added the faster it ran, the thing is that by doing that you create the illusion to the player that the AI is working on all units at the same time, but it actually works only with a few at a time, and by pooling the orders you will be able to see in real time that pretty much everything is moving at the same time , but in reality only a few are calculated per update cycle.

I glanced over your code too quickly. Without knowing what’s inside
IsPathFromA2B my judgment was obviously premature.

CalculateCourierPathsRed();
CalculateCourierPathsBlue();

Make your life easier and turn this into:

CalculateCourierPaths(redArmy);
CalculateCourierPaths(blueArmy);

Having two separate code paths here is an unneccessary burden.

Some methods I can do that, others like CalculateCourierPaths really have too much different code for one method doing double duty.

Oh, the red and blue army are asymmetric. I guess I judged prematurely for the second time then :slight_smile:

1 Like

Nothing wrong with identifying potential issues or improvements and bringing them up, you get a heart for being helpful. @markus

2 Likes

Yeah, Red and Blue are very asymmetrical. But, you didn’t know that.
You guys have been incredibly helpful to me! Thanks a million!

2 Likes

Remove the task.Wait(); calls as they hang the game. Instead you need to store CalculateCourierPathsTask somewhere and it’s done when CalculateCourierPathsTask.isCompleted

1 Like

Thanks!