// append level data to queue of rows
        public void BuildLevel(int levelID)
        {
            difficulty = levelID;
            // load level from disk
            Level level = LoadLevel(levelID);

            // initialize instance containers
            m_spawnedInstanceContainer = Instantiate(new GameObject(), Vector3.zero, Quaternion.identity);
            m_spawnedInstances         = new List <GameObject>();

            // load save data
            bool levelHasBeenPlayed = false;

            in_levelSaveData = new SaveData(levelID.ToString(), out levelHasBeenPlayed);

            //set seed
            m_seed = levelID;

            // initialize queue
            m_level = new Queue <BlockRow>();

            // loop through each block group in level
            int k = 0;

            foreach (BlockGroup group in level.m_level)
            {
                // loop through each row of block group
                for (int i = group.height - 1; i >= 0; i--)
                {
                    // create new row struct
                    BlockRow row = new BlockRow(BlockData.Columns);
                    // assign the appropriate data to each block
                    for (int j = 0; j < BlockData.Columns; j++)
                    {
                        row.blocks[j] = group.m_layout.blocks[i * BlockData.Columns + j];
                    }

                    row.difficultyBalance = level.m_difficultyBalance[k];

                    // check if this is the last row in the group.
                    // if true, set a flag to signify this
                    if (i == 0)
                    {
                        row.groupEnd = true;
                    }

                    // push row into queue
                    m_level.Enqueue(row);
                }
                k++;
            }

            m_currencyCount = level.m_currencyCount;

            if (GameController.Instance.userData.controlGroup)
            {
                GenerateCurrencyPositions(level);
            }
        }
        // a function to spawn a row of blocks
        public void SpawnRow()
        {
            // check that there are still blocks to be spawned
            if (m_level.Count <= 0)
            {
                return;
            }

            // get latest row from the queue
            BlockRow row = m_level.Dequeue();

            // create list of all available spaces in this row
            List <int> availableSpaces = new List <int>();

            for (int i = 0; i < BlockData.Columns; i++)
            {
                if (row.blocks[i] == BlockType.NONE)
                {
                    availableSpaces.Add(i);
                }
            }
            // generate currency spawn position
            int currencySpace = 0;

            if (availableSpaces.Count > 0)
            {
                currencySpace = availableSpaces[Random.Range(0, availableSpaces.Count)];
            }

            // loop through each block
            for (int i = 0; i < BlockData.Columns; i++)
            {
                // calculate the offset
                float offset = 1.0f / ((float)BlockData.Columns * 20.0f);

                // calculate the position on the x axis to spawn the block
                float anchor = (1.0f / (float)BlockData.Columns) * (float)i;

                // convert the screen space coordinate to world space
                if (!m_camera)
                {
                    return;
                }

                Vector3 pos = m_camera.ViewportToWorldPoint(new Vector3(anchor + offset, 1.25f, 0));
                pos = new Vector3(pos.x, pos.y, 0);

                // instantiate new prefab
                switch (row.blocks[i])
                {
                case BlockType.DEFAULT:
                case BlockType.LARGE:
                {
                    GameObject block = CreateBlock(pos, row.blocks[i]);
                    SetHealth(block, row.difficultyBalance, i);
                }
                break;

                case BlockType.INDESTRUCTABLE:
                {
                    CreateBlock(pos, row.blocks[i]);
                }
                break;

                case BlockType.NONE:
                {
                    if (m_currencyPositions.Contains(m_rowNum) && i == currencySpace)
                    {
                        if (!in_levelSaveData.IsCoinCollected(m_currencyPositions.IndexOf(m_rowNum)))
                        {
                            GameObject currency = Instantiate(in_currencyPrefab, pos, Quaternion.identity);
                            currency.transform.SetParent(m_spawnedInstanceContainer.transform);
                            currency.GetComponent <CurrencyPickup>().fallSpeed    = m_fallSpeed;
                            currency.GetComponent <CurrencyPickup>().screenHeight = m_camera.ViewportToWorldPoint(new Vector3(1, 0, 1)).y;
                            currency.GetComponent <CurrencyPickup>().in_saveData  = in_levelSaveData;
                            currency.GetComponent <CurrencyPickup>().in_coinId    = m_currencyPositions.IndexOf(m_rowNum);
                            m_spawnedInstances.Add(currency);
                        }
                    }
                }
                break;
                }
            }

            // calculate spacing between this row and the next.
            // space determined depending on whether or not the
            // next row is in the same group or a new group.
            float spacer = (row.groupEnd) ? m_groupSpacing : 1;

            // calculate the time to wait using the v = dt formula
            StartCoroutine(WaitToSpawnNextRow((m_blockSpacing / m_fallSpeed) * spacer));
        }