// Vector arithmetic // A: current position // B: target position // d: distance to travel along the line from A to B // A_moved = A + |B - A| * d where | | represents 'norm' public void updateLocation() { Vector2f currentLoc = new Vector2f((float) getX2(), (float) getY2()); Vector2f update = new Vector2f(target.x, target.y); update.sub(currentLoc); // B - A update.normalize(); // |B - A| update.scale(travelDistance); // |B - A| x dist currentLoc.add(update); // A + |B - A| x d setLine(x1, y1, currentLoc.x, currentLoc.y); }
/** @return Vector2f vector holding the starting location for a Person Node */ public Vector2f pStartLocation() { // Try to place the new node in a location that won't disrupt the system too much (by being too // close to another person) for (int i = 0; i < 100; i++) { Vector2f testStart = this.randomLocation(); boolean good = true; for (code_swarm.PersonNode n : code_swarm.getLivingPeople()) { Vector2f delta = new Vector2f(); delta.sub(n.mPosition, testStart); if (delta.lengthSquared() < MIN_DISTANCE_SQR) { good = false; break; } } if (good) return testStart; } return randomLocation(); }
/** * Method that allows Physics Engine to modify Speed / Position during the relax phase. * * @param pNode the node to which the force apply @Note Standard physics is "Position Variation = * Speed x Duration" with a convention of "Duration=1" between to frames */ public void onRelax(code_swarm.PersonNode pNode) { Vector2f delta = new Vector2f(); // A gentle force to attract pNodes to the center // NOTE: this should be done prior to attraction/repulsion forces, otherwise // tends to generate a grid-like pattern Vector2f midpoint = new Vector2f(code_swarm.width / 2, code_swarm.height / 2); delta = new Vector2f(); delta.sub(midpoint, pNode.mPosition); delta.scale(1 / delta.length() * 0.003f); pNode.mPosition.add(delta); // All person nodes attract each other, but only to a certain point, then they repel with gentle // force for (code_swarm.PersonNode n : code_swarm.getLivingPeople()) { if (pNode != n) { delta.sub(pNode.mPosition, n.mPosition); if (delta.lengthSquared() < MIN_DISTANCE_SQR) { // This calculation gives a 'stiff spring' affect float toMove = ((float) Math.sqrt(MIN_DISTANCE_SQR) - delta.length()) / 10.0f; // This calculation gives a much nicer flow // float toMove = 0.03f; delta.scale((1 / delta.length()) * toMove); n.mPosition.sub(delta); pNode.mPosition.add(delta); } else { float toMove = -0.003f; delta.scale((1 / delta.length()) * toMove); n.mPosition.sub(delta); pNode.mPosition.add(delta); } } } // place the edited files around the person Iterator<code_swarm.FileNode> editedFiles = pNode.editing.iterator(); int index = 0; int radius = 45; final int node_size = 4; final int salt = pNode.hashCode(); // used to randomize orientation of circle of nodes int num_nodes_in_ring = (int) ((2 * radius * Math.PI) / node_size); while (editedFiles.hasNext()) { // if we've placed all the nodes in this ring... if (index == num_nodes_in_ring) { // start on a new ring radius += node_size; num_nodes_in_ring = (int) ((2 * radius * Math.PI) / node_size); index = 0; } index++; code_swarm.FileNode file = editedFiles.next(); // leave a hole for the null files if (file == null) continue; final int place_around_ring = index * num_nodes_in_ring + salt; int x = (int) (radius * Math.sin(place_around_ring)); int y = (int) (radius * Math.cos(place_around_ring)); delta = new Vector2f(); delta.sub(file.mPosition, new Vector2f(pNode.mPosition.x + x, pNode.mPosition.y + y)); float distance = delta.length(); delta.scale(1 / delta.length() * -0.01f * distance); file.mPosition.add(delta); } }