public void act(BucketbotBase self) { // make sure bucketbot is in vacinity of station, otherwise go there if (self.getDistance(station.getX(), station.getY()) > SimulationWorldSimpleExample.getSimulationWorld().getMap().getTolerance()) { stateQueue.add(0, new BucketbotMove(station.getX(), station.getY())); return; } // if it's the first time, request the letters be taken if (!requested_letters_take) { station.requestLetterTake(self, letter, null); requested_letters_take = true; } if (self.getBucket() == null) { // something wrong happened... don't have a bucket! SimulationWorldSimpleExample.getSimulationWorld() .bucketbotManager .taskAborted(self, getCurrentTask()); stateQueue.remove(0); if (stateQueue.size() > 0) stateQueue.get(0).act(self); return; } // see if letter has been taken from the bucket if (!self.getBucket().containsLetter(letter)) { stateQueue.remove(0); if (stateQueue.size() > 0) stateQueue.get(0).act(self); return; } }
public void act(BucketbotBase self) { alphabetsoup.framework.Map map = SimulationWorldSimpleExample.getSimulationWorld().getMap(); float cur_speed = getSpeed(); // called once for code efficiency (since getSpeed does a sqrt) // find distance to be covered before next planned update getNextEventTime(curTime); double time_interval = Math.max(getMinUntil() - curTime, 0.001); float distance_to_be_covered = (float) (Math.max(cur_speed, getTargetSpeed()) * time_interval); distance_to_be_covered += 2 * getRadius(); // count its radius and the radius of another object // make sure see at least a minimal distance regardless of speed float min_visible_distance = 3 * getRadius(); distance_to_be_covered = Math.max(distance_to_be_covered, min_visible_distance); // get visible objects within the distance of the next planned update Collection<Circle> visible_objects = map.getBucketbotsWithinDistance(getX(), getY(), distance_to_be_covered); if (self.getBucket() != null) visible_objects.addAll( map.getBucketsWithinDistance(getX(), getY(), distance_to_be_covered)); // don't want to do anything yet, // unless something is now visible that wasn't before, // a collision occured (speed == 0) // timer is ready to do something else if (((getBucket() == null && visible_objects.size() == 1) || (getBucket() != null && visible_objects.size() == 2)) && cur_speed > 0.0f && curTime < cruiseUntil) return; // if something other than bucketbot (and bucket if applicable) is near, evade if ((getBucket() == null && visible_objects.size() > 1) || (getBucket() != null && visible_objects.size() > 2)) { // find closest object float min_dist2 = Float.POSITIVE_INFINITY; // minimum distance squared for (Circle c : visible_objects) { if (c == self || c == self.getBucket()) continue; // see if infront of bucketbot float object_direction = (float) Math.atan2(c.getY() - getY(), c.getX() - getX()); float relative_direction = angleDifference(object_direction, getDirection()); if (Math.abs(relative_direction) > Math.PI / 4 + 0.5) // just beyond 1/4 circle, to make sure they don't get stuck continue; // see if it's closer than any other float dist2 = (getX() - c.getX()) * (getX() - c.getX()) + (getY() - c.getY()) * (getY() - c.getY()); if (dist2 < min_dist2) min_dist2 = dist2; } // if anything is closer than this constant value, then evade... if (min_dist2 < min_visible_distance * min_visible_distance) { float new_direction = getBestEvadeDirection(min_visible_distance); if (getDirection() != new_direction) setDirection(new_direction); setTargetSpeed(getMaxVelocity()); cruiseUntil = curTime + 0.25f; frustration = 0.0f; stateQueue.add(0, bucketbotEvade); return; } } // if trying to move, but can't try evading if (cur_speed > 0.0f) { stuckCount = 0; } else { // not moving... stuckCount++; if (stuckCount > 3) { frustration = 0.0f; stateQueue.add(0, bucketbotEvade); return; } } // find distance to goal float goal_distance = getDistance(moveToX, moveToY); // make sure tolerance is less than the map's tolerance/3 to make sure that if it sets a // bucket down, // the next one bucketbot will be able to pick it up (and could also be tolerance/3 away) // better fudge factor than tolerance / 2 (which is the minimum that will work) float tolerance = map.getTolerance() / 3; // if close enough to goal and stopped moving, then do next action if (goal_distance < tolerance && cur_speed == 0.0f) { frustration = 0.0f; stateQueue.remove(0); if (stateQueue.size() > 0) stateQueue.get(0).act(self); return; } // if not facing the right way (within tolerance), or heading outside of the map, turn so it // is a good direction double projected_x = getX() + goal_distance * Math.cos(getDirection()); double projected_y = getY() + goal_distance * Math.sin(getDirection()); if ((projected_x - moveToX) * (projected_x - moveToX) + (projected_y - moveToY) * (projected_y - moveToY) >= tolerance * tolerance || projected_x + getRadius() > map.getWidth() || projected_x - getRadius() < 0.0 || projected_y + getRadius() > map.getHeight() || projected_y - getRadius() < 0.0) { setDirection((float) Math.atan2(moveToY - getY(), moveToX - getX())); if (cur_speed > 0) setTargetSpeed(0.0f); cruiseUntil = getAccelerateUntil(); return; } // going the right direction -now figure out speed // if too close to stop, then stop as fast as possible float decel_time = cur_speed / getMaxAcceleration(); float decel_distance = getMaxAcceleration() / 2 * decel_time * decel_time; if (cur_speed > 0.0f && decel_distance > goal_distance) { setTargetSpeed(0.0f); cruiseUntil = getAccelerateUntil(); frustration = (frustration + 1.0f) / 2; return; } // get new velocity based on frustration float cur_vel = getMaxVelocity() * Math.max(1.0f - frustration, 0.0078125f); setTargetSpeed(cur_vel); // see if have room to accelerate to full speed and still decelerate float accel_time = getTargetSpeedDifference() / getMaxAcceleration(); float accel_distance = cur_speed * accel_time + getMaxAcceleration() / 2 * accel_time * accel_time; decel_time = cur_vel / getMaxAcceleration(); decel_distance = getMaxAcceleration() / 2 * accel_time * accel_time; // if enough room to fully accelerate, do so if (accel_distance + decel_distance <= goal_distance) cruiseUntil = getAccelerateUntil(); else { // don't have time to fully accelerate // having this code spread out with sub-steps dramatically helps the java compiler have // better performance double cos_dir = Math.cos(getDirection()); double sin_dir = Math.sin(getDirection()); double x_accel = getMaxAcceleration() * cos_dir; double y_accel = getMaxAcceleration() * sin_dir; if (Math.abs(x_accel) > Math.abs(y_accel)) { double x_goal = goal_distance * cos_dir; cruiseUntil = curTime + sqrt2 * (Math.sqrt(2 * x_accel * x_goal + getXVelocity() * getXVelocity()) - sqrt2 * getXVelocity()) / (2 * x_accel); } else { double y_goal = goal_distance * sin_dir; cruiseUntil = curTime + sqrt2 * (Math.sqrt(2 * y_accel * y_goal + getYVelocity() * getYVelocity()) - sqrt2 * getYVelocity()) / (2 * y_accel); } } } // act()