/// <summary>
    /// Called at beginning of game.
    /// Generates a X_MAX x Z_MAX tile grid out of the tile gameobject
    /// </summary>
    public void GenerateGrid()
    {
        // Builds walls that encompass the playmat.
        BuildAWall(-1, Z_MAX, -1, 'z', toyBlock);           // West wall
        BuildAWall(-1, Z_MAX, X_MAX, 'z', toyBlock);        // East wall
        BuildAWall(0, X_MAX, -1, 'x', toyBlock);            // South wall
        BuildAWall(-1, X_MAX + 1, Z_MAX, 'x', toyBlock);    // North wall

        GenerateTiles();

        GameGrid2DObject grid = ProcedurallyPlaceObstacles(toyBlock);

        PlaceResources(grid, fluff, plastic);

        //minionNavMeshSurface.BuildNavMesh();  // only bake after obstacles have been placed
        bakeNavMesh();
    }
    /// <summary>
    /// Places resources around the grid, making sure not to collide with existing objects.
    /// </summary>
    /// <param name="grid">reference to grid object for tile access</param>
    /// <param name="fluff">an array for holding fluff game objects</param>
    /// <param name="plastic">an array for holding plastic game objects</param>
    private void PlaceResources(GameGrid2DObject grid, GameObject[] fluff, GameObject[] plastic)
    {
        // Tear down any leftover resources hanging out in resourceFondler from previous runs
        resourceFondler.transform.DetachChildren();

        List <GameObject> fluffs   = new List <GameObject>();
        List <GameObject> plastics = new List <GameObject>();

        //int gridLoopCount = 0;

        // Keep looping around the grid until the max for each type of resource has been fulfilled
        while (fluffs.Count < maxFluff || plastics.Count < maxPlastic)
        {
            foreach (TileObject t in grid)
            {
                int placeChance = Random.Range(0, 100);

                // if current tile is "empty" and if percent chance of placement is fulfilled
                if (t.type == TileObject.TileType.TRAVERSABLE && placeChance < chanceOfResourceSpawn)
                {
                    int coinFlip = Random.Range(0, 2);

                    GameObject resource;

                    // Flip a coin; either spawn a fluff or plastic resource
                    if (coinFlip % 2 == 0 && fluffs.Count < maxFluff)
                    {
                        resource = Instantiate(
                            fluff[Random.Range(0, 4)],
                            new Vector3(t.location.x, 0.3f, t.location.y),
                            Quaternion.identity);

                        fluffs.Add(resource);

                        // Set as child of resourceFondler
                        resource.transform.parent = resourceFondler.transform;

                        t.type = TileObject.TileType.RESOURCE;
                    }
                    else if (coinFlip % 2 == 1 && plastics.Count < maxPlastic)
                    {
                        resource = Instantiate(
                            plastic[Random.Range(0, 4)],
                            new Vector3(t.location.x, 0.3f, t.location.y),
                            Quaternion.identity);

                        plastics.Add(resource);

                        // Set as child of resourceFondler
                        resource.transform.parent = resourceFondler.transform;

                        t.type = TileObject.TileType.RESOURCE;
                    }
                }

                // No need to keep looping if max count is reached, just return
                if (fluffs.Count == maxFluff && plastics.Count == maxPlastic)
                {
                    //Debug.Log("Returning early: fluff count: " + fluffs.Count + " plastic count: " + plastics.Count);
                    return;
                }
            }

            //gridLoopCount++;
        }

        //Debug.Log("Returning at very end: fluff count: " + fluffs.Count + " plastic count: " + plastics.Count);
        //Debug.Log("Grid Loop Count: " + gridLoopCount);
    }
    /// <summary>
    /// Places obstacle objects on the board,
    /// such that one can always traverse between the two bases on opposite corners of the board.
    /// Find some balance of the two paramters such that the board designs are generally favorable.
    /// These can be changed to your preference - you do you!
    /// Please note that this runs in O( |pathLandmarks|^2 ),
    /// and the lag really gets noticable around pathLandmarks = 50.
    /// </summary>
    /// <param name="obstacleTemplate">GameObject which should be instantiated as objects</param>
    private GameGrid2DObject ProcedurallyPlaceObstacles(GameObject[] obstacleTemplate)
    {
        // Tear down any leftover tiles hanging out in obstacleFondler from previous runs
        obstacleFondler.transform.DetachChildren();

        // First, generate new grid
        GameGrid2DObject tempGrid = new GameGrid2DObject(new Coord2DObject(X_MAX, Z_MAX), pathWidth, pathLandmarks, BASE_WIDTH);

        // Then, iterate through that grid.
        // Every time you see a Tile whose type is NON_TRAVERSABLE,
        // instantiate a Wall object at that location,
        // and add it to ObstacleFondler
        foreach (TileObject t in tempGrid)
        {
            // Skip empty or traversable tiles
            if (t.type != TileObject.TileType.NON_TRAVERSABLE)
            {
                continue;
            }

            GameObject tempObstacle;

            int rotationChance = Random.Range(0, 3);

            // Create new obstacle and rotate randomly by either 0/90/180/270 degree angles on the y-axis
            switch (rotationChance)
            {
            case 0:
                tempObstacle = Instantiate(
                    obstacleTemplate[Random.Range(0, obstacleTemplate.Length)],      // use random template
                    new Vector3(t.location.x, 0.5f, t.location.y),
                    Quaternion.Euler(0, 0, 0));

                // Set as child of obstacleFondler
                tempObstacle.transform.parent = obstacleFondler.transform;
                explodeBoard.AddPiece(tempObstacle);
                break;

            case 1:
                tempObstacle = Instantiate(
                    obstacleTemplate[Random.Range(0, obstacleTemplate.Length)],      // use random template
                    new Vector3(t.location.x, 0.5f, t.location.y),
                    Quaternion.Euler(0, 90, 0));

                // Set as child of obstacleFondler
                tempObstacle.transform.parent = obstacleFondler.transform;
                explodeBoard.AddPiece(tempObstacle);
                break;

            case 2:
                tempObstacle = Instantiate(
                    obstacleTemplate[Random.Range(0, obstacleTemplate.Length)],      // use random template
                    new Vector3(t.location.x, 0.5f, t.location.y),
                    Quaternion.Euler(0, 180, 0));

                // Set as child of obstacleFondler
                tempObstacle.transform.parent = obstacleFondler.transform;
                explodeBoard.AddPiece(tempObstacle);
                break;

            case 3:
                tempObstacle = Instantiate(
                    obstacleTemplate[Random.Range(0, obstacleTemplate.Length)],      // use random template
                    new Vector3(t.location.x, 0.5f, t.location.y),
                    Quaternion.Euler(0, 270, 0));

                // Set as child of obstacleFondler
                tempObstacle.transform.parent = obstacleFondler.transform;
                explodeBoard.AddPiece(tempObstacle);
                break;

            default:
                Debug.LogError("rotationChance: " + rotationChance);
                break;
            }
        }

        return(tempGrid);
    }