Home > Back-end >  Game not printing or updating when AI is thinking
Game not printing or updating when AI is thinking

Time:02-08

I have a game I am developing in Unity where AI is doing large calculations when it is its turn. It searches the position to depth 1, then 2, then 3 etc. Between each depth I want to instantiate a Gameobject with info about the depth to UI. The problem is that nothing happens until the AI is completely finished, then all items are added at once. Here is some code to explain better:

private void AIMakeMove()
{
    for (int currentDepth = 1; currentDepth < maxDepth   1; currentDepth  )
    {
        SearchPosition(currentDepth);
    }
}
 
private void SearchPosition(int _currentDepth)
{
    // Search the position to the given depth
    score = Negamax(_currentDepth);
 
     // Print things   PROBLEM HERE
    GameObject printItem = Instantiate(printItemPrefab, printItemParent.transform);
    Debug.Log(_currentDepth);
}

I also tried just a simple Debug.Log instead of Instantiate but same thing happens then, all prints to console happens after the AI is done with its thinking process.

Why is my UI not updating with information? I tell it to create some things after it run the first iteration with depth 0 but it skips this step and goes on depth 2 instead. Can someone please let me know how to get information out between each depth?

CodePudding user response:

The problem is that nothing happens until the AI is completely finished

well the UI is only updated if the Unity main-thread is allowed to finish a frame.

You, however, block the main thread until all iterations are finished.


If it is okey for you to block between each instantiation then you could simply use a Coroutine and do something like

private void AIMakeMove()
{
    StartCoroutine(AIMakeMoveRoutine());
}

private IEnuemrator AIMakeMoveRoutine()
{
    for (int currentDepth = 1; currentDepth < maxDepth   1; currentDepth  )
    {
        SearchPosition(currentDepth);

        // This now tells Unity to "interrupt" this routine here
        // render the current frame and continue from here in the next frame
        yield return null;
    }
}
 
private void SearchPosition(int _currentDepth)
{
    score = Negamax(_currentDepth);
 
    GameObject printItem = Instantiate(printItemPrefab, printItemParent.transform);
    Debug.Log(_currentDepth);
}

This will finish a frame and start a new one (thus refresh the UI) after each finished iteration.


However, if this still blocks the rest of your application too much you should additionally actually run the calculation async e.g. using a Task like

private void AIMakeMove()
{
    StartCoroutine(AIMakeMoveRoutine());
}

private IEnuemrator AIMakeMoveRoutine()
{
    for (int currentDepth = 1; currentDepth < maxDepth   1; currentDepth  )
    {
        // you can yield another IEnuemrator -> executes this and waits for it to finish
        yield return SearchPosition(currentDepth);

        // This now tells Unity to "interrupt" this routine here
        // render the current frame and continue from here in the next frame
        yield return null;
    }
}
 
private IEnumerator SearchPosition(int _currentDepth)
{
    // run the NegamaxTask asynchronously in the background
    var task = Task.Run(() => Negamax(_currentDepth));
    // wait for the task to finish
    while(!task.IsCompleted)
    {
        // do nothing but skip frames to allow the rest of the application to run smoothly
        yield return null;
    }
    // If you do nothing else inside the loop this could also be written as
    //yield return new WaitWhile(() => !task.IsComoleted);
    // or
    //yield return new WaitUntil(() => task.IsCompleted);

    // since the task is already finished it is save / non-blocking to access the result now
    score = task.Result;
 
    var printItem = Instantiate(printItemPrefab, printItemParent.transform);
    Debug.Log(_currentDepth);
}

Now this allows your application to continue with a normal frame-rate while in the background you do the heavy calculations and once in a while get a result back when an iteration is finished.

CodePudding user response:

Try using a thread:

private void AIMakeMove()
    {
        new System.Threading.Thread(() =>
        {
            for (int currentDepth = 1; currentDepth < maxDepth   1; currentDepth  )
            {
                SearchPosition(currentDepth);
            }
        }).Start();
    }

    private void SearchPosition(int _currentDepth)
    {
        // Search the position to the given depth
        score = Negamax(_currentDepth);

        // Print things   PROBLEM HERE
        GameObject printItem = Instantiate(printItemPrefab, printItemParent.transform);
        Debug.Log(_currentDepth);
    }
  •  Tags:  
  • Related