/// <summary>
        /// Called every frame from Robot.update() if it's the current state (top of the stack)
        /// </summary>
        /// <param name="r">The robot to update</param>
        public override void update(Robot r)
        {
            bool    finished        = false;
            Vector2 currentPosition = new Vector2(r.body.transform.position.x,
                                                  r.body.transform.position.z);

            ////////////////////////////////////////////////////////////////////////////////////////
            // Initialize variables if necessary when first enter state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (!initialized)
            {
                initialized = true;
                resume      = true;

                lastWaypoint = currentPosition;
                nextWaypoint = queueWaypoints.Peek();

                if (robotSpacing < r.body.transform.localScale.x)
                {
                    Log.a(LogTag.ROBOT, "Cannot initialize queue with robot spacing that's less than 2x robot radius!");
                }
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // Reset variables if robot is returning from another state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (resume)
            {
                resume = false;

                if (!enteredQueue)
                {
                    Log.d(LogTag.ROBOT, "Robot " + r.id + " is travelling to the the queue at " + queueWaypoints.Peek());
                    enteredQueue = true;
                    nextWaypoint = queueWaypoints.Peek();
                    r.pushState(new RobotStateMove(nextWaypoint));
                }
                else
                {
                    if (!enteredQueue)
                    {
                        enteredQueue = true;
                    }

                    if (Vector2.Distance(currentPosition, nextWaypoint) < 0.1f)
                    {
                        lastWaypoint = queueWaypoints.Dequeue();

                        if (queueWaypoints.Count == 0)
                        {
                            finished = true;
                        }
                        else
                        {
                            nextWaypoint = queueWaypoints.Peek();
                        }
                    }

                    if (!finished)
                    {
                        bool       moveToDestination  = true;
                        float      distanceToWaypoint = Vector2.Distance(currentPosition, nextWaypoint);
                        int        layerMask          = 1 << 8; // check Robot layer only
                        RaycastHit hitInfo;
                        Vector2    nextDestination = nextWaypoint;
                        Vector2    dir2d           = nextDestination - currentPosition;
                        Vector3    dir3d           = new Vector3(dir2d.x, 0, dir2d.y);

                        if (Physics.Raycast(r.body.transform.position, dir3d, out hitInfo, distanceToWaypoint, layerMask))
                        {
                            float distanceBetweenRobots = hitInfo.distance + r.body.transform.localScale.x / 2.0f;
                            if (distanceBetweenRobots > robotSpacing)
                            {
                                dir2d.Normalize();
                                float nextDestinationDistance = distanceBetweenRobots - robotSpacing;
                                nextDestination = nextWaypoint - dir2d * (distanceToWaypoint - nextDestinationDistance);
                            }
                            else
                            {
                                moveToDestination = false;
                            }
                        }

                        if (moveToDestination)
                        {
                            r.pushState(new RobotStateMove(nextDestination, tolerance));
                        }
                        else
                        {
                            r.pushState(new RobotStateSleep(0.1f));
                        }
                    }
                }
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // Update: TODO wait for other robots
            ////////////////////////////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////////////////////////////
            // Process messages: TODO
            ////////////////////////////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////////////////////////////
            // "Clean up" robot state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (finished)
            {
                Log.d(LogTag.ROBOT, "Robot " + r.id + " has reached the front of the queue at " + lastWaypoint);
                r.popState();
            }
        }
        /// <summary>
        /// Called every frame from Robot.update() if it's the current state (top of the stack)
        /// </summary>
        /// <param name="r">The robot to update</param>
        public override void update(Robot r)
        {
            bool finished = false;

            ////////////////////////////////////////////////////////////////////////////////////////
            // Initialize variables if necessary when first enter state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (!initialized)
            {
                initialized = true;
                state       = ConstructionState.WAITING_FOR_INITIALIZATION;

                if (initialCommand.text.StartsWith(MessageConstructionStart.TAG))
                {
                    MessageConstructionStart msgData;
                    if (MessageConstructionStart.TryParse(initialCommand.text, out msgData))
                    {
                        waitQueue = msgData.waitQueue;
                        r.pushState(new RobotStateQueue(new Queue <Vector2>(waitQueue), 1.5f));
                        state = ConstructionState.QUEUING;
                        r.pushState(new RobotStateSleep(2 * r.id));
                    }
                    else
                    {
                        Log.a(LogTag.ROBOT, "Failed to parse " + MessageConstructionStart.TAG + " data.");
                        finished = true;
                    }
                }
                else
                {
                    Log.a(LogTag.ROBOT, "Failed to parse initial MessageConstructionStart");
                    finished = true;
                }
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // Reset variables if robot is returning from another state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (resume)
            {
                resume = false;
                Log.d(LogTag.ROBOT, "Robot " + r.id + " is returning to construction (satellite)");

                switch (state) // resuming from this state
                {
                case ConstructionState.QUEUING:
                {
                    state = ConstructionState.FRONT_OF_QUEUE;

                    Comm.directMessage(r.id, Comm.SATELLITE, "construction\nrequest_task");
                    break;
                }

                case ConstructionState.FINISHED:
                {
                    finished = true;
                    break;
                }

                default:
                {
                    break;
                }
                }
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // Update
            ////////////////////////////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////////////////////////////
            // Process messages: TODO
            ////////////////////////////////////////////////////////////////////////////////////////
            int count = r.unhandledMessages.Count;

            for (int i = 0; i < count; ++i)
            {
                bool        handledMessage = false;
                CommMessage msg            = r.unhandledMessages.Dequeue();

                // TODO: this if-block is more repugnant than someone kicking a puppy
                if (msg.text.StartsWith("construction"))
                {
                    handledMessage = true;

                    if (msg.text.StartsWith(MessageConstructionStart.TAG))
                    {
                        MessageConstructionStart msgData;
                        if (MessageConstructionStart.TryParse(msg.text, out msgData))
                        {
                            if (state == ConstructionState.WAITING_FOR_INITIALIZATION)
                            {
                                waitQueue = msgData.waitQueue;
                                r.pushState(new RobotStateQueue(new Queue <Vector2>(waitQueue), 2f));
                                state = ConstructionState.QUEUING;
                            }
                            else
                            {
                                Log.e(LogTag.ROBOT, "Received " + MessageConstructionStart.TAG + " message outside of WAITING_FOR_INITIALIZATION state");
                            }
                        }
                        else
                        {
                            Log.a(LogTag.ROBOT, "Failed to parse " + MessageConstructionStart.TAG + " data.");
                        }
                    }
                    else if (msg.text.StartsWith(MessageConstructionTask.TAG))
                    {
                        MessageConstructionTask msgData;
                        if (MessageConstructionTask.TryParse(msg.text, out msgData))
                        {
                            if (state == ConstructionState.FRONT_OF_QUEUE)
                            {
                                Queue <Vector2> startToPlacementPerimeter;
                                Queue <Vector2> placementToEndPerimeter;
                                calculateBreakPosition(msgData.constructionPerimeter,
                                                       msgData.resourcePlacement,
                                                       out startToPlacementPerimeter,
                                                       out placementToEndPerimeter);

                                if (msgData.lastTask)
                                {
                                    r.pushState(new RobotStateMove(new Vector2(r.id * -1.5f, 31)));
                                    state = ConstructionState.FINISHED;
                                }
                                else
                                {
                                    r.pushState(new RobotStateQueue(new Queue <Vector2>(waitQueue), 2f));
                                    state = ConstructionState.QUEUING;
                                }

                                r.pushState(new RobotStateQueue(placementToEndPerimeter, 2f));
                                r.pushState(new RobotStatePlaceResource(msgData.resourcePlacement));
                                r.pushState(new RobotStateQueue(startToPlacementPerimeter, 2f));
                                r.pushState(new RobotStateMove(msgData.resourceOrigin + new Vector2(0, -10)));
                                r.pushState(new RobotStateRetrieveResource(msgData.resourceOrigin));
                            }
                            else
                            {
                                Log.e(LogTag.ROBOT, "Received " + MessageConstructionTask.TAG + " message outside of FRONT_OF_QUEUE state");
                            }
                        }
                        else
                        {
                            Log.a(LogTag.ROBOT, "Failed to parse " + MessageConstructionTask.TAG + " data.");
                        }
                    }
                    else if (msg.text == "construction/finished")
                    {
                        r.pushState(new RobotStateMove(new Vector2(r.id * -1.5f, 31)));
                        state = ConstructionState.FINISHED;
                    }
                    else
                    {
                        Log.a(LogTag.ROBOT, "Unknown construction message:\n" + msg.text);
                    }
                }

                if (!handledMessage) // didn't process message, leave for next state
                {
                    r.unhandledMessages.Enqueue(msg);
                }
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // "Clean up" robot state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (finished)
            {
                Log.d(LogTag.ROBOT, "Robot " + r.id + " has finished construction (satellite).");

                // Pop state off the stack
                r.popState();
            }
        }
        /// <summary>
        /// Called every frame from Robot.update() if it's the current state (top of the stack)
        /// </summary>
        /// <param name="r">The robot to update</param>
        public override void update(Robot r)
        {
            bool finished = false;

            ////////////////////////////////////////////////////////////////////////////////////////
            // Initialize variables if necessary when first enter state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (!initialized)
            {
                initialized = true;

                if (r.carriedResource != null)
                {
                    r.pushState(new RobotStateMove(position, placementDistance));
                }
                else
                {
                    Log.e(LogTag.ROBOT, "Initializing RobotPlaceResource, but robot isn't carrying anything.");
                    finished = true;
                }
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // Reset variables if robot is returning from another state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (resume)
            {
                resume = false;

                Vector2 robotPosition = new Vector2(r.body.transform.position.x,
                                                    r.body.transform.position.z);
                if (r.carriedResource != null &&
                    Vector2.Distance(robotPosition, position) <= placementDistance)
                {
                    Log.w(LogTag.ROBOT, "Robot " + r.id + " has placed " + r.carriedResource.transform.name);
                    GameObject resourceHeader = GameObject.Find("Resources");
                    Transform  t = resourceHeader != null ? resourceHeader.transform : null;

                    r.carriedResource.transform.SetParent(t);
                    r.carriedResource.transform.position = new Vector3(position.x, 0.5f, position.y);
                    r.carriedResource.transform.rotation = new Quaternion();
                    r.carriedResource = null;
                }

                finished = true;
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // Update: intentionally empty
            ////////////////////////////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////////////////////////////
            // Process messages: disabled here
            ////////////////////////////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////////////////////////////
            // "Clean up" robot state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (finished)
            {
                r.popState();
            }
        }
        /// <summary>
        /// Called every frame from Robot.update() if it's the current state (top of the stack)
        /// </summary>
        /// <param name="r">The robot to update</param>
        public override void update(Robot r)
        {
            bool finished = false;

            ////////////////////////////////////////////////////////////////////////////////////////
            // Initialize variables if necessary when first enter state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (!initialized)
            {
                initialized = true;
                resume      = true;

                robotAgent = r.body.GetComponent <NavMeshAgent>();

                if (robotAgent != null)
                {
                    robotAgent.avoidancePriority = (int)r.id + 1;
                    robotAgent.speed             = r.VELOCITY;
                }
                else
                {
                    Log.a(LogTag.ROBOT, "Robot " + r.id + " does not have attached NavMeshAgent");
                    return;
                }

                targetPosition.y = r.body.transform.position.y;
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // Reset variables if robot is returning from another state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (resume)
            {
                resume = false;

                if (!hasRotated)
                {
                    robotAgent.updateRotation = false;
                    r.pushState(new RobotStateTurn(new Vector2(targetPosition.x, targetPosition.z)));
                    hasRotated = true;
                    return;
                }
                else
                {
                    robotAgent.updateRotation = true;
                    robotAgent.SetDestination(targetPosition);
                }
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // Update: check if robot has reached its destination (within specified tolerance)
            ////////////////////////////////////////////////////////////////////////////////////////
            if (!robotAgent.pathPending && robotAgent.remainingDistance == 0)
            {
                if (Vector3.Distance(targetPosition, r.body.transform.position) < tolerance)
                {
                    finished = true;
                }
                else
                {
                    Log.d(LogTag.ROBOT, "Robot " + r.id + " cannot reach its destination. Waiting for path to open up.");
                    // robotAgent.SetDestination(targetPosition);
                    r.pushState(new RobotStateSleep(1.0f));
                }
            }
            else if (stoppingDistance > 0 && Vector3.Distance(targetPosition, r.body.transform.position) < stoppingDistance)
            {
                finished = true;
                robotAgent.SetDestination(r.body.transform.position);
                robotAgent.updateRotation = false;
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // Process messages: no, should be handled in other states
            ////////////////////////////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////////////////////////////
            // "Clean up" robot state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (finished)
            {
                // Log.d(LogTag.ROBOT, "Robot " + r.id + " has reached target position " + targetPosition);

                // Other robots must navigate around it
                robotAgent.avoidancePriority = 0;

                // Pop state off the stack
                r.popState();
            }
        }
        public override void update(Robot r)
        {
            bool finished = false;

            ////////////////////////////////////////////////////////////////////////////////////////
            // Initialize variables if necessary when first enter state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (!initialized)
            {
                initialized = true;
                resume      = true;

                state = ForagingState.REQUEST_RESOURCE;
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // Reset variables if robot is returning from another state
            ////////////////////////////////////////////////////////////////////////////////////////

            if (resume)
            {
                resume = false;
                Log.d(LogTag.ROBOT, "Robot " + r.id + " is returning to foraging");

                switch (state)
                {
                case ForagingState.REQUEST_RESOURCE:
                {
                    Log.d(LogTag.ROBOT, "ROBOT " + r.id + " has requested a resource.");
                    Comm.directMessage(r.id, Comm.SATELLITE, "resource_request");
                    break;
                }

                case ForagingState.PICK_UP_RESOURCE:
                {
                    testMove = new Vector2(10f, 10f);
                    r.pushState(new RobotStateMove(testMove));
                    state = ForagingState.GO_TO_DROP_OFF;
                    break;
                }

                case ForagingState.GO_TO_RESOURCE_HOME:
                {
                    state = ForagingState.GO_TO_DROP_OFF;

                    break;
                }

                case ForagingState.GO_TO_DROP_OFF:
                {
                    //request a position where to drop off the resource in the resource home
                    Comm.directMessage(r.id, Comm.SATELLITE, "resource_home_request");
                    break;
                }

                case ForagingState.DROP_OFF_RESOURCE:
                {
                    //drop off the resource
                    Comm.directMessage(r.id, Comm.SATELLITE, "resource_delivered");
                    break;
                }

                case ForagingState.RETURN_TO_BASE:
                {
                    state = ForagingState.REQUEST_RESOURCE;
                    break;
                }

                case ForagingState.FINISHED:
                {
                    finished = true;
                    break;
                }

                default:
                {
                    break;
                }
                }
            }
            ////////////////////////////////////////////////////////////////////////////////////////
            // Update: check if robot has reached its destination (within specified tolerance)
            ////////////////////////////////////////////////////////////////////////////////////////


            ////////////////////////////////////////////////////////////////////////////////////////
            // Process messages: no, should be handled in other states
            ////////////////////////////////////////////////////////////////////////////////////////

            int count = r.unhandledMessages.Count;

            for (int i = 0; i < count; ++i)
            {
                CommMessage msg = r.unhandledMessages.Dequeue();

                if (msg.senderId == Comm.SATELLITE)
                {
                    switch (state)
                    {
                    case ForagingState.REQUEST_RESOURCE:
                    {
                        if (msg.text.StartsWith("resource_location"))
                        {
                            string[] lines = msg.text.Split('\t');
                            //parse the messgae sent back from the satellite
                            //will be sent the location of the resource
                            StringToVector2(lines[1], out result);
                            r.pushState(new RobotStateRetrieveResource(result));
                            state = ForagingState.PICK_UP_RESOURCE;
                        }
                        else if (msg.text.StartsWith("go_to_base"))
                        {
                            string[] lines = msg.text.Split('\t');
                            StringToVector3(lines[1], out resultBase);
                            r.pushState(new RobotStateMove(resultBase));
                            state = ForagingState.FINISHED;
                        }
                        break;
                    }

                    case ForagingState.GO_TO_DROP_OFF:
                    {
                        if (msg.text.StartsWith("resource_home"))
                        {
                            string[] lines = msg.text.Split('\t');
                            StringToVector2(lines[1], out resultRH);
                        }
                        testMove = new Vector2(10f, 15f);
                        r.pushState(new RobotStateMove(testMove));
                        r.pushState(new RobotStatePlaceResource(resultRH));
                        state = ForagingState.DROP_OFF_RESOURCE;
                        break;
                    }

                    case ForagingState.DROP_OFF_RESOURCE:
                    {
                        if (msg.text.StartsWith("resource_location"))
                        {
                            string[] lines = msg.text.Split('\t');
                            //parse the messgae sent back from the satellite
                            //will be sent the location of the resource
                            StringToVector2(lines[1], out result);
                            r.pushState(new RobotStateRetrieveResource(result));
                            state = ForagingState.PICK_UP_RESOURCE;
                        }
                        else if (msg.text.StartsWith("go_to_base"))
                        {
                            string[] lines = msg.text.Split('\t');
                            StringToVector3(lines[1], out resultBase);
                            r.pushState(new RobotStateMove(resultBase));
                            state = ForagingState.FINISHED;
                        }
                        break;
                    }
                    }
                }
                else
                {
                    Log.w(LogTag.ROBOT, "Robot " + r.id + " processed unknown message " + msg.text + " from " + msg.senderId);
                }
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // "Clean up" robot state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (finished)
            {
                Log.d(LogTag.ROBOT, "Robot " + r.id + " has finished foraging");

                // Pop state off the stack
                r.popState();
            }
        }
Beispiel #6
0
        /// <summary>
        /// Called every frame from Robot.update() if it's the current state (top of the stack)
        /// </summary>
        /// <param name="r">The robot to update</param>
        public override void update(Robot r)
        {
            bool finished = false;

            ////////////////////////////////////////////////////////////////////////////////////////
            // Initialize variables if necessary when first enter state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (!initialized)
            {
                initialized = true;

                if (r.carriedResource == null)
                {
                    resume = true;
                }
                else
                {
                    Log.e(LogTag.ROBOT, "Initializing RobotPlaceResource, but robot is already carrying object.");
                    finished = true;
                }
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // Reset variables if robot is returning from another state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (resume)
            {
                resume = false;

                Vector2 robotPosition = new Vector2(r.body.transform.position.x,
                                                    r.body.transform.position.z);
                if (Vector2.Distance(robotPosition, position) > retrievalDistance)
                {
                    r.pushState(new RobotStateTurn(position));
                    r.pushState(new RobotStateMove(position, retrievalDistance));
                }
                else
                {
                    GameObject resource = r.getObjectInFront();
                    if (resource != null && resource.CompareTag("Resource"))
                    {
                        Log.w(LogTag.ROBOT, "Robot " + r.id + " has picked up " + resource.transform.name);
                        resource.transform.SetParent(r.body.transform);
                        resource.transform.position = new Vector3(r.body.transform.position.x, 1.5f, r.body.transform.position.z);
                        r.carriedResource           = resource;
                        finished = true;
                    }
                    else
                    {
                        Log.e(LogTag.ROBOT, "Robot " + r.id + " isn't facing any resources");
                        r.pushState(new RobotStateSleep(2.0f)); // allow other robots to move out of the way
                    }
                }
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // Update: intentionally empty
            ////////////////////////////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////////////////////////////
            // Process messages: disabled here
            ////////////////////////////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////////////////////////////
            // "Clean up" robot state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (finished)
            {
                r.popState();
            }
        }
Beispiel #7
0
        /// <summary>
        /// Called every frame from Robot.update() if it's the current state (top of the stack)
        /// </summary>
        /// <param name="r">The robot to update</param>
        public override void update(Robot r)
        {
            bool finished = false;

            ////////////////////////////////////////////////////////////////////////////////////////
            // Initialize variables if necessary when first enter state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (!initialized)
            {
                initialized = true;
                resume      = true;
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // Reset variables if robot is returning from another state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (resume)
            {
                resume = false;
                Log.d(LogTag.ROBOT, "Robot " + r.id + " is waiting");
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // Update: intentionally empty
            ////////////////////////////////////////////////////////////////////////////////////////

            ////////////////////////////////////////////////////////////////////////////////////////
            // Process messages: TODO
            ////////////////////////////////////////////////////////////////////////////////////////
            while (r.unhandledMessages.Count > 0)
            {
                CommMessage msg = r.unhandledMessages.Dequeue();
                if (msg.senderId == Comm.SATELLITE)
                {
                    if (msg.text.StartsWith("build/start"))
                    {
                        r.pushState(new RobotStateBuildSatellite(r, msg));
                    }
                    else if (msg.text.StartsWith("construction/start"))
                    {
                        r.pushState(new RobotStateConstructionSatellite(r, msg));
                    }
                    else if (msg.text == "foraging\tstart")
                    {
                        r.pushState(new RobotStateForaging());
                    }
                    else if (msg.text == "test")
                    {
                        Log.w(LogTag.ROBOT, "Robot " + r.id + " performing test.");
                        r.pushState(new RobotStateMove(Vector2.zero));
                        r.pushState(new RobotStateSleep(0.5f));
                        r.pushState(new RobotStateMove(new Vector2(0, 5)));
                        r.pushState(new RobotStateSleep(0.5f * r.id));
                    }
                    else if (msg.text == "test_queue")
                    {
                        Queue <Vector2> waypointQueue   = new Queue <Vector2>();
                        bool            switchDirection = false;

                        waypointQueue.Enqueue(new Vector2(0, -2)); // to attempt to avoid blocking the queue start

                        for (int i = 0; i < 4; ++i)
                        {
                            for (int j = 0; j < 2; ++j)
                            {
                                if (switchDirection)
                                {
                                    waypointQueue.Enqueue(new Vector2(i * 2, (1 - j) * 10));
                                }
                                else
                                {
                                    waypointQueue.Enqueue(new Vector2(i * 2, j * 10));
                                }
                            }

                            switchDirection = !switchDirection;
                        }

                        r.pushState(new RobotStateQueue(waypointQueue, 2.0f));
                    }
                    else
                    {
                        Log.w(LogTag.ROBOT, "Robot " + r.id + " processed unknown message " + msg.text + " from " + msg.senderId);
                    }
                }
                else
                {
                    Log.w(LogTag.ROBOT, "Robot " + r.id + " processed unknown message " + msg.text + " from " + msg.senderId);
                }
            }

            ////////////////////////////////////////////////////////////////////////////////////////
            // "Clean up" robot state
            ////////////////////////////////////////////////////////////////////////////////////////
            if (finished)
            {
                // Intentionally empty because this should never happen
            }
        }