2048 Game Null Reference Exception with fast inputs

I am working on a 2048 style game, and applying ML-Agents to see if it learns how to play the game. The game works and is functional and playable, unless there are super fast movements. I can recreate this by spamming the input keys a bunch, but the ML-Agent will create this error every time. In ShiftPanels.cs(shown after this description), I have a GameObject.Find() when moving left to find the current panel on the screen in UI. This is null sometimes, only when we are going super fast. Another thing is the gameBoardArray[x,yj] is not updated at this point. Below is all the scripts used for moving the panels, I only included moving left because everything else is mainly the same, just modified some math, etc… Is ShiftPanels.cs the cause? How do I fix it? Appreciate the help in advance!!!
PanelPhysics.cs:

using UnityEngine;

public class PanelPhysics : MonoBehaviour
{
    [SerializeField] private ShiftPanels shiftPanelsScript;
    [SerializeField] private CombinePanels combinePanelsScript;
    [SerializeField] private PanelInstantiator panelInstantiatorScript;
    [SerializeField] private UpdatePanelColors updatePanelColorsScript;

    [SerializeField] private GameState gameStateScript;

    public GameObject panel;
    public GameObject game;

    [HideInInspector] public int[] fibonacciArray = new int[] { 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, 144, 233, 377, 610, 987, 1597, 2584 };
    public int[,] gameBoardArray = new int[4, 4];

    [HideInInspector] public bool canShift = false;
    [HideInInspector] public bool canCombine = false;

    [HideInInspector] public bool isMoveActive = false;

    public void ResetGame()
    {
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                gameBoardArray[i, j] = 0;
                Destroy(GameObject.Find("Panel_Prefab_" + (i * 4 + j)));
            }
        }

        panelInstantiatorScript.SpawnRandomPanel();
        panelInstantiatorScript.SpawnRandomPanel();
        updatePanelColorsScript.UpdateColors();
    }

    public void MovePanelsLeft()
    {
        isMoveActive = true;

        ResetVariables();

        shiftPanelsScript.ShiftPanelsLeft();
        combinePanelsScript.CombinePanelsLeft();
        shiftPanelsScript.ShiftPanelsLeft();

        if ((canShift) || (canCombine))
        {
            panelInstantiatorScript.SpawnRandomPanel();
            updatePanelColorsScript.UpdateColors();
        }

        gameStateScript.CheckLoseCondition();
        gameStateScript.CheckWinCondition();

        isMoveActive = false;
    }

    public void ResetVariables()
    {
        shiftPanelsScript.iterator = 0;
        shiftPanelsScript.previousTilesIterator = 0;
        canShift = false;
        canCombine = false;
    }
}

ShiftPanels.cs:

using UnityEngine;

public class ShiftPanels : MonoBehaviour
{
    [SerializeField] private PanelPhysics panelPhysicsScript;

    [HideInInspector] public int iterator = 0;
    [HideInInspector] public int previousTilesIterator = 0;

    public void ShiftPanelsLeft()
    {
        for (int i = 0; i < 4;  i++)
        {
            for (int j = 0; j < 4; j++)
            {
                if (panelPhysicsScript.gameBoardArray[i, j] != 0)
                {
                    for (int k = 1; k < 4; k++)
                    {
                        //decrement row from right to left
                        if ((i - k >= 0) && (panelPhysicsScript.gameBoardArray[(i - k), j] != 0))
                        {
                            previousTilesIterator++;
                        }
                    }
                    int shiftingInt = Mathf.FloorToInt(iterator / 4) - previousTilesIterator;
                    int newPosX = i - shiftingInt;

                    GameObject currentPanel = GameObject.Find("Panel_Prefab_" + iterator);
                    Vector3 currentOldPos = currentPanel.transform.position;

                    Vector3 currentNewPos = new Vector3(currentPanel.transform.position.x - 480 * shiftingInt, currentPanel.transform.position.y, currentPanel.transform.position.z);

                    if (currentNewPos != currentOldPos)
                    {
                        panelPhysicsScript.gameBoardArray[newPosX, j] = panelPhysicsScript.gameBoardArray[i, j];
                        panelPhysicsScript.gameBoardArray[i, j] = 0;

                        currentPanel.transform.position = currentNewPos;
                        currentPanel.name = "Panel_Prefab_" + ((newPosX * 4) + j);

                        if (!panelPhysicsScript.canShift)
                            panelPhysicsScript.canShift = true;
                    }
                }

                previousTilesIterator = 0;
                iterator++;
            }
        }
        iterator = 0;
    }

CombinePanels.cs:

using Google.Protobuf.WellKnownTypes;
using System;
using TMPro;
using UnityEngine;

public class CombinePanels : MonoBehaviour
{
    [SerializeField] private PanelPhysics panelPhysicsScript;
    [SerializeField] private TestScriptAgent testScriptAgentScript;

    public void CombinePanelsLeft(bool shouldUpdatePanels = true)
    {
        for (int i = 0; i < 4; i++)
        {
            for (int j = 0; j < 4; j++)
            {
                if ((panelPhysicsScript.gameBoardArray[i, j] != 0) && (i + 1 <= 3) && (panelPhysicsScript.gameBoardArray[(i + 1), j] != 0))
                {
                    GameObject currentPanel = GameObject.Find("Panel_Prefab_" + (i * 4 + j));
                    GameObject nextPanel = GameObject.Find("Panel_Prefab_" + ((i + 1) * 4 + j));

                    int currentIndex = Array.IndexOf(panelPhysicsScript.fibonacciArray, panelPhysicsScript.gameBoardArray[i, j]);
                    int nextIndex = Array.IndexOf(panelPhysicsScript.fibonacciArray, panelPhysicsScript.gameBoardArray[(i + 1), j]);

                    if ((currentIndex == (nextIndex + 1)) || (currentIndex == (nextIndex - 1)))
                    {
                        panelPhysicsScript.canCombine = true;

                        if (shouldUpdatePanels)
                        {
                            int newNum = panelPhysicsScript.gameBoardArray[i, j] + panelPhysicsScript.gameBoardArray[(i + 1), j];
                            panelPhysicsScript.gameBoardArray[i, j] = newNum;
                            panelPhysicsScript.gameBoardArray[(i + 1), j] = 0;

                            currentPanel.GetComponentInChildren<TMP_Text>().text = panelPhysicsScript.gameBoardArray[i, j].ToString();
                            Destroy(nextPanel);

                            testScriptAgentScript.AddCombineReward(newNum);
                        }
                    }
                    else if ((panelPhysicsScript.gameBoardArray[i, j] == 1) && (currentIndex == nextIndex))
                    {
                        panelPhysicsScript.canCombine = true;

                        if (shouldUpdatePanels)
                        {
                            panelPhysicsScript.gameBoardArray[i, j] = 2;
                            panelPhysicsScript.gameBoardArray[(i + 1), j] = 0;

                            currentPanel.GetComponentInChildren<TMP_Text>().text = panelPhysicsScript.gameBoardArray[i, j].ToString();
                            Destroy(nextPanel);

                            testScriptAgentScript.AddCombineReward(2);
                        }
                    }
                }
            }
        }
    }

ML-Agents Script:

using Unity.MLAgents.Actuators;
using Unity.MLAgents.Sensors;
using UnityEngine;

public class TestScriptAgent : Agent
{
    [SerializeField] private PanelPhysics panelPhysicsScript;

    private bool isAxisInUse = false;

    public override void OnEpisodeBegin()
    {
        panelPhysicsScript.ResetGame();
    }

    public override void CollectObservations(VectorSensor sensor)
    {
        isAxisInUse = false;
        sensor.AddObservation(panelPhysicsScript.gameBoardArray[0, 0]);
        sensor.AddObservation(panelPhysicsScript.gameBoardArray[0, 1]);
        sensor.AddObservation(panelPhysicsScript.gameBoardArray[0, 2]);
        sensor.AddObservation(panelPhysicsScript.gameBoardArray[0, 3]);
        sensor.AddObservation(panelPhysicsScript.gameBoardArray[1, 0]);
        sensor.AddObservation(panelPhysicsScript.gameBoardArray[1, 1]);
        sensor.AddObservation(panelPhysicsScript.gameBoardArray[1, 2]);
        sensor.AddObservation(panelPhysicsScript.gameBoardArray[1, 3]);
        sensor.AddObservation(panelPhysicsScript.gameBoardArray[2, 0]);
        sensor.AddObservation(panelPhysicsScript.gameBoardArray[2, 1]);
        sensor.AddObservation(panelPhysicsScript.gameBoardArray[2, 2]);
        sensor.AddObservation(panelPhysicsScript.gameBoardArray[2, 3]);
        sensor.AddObservation(panelPhysicsScript.gameBoardArray[3, 0]);
        sensor.AddObservation(panelPhysicsScript.gameBoardArray[3, 1]);
        sensor.AddObservation(panelPhysicsScript.gameBoardArray[3, 2]);
        sensor.AddObservation(panelPhysicsScript.gameBoardArray[3, 3]);
    }

    public override void OnActionReceived(ActionBuffers actions)
    {
        if ((!isAxisInUse) && (!panelPhysicsScript.isMoveActive))
        {
            isAxisInUse = true;
            if (actions.DiscreteActions[0] == 0)
            {
                Debug.Log("LEFT");
                panelPhysicsScript.MovePanelsLeft();
            }
            if (actions.DiscreteActions[0] == 1)
            {
                Debug.Log("RIGHT");
                panelPhysicsScript.MovePanelsRight();
            }
            if (actions.DiscreteActions[1] == 0)
            {
                Debug.Log("DOWN");
                panelPhysicsScript.MovePanelsDown();
            }
            if (actions.DiscreteActions[1] == 1)
            {
                Debug.Log("UP");
                panelPhysicsScript.MovePanelsUp();
            }
        }
    }

    public override void Heuristic(in ActionBuffers actionsOut)
    {
        ActionSegment<int> discreteActions = actionsOut.DiscreteActions;

        isAxisInUse = false;

        int horizontalAxis = (int)Input.GetAxisRaw("Horizontal");
        int verticalAxis = (int)Input.GetAxisRaw("Vertical");

        //MLAgent actions can only be positive integers, so we 'transpose' from -1 to 0
        //and vise-versa, so we don't have to manually modify values when on Heuristic
        
        if (horizontalAxis == -1)
            horizontalAxis = 0;
        else if (horizontalAxis == 0)
            horizontalAxis = -1;

        if (verticalAxis == -1)
            verticalAxis = 0;
        else if (verticalAxis == 0)
            verticalAxis = -1;

        discreteActions[0] = horizontalAxis;
        discreteActions[1] = verticalAxis;
    }

    public void AddCombineReward(float rewardNum)
    {
        rewardNum /= 2584;
        AddReward(+rewardNum);
    }

    public void AddWinReward()
    {
        AddReward(+2f);
        EndEpisode();
    }

    public void AddLoseReward()
    {
        AddReward(-2f);
        EndEpisode();
    }
}

What’s the error point to?

To solve a NullReferenceException you need to follow a set of steps, and the very first one is to read the stack trace so you know what it’s talking about.

It’s not a mystery error that’s somewhere across the four scripts you’ve posted, it happened in a script on a single line.

See my troubleshooting NullReferenceException resource to learn about the steps.

So the stacktrace just said ShiftPanels then PanelPhysics then to ML-Agents OnActionRecieved, but it doesn’t really matter anymore, I got rid of the bug, by, instead of updating the panel in the ShiftPanels for loop, I just modify the array, then afterwards update the UI, so that we aren’t potentially finding old information.