/// <summary>
    /// Update the element given a distance of parallax move, t
    /// </summary>
    /// <param name="p">InfiniteScroll container</param>
    /// <param name="t">Total amount the parallax moved. Elements will move a percetage of this distance.</param>
    public void Update(InfiniteScroll p, float t, Camera c)
    {
        if (GameObjects == null || GameObjects.Count == 0 || GameObjects.Count != GameObjectRenderers.Count)
        {
            // cannot update, something went wrong in setup
            return;
        }

        // move everything first
        if (p.IsHorizontal)
        {
            foreach (GameObject obj in GameObjects)
            {
                obj.transform.Translate(t * SpeedRatio, 0.0f, 0.0f);
            }
        }
        else
        {
            foreach (GameObject obj in GameObjects)
            {
                obj.transform.Translate(0.0f, t * SpeedRatio, 0.0f);
            }
        }

        bool wrap = RepositionLogic.PositionMode != FreeParallaxPositionMode.IndividualStartOffScreen &&
                    RepositionLogic.PositionMode != FreeParallaxPositionMode.IndividualStartOnScreen;

        // if it's an individual object we let it go an extra screen width in case the player changes direction
        float padding = (wrap ? 0.0f : 1.0f);
        float minEdge, maxEdge;

        if (p.IsHorizontal)
        {
            minEdge = c.rect.x - padding;
            maxEdge = c.rect.width + padding;
        }
        else
        {
            minEdge = c.rect.y - padding;
            maxEdge = c.rect.height + padding;
        }

        int end = GameObjects.Count;

        // now check for wrapping and stuff going off screen
        for (int i = 0; i < end; i++)
        {
            GameObject obj             = GameObjects[i];
            Renderer   r               = GameObjectRenderers[i];
            Bounds     b               = r.bounds;
            Vector3    screenEdge      = (t > 0 ? c.WorldToViewportPoint(b.min) : c.WorldToViewportPoint(b.max));
            float      screenEdgeValue = (p.IsHorizontal ? screenEdge.x : screenEdge.y);

            if (wrap)
            {
                if (t > 0 && screenEdgeValue >= maxEdge)
                {
                    if (p.IsHorizontal)
                    {
                        // move to the back of the line at far left
                        float newX = (GameObjectRenderers[0].bounds.min.x - r.bounds.size.x) + p.WrapOverlap;
                        InfiniteScroll.SetPosition(obj, r, newX, r.bounds.min.y);
                    }
                    else
                    {
                        // move to the back of the line at far bottom
                        float newY = (GameObjectRenderers[0].bounds.min.y - r.bounds.size.y) + p.WrapOverlap;
                        InfiniteScroll.SetPosition(obj, r, r.bounds.min.x, newY);
                    }

                    GameObjects.RemoveAt(i);
                    GameObjects.Insert(0, obj);
                    GameObjectRenderers.RemoveAt(i);
                    GameObjectRenderers.Insert(0, r);
                }
                else if (t < 0 && screenEdgeValue <= minEdge)
                {
                    if (p.IsHorizontal)
                    {
                        // move to the front of the line at far right
                        float newX = (GameObjectRenderers[GameObjects.Count - 1].bounds.max.x) - p.WrapOverlap;
                        InfiniteScroll.SetPosition(obj, r, newX, r.bounds.min.y);
                    }
                    else
                    {
                        // move to the front of the line at far top
                        float newY = (GameObjectRenderers[GameObjects.Count - 1].bounds.max.y) - p.WrapOverlap;
                        InfiniteScroll.SetPosition(obj, r, r.bounds.min.x, newY);
                    }

                    GameObjects.RemoveAt(i);
                    GameObjects.Add(obj);
                    GameObjectRenderers.RemoveAt(i--);
                    GameObjectRenderers.Add(r);
                    end--;
                }
            }
            else if (p.IsHorizontal)
            {
                if (t > 0 && (screenEdge.y >= c.rect.height || screenEdgeValue >= maxEdge))
                {
                    if (RepositionLogicFunction != null)
                    {
                        RepositionLogicFunction(p, this, t, obj, r);
                    }
                    else
                    {
                        Vector3 leftEdge      = c.ViewportToWorldPoint(Vector3.zero);
                        float   randX         = UnityEngine.Random.Range(RepositionLogic.MinXPercent, RepositionLogic.MaxXPercent);
                        float   randY         = UnityEngine.Random.Range(RepositionLogic.MinYPercent, RepositionLogic.MaxYPercent);
                        Vector3 newWorldPoint = c.ViewportToWorldPoint(new Vector3(randX, randY));
                        InfiniteScroll.SetPosition(obj, r, leftEdge.x - newWorldPoint.x, newWorldPoint.y);
                    }
                }
                else if (t < 0 && (screenEdge.y >= c.rect.height || screenEdge.x < minEdge))
                {
                    if (RepositionLogicFunction != null)
                    {
                        RepositionLogicFunction(p, this, t, obj, r);
                    }
                    else
                    {
                        Vector3 rightEdge     = c.ViewportToWorldPoint(Vector3.one);
                        float   randX         = UnityEngine.Random.Range(RepositionLogic.MinXPercent, RepositionLogic.MaxXPercent);
                        float   randY         = UnityEngine.Random.Range(RepositionLogic.MinYPercent, RepositionLogic.MaxYPercent);
                        Vector3 newWorldPoint = c.ViewportToWorldPoint(new Vector3(randX, randY));
                        InfiniteScroll.SetPosition(obj, r, rightEdge.x + newWorldPoint.x, newWorldPoint.y);
                    }
                }
            }
            else
            {
                if (t > 0 && (screenEdge.x >= c.rect.width || screenEdgeValue >= maxEdge))
                {
                    if (RepositionLogicFunction != null)
                    {
                        RepositionLogicFunction(p, this, t, obj, r);
                    }
                    else
                    {
                        Vector3 bottomEdge    = c.ViewportToWorldPoint(Vector3.zero);
                        float   randX         = UnityEngine.Random.Range(RepositionLogic.MinXPercent, RepositionLogic.MaxXPercent);
                        float   randY         = UnityEngine.Random.Range(RepositionLogic.MinYPercent, RepositionLogic.MaxYPercent);
                        Vector3 newWorldPoint = c.ViewportToWorldPoint(new Vector3(randX, randY));
                        InfiniteScroll.SetPosition(obj, r, newWorldPoint.x, bottomEdge.y - newWorldPoint.y);
                    }
                }
                else if (t < 0 && (screenEdge.x >= c.rect.width || screenEdge.y < minEdge))
                {
                    if (RepositionLogicFunction != null)
                    {
                        RepositionLogicFunction(p, this, t, obj, r);
                    }
                    else
                    {
                        Vector3 topEdge       = c.ViewportToWorldPoint(Vector3.one);
                        float   randX         = UnityEngine.Random.Range(RepositionLogic.MinXPercent, RepositionLogic.MaxXPercent);
                        float   randY         = UnityEngine.Random.Range(RepositionLogic.MinYPercent, RepositionLogic.MaxYPercent);
                        Vector3 newWorldPoint = c.ViewportToWorldPoint(new Vector3(randX, randY));
                        InfiniteScroll.SetPosition(obj, r, newWorldPoint.x, topEdge.y + newWorldPoint.y);
                    }
                }
            }
        }
    }
    public void SetupPosition(InfiniteScroll p, Camera c, int index)
    {
        Vector3 screenLeft = c.ViewportToWorldPoint(Vector3.zero);
        Vector3 screenTop = c.ViewportToWorldPoint(Vector3.one);
        float   start, offset;

        if (p.IsHorizontal)
        {
            start  = screenTop.y + 1.0f;
            offset = screenLeft.x + GameObjectRenderers[0].bounds.size.x;
        }
        else
        {
            start  = screenTop.x + 1.0f;
            offset = screenLeft.y + GameObjectRenderers[0].bounds.size.y;
        }

        for (int i = 0; i < GameObjects.Count; i++)
        {
            GameObject obj = GameObjects[i];
            Renderer   r   = GameObjectRenderers[i];
            if (RepositionLogic.SortingOrder != 0)
            {
                r.sortingOrder = RepositionLogic.SortingOrder;
            }

            if (RepositionLogic.PositionMode == FreeParallaxPositionMode.IndividualStartOffScreen ||
                RepositionLogic.PositionMode == FreeParallaxPositionMode.IndividualStartOnScreen)
            {
                float x, y;
                if (p.IsHorizontal)
                {
                    x = (RepositionLogic.PositionMode == FreeParallaxPositionMode.IndividualStartOnScreen ? r.bounds.min.x : 0);
                    y = (RepositionLogic.PositionMode == FreeParallaxPositionMode.IndividualStartOnScreen ? r.bounds.min.y : start + r.bounds.size.y);
                }
                else
                {
                    x = (RepositionLogic.PositionMode == FreeParallaxPositionMode.IndividualStartOnScreen ? r.bounds.min.x : start + r.bounds.size.x);
                    y = (RepositionLogic.PositionMode == FreeParallaxPositionMode.IndividualStartOnScreen ? r.bounds.min.y : 0);
                }
                InfiniteScroll.SetPosition(obj, r, x, y);
            }
            else
            {
                // position in the next spot in line
                if (p.IsHorizontal)
                {
                    offset -= (r.bounds.size.x - p.WrapOverlap);
                }
                else
                {
                    offset -= (r.bounds.size.y - p.WrapOverlap);
                }
                obj.transform.rotation = Quaternion.identity;

                // anchor to the top of the screen
                if (RepositionLogic.PositionMode == FreeParallaxPositionMode.WrapAnchorTop)
                {
                    if (p.IsHorizontal)
                    {
                        Vector3 topWorld = c.ViewportToWorldPoint(new Vector3(0.0f, 1.0f, 0.0f));
                        InfiniteScroll.SetPosition(obj, r, offset, topWorld.y - r.bounds.size.y);
                    }
                    else
                    {
                        Vector3 topWorld = c.ViewportToWorldPoint(new Vector3(1.0f, 0.0f, 0.0f));
                        InfiniteScroll.SetPosition(obj, r, topWorld.x - r.bounds.size.x, offset + r.bounds.size.y);
                    }
                }
                else if (RepositionLogic.PositionMode == FreeParallaxPositionMode.WrapAnchorBottom)
                {
                    if (p.IsHorizontal)
                    {
                        InfiniteScroll.SetPosition(obj, r, offset, screenLeft.y);
                    }
                    else
                    {
                        InfiniteScroll.SetPosition(obj, r, screenLeft.x, offset);
                    }
                }
                else
                {
                    // no anchor, maintain position
                    if (p.IsHorizontal)
                    {
                        InfiniteScroll.SetPosition(obj, r, offset, r.bounds.min.y);
                    }
                    else
                    {
                        InfiniteScroll.SetPosition(obj, r, r.bounds.min.x, offset);
                    }
                }

                GameObjects.RemoveAt(i);
                GameObjects.Insert(0, obj);
                GameObjectRenderers.RemoveAt(i);
                GameObjectRenderers.Insert(0, r);
            }
        }
    }