void Update()
    {
        accumulatedDeltaTime += Time.deltaTime * simulationSpeedFactor;
        if (accumulatedDeltaTime >= vehicleDt)
        {
            accumulatedDeltaTime = 0.0f;
            // Get positions of virtual structure edges
            PointInfo[] edges = formationRectangle.getEdges();

            Vector3    targetPosition = agents [0].transform.position;
            List <int> failedAgents   = new List <int> ();
            if (winnerIdx == agents.Length - 1 || !moveNearestAgent(targetPosition, winnerIdx))
            {
                failedAgents.Add(winnerIdx);
                for (int t = 1; t < agents.Length - 1; t++)
                {
                    // Get closest player to opponent
                    float minDistance = float.MaxValue;

                    for (int i = 1; i < agents.Length - 1; i++)
                    {
                        // If this agent has failed moving before, due to moving the formation out of the polygon
                        if (failedAgents.Contains(i))
                        {
                            continue;
                        }
                        float distance = Vector2.Distance(new Vector2(targetPosition.x, targetPosition.z), getDesiredPosition(i - 1));
                        if (distance < minDistance)
                        {
                            minDistance = distance;
                            winnerIdx   = i;
                        }
                    }

                    // If movement of agent succeeds without collision of the formation with the boundary polygon
                    if (moveNearestAgent(targetPosition, winnerIdx))
                    {
                        break;
                    }
                    failedAgents.Add(winnerIdx);
                    winnerIdx = agents.Length - 1;
                }
            }
            //If noone can move
            if (winnerIdx == agents.Length - 1)
            {
                setRelativeFormationPositions(this.relativeFormationPositions, winnerIdx - 1);
                this.desiredRelativePositions = getDesiredPositions(winnerIdx, false, false);
                this.desiredAbsolutePositions = getDesiredPositions(winnerIdx, false, true);
                FootballPlayerController virtualCenterController = agents[agents.Length - 1].GetComponent <FootballPlayerController>();
                virtualCenterController.setPlay(false);
            }
        }
    }
    private bool moveNearestAgent(Vector3 target, int nearestAgentIdx)
    {
        // Get next position information of the nearestAgentIdx
        FootballPlayerController nearestAgentController = agents[nearestAgentIdx].GetComponent <FootballPlayerController>();
        PointInfo lastPos = nearestAgentController.getLastPosInfo();
        BaseModel model   = nearestAgentController.getMotionModel();

        PointInfo nextPoint;

        if (formationDecreasingGoalVelocity)
        {
            PointInfo goalPointInfo = new PointInfo(target, Vector3.zero, Vector3.forward, lastPos.currentTime + vehicleDt);
            nextPoint = model.moveTowardsWithDecreasingVelocity(lastPos, goalPointInfo, nearestAgentController.getWorld(), false);
        }
        else
        {
            PointInfo        goalPointInfo = new PointInfo(target, getAgentVelocity(0), getAgentOrientation(0), lastPos.currentTime + vehicleDt);
            List <PointInfo> path          = model.completePath(lastPos, goalPointInfo, nearestAgentController.getWorld(), false);
            if (path != null && path.Count > 0)
            {
                nextPoint = path [0];
            }
            else
            {
                return(false);
            }
        }
        nearestAgentController.getWorld().currentVelocities[nearestAgentIdx - 1] = nextPoint.vel;
        setCurrentVelocity(nearestAgentIdx, nextPoint.vel);

        // Get previous position of agent
        Vector3 prevPos = new Vector3(agents[nearestAgentIdx].transform.position.x, agents[nearestAgentIdx].transform.position.y, agents[nearestAgentIdx].transform.position.z);

        agents[nearestAgentIdx].transform.position = nextPoint.pos;
        Vector2[] tmpDesiredRelativePositions = getDesiredPositions(winnerIdx, false, false);
        // Store previous positional information
        Vector2[] prevRelativeFormationPositions = new Vector2[this.relativeFormationPositions.Length];
        for (int i = 0; i < prevRelativeFormationPositions.Length; i++)
        {
            prevRelativeFormationPositions [i] = new Vector2(this.relativeFormationPositions[i].x, this.relativeFormationPositions[i].y);
        }
        Vector2[] prevDesiredRelative = getDesiredPositions(winnerIdx, false, false);
        Vector2[] prevDesiredAbsolute = getDesiredPositions(winnerIdx, false, true);
        // Calculate new positional information
        setRelativeFormationPositions(this.relativeFormationPositions, nearestAgentIdx - 1);
        this.desiredRelativePositions = getDesiredPositions(winnerIdx, false, false);
        this.desiredAbsolutePositions = getDesiredPositions(winnerIdx, false, true);

        // Get virtual center controller and its last position
        FootballPlayerController virtualCenterController = agents[agents.Length - 1].GetComponent <FootballPlayerController>();
        PointInfo lastCenterPos = virtualCenterController.getLastPosInfo();
        // Move center in the same way the nearest agent moves, anchoring the formation to the agent
        Vector2 desiredCenterPosition = getDesiredPosition(agents.Length - 2);
        Vector3 desiredCenter3D       = new Vector3(desiredCenterPosition.x, agentHeight, desiredCenterPosition.y);
        // Get copy of formation rectangle
        VirtualStructureRectangle tmp = new VirtualStructureRectangle(formationRectangle);

        // Update rectangle with new desired center
        tmp.updateRectangle(desiredCenter3D);

        // Check if new rectangle gets out of the bounding polygon in case the agent is not already near the boundary
        if (lastPos.currentTime > 30.0f && !tmp.isInPolygon(nearestAgentController.getWorld().boundingPolygon))
        {
            // If it is not entirely inside, restore changes and return false
            agents[nearestAgentIdx].transform.position = prevPos;
            this.relativeFormationPositions            = prevRelativeFormationPositions;
            this.desiredAbsolutePositions = prevDesiredAbsolute;
            this.desiredRelativePositions = prevDesiredRelative;
            return(false);
        }


        // Otherwise make all necessary changes to variables of the closest agent and formation center
        agents[nearestAgentIdx].transform.position = prevPos;
        agents [nearestAgentIdx].transform.LookAt(agents[nearestAgentIdx].transform.position + (target - agents[nearestAgentIdx].transform.position).normalized);
        PointInfo nextPos = new PointInfo(nextPoint.pos, Vector3.zero, nextPoint.orientation, nextPoint.currentTime + vehicleDt);

        nearestAgentController.setNextPosInfo(nextPoint);

        agents [agents.Length - 1].transform.position = desiredCenter3D;
        lastCenterPos.pos         = desiredCenter3D;
        lastCenterPos.vel         = nextPoint.vel;
        lastCenterPos.orientation = nextPoint.orientation;
        lastCenterPos.currentTime = nextPoint.currentTime;
        formationRectangle        = tmp;
        agents [agents.Length - 1].transform.LookAt(agents[agents.Length - 1].transform.position + (target - agents[agents.Length - 1].transform.position).normalized);
        virtualCenterController.setLastPosInfo(lastCenterPos);
        nextPos = new PointInfo(lastCenterPos.pos, Vector3.zero, lastCenterPos.orientation, lastCenterPos.currentTime + vehicleDt);
        virtualCenterController.setNextPosInfo(nextPos);
        virtualCenterController.setPlay(false);
        return(true);
    }