/// <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(); } }
/// <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(); } }
/// <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 } }