public double calcDensity(int x, int y, int z) { double height = calcBaseTerrain(x, z); double ocean = calcOceanTerrain(x, z); double river = calcRiverTerrain(x, z); float temp = biomeProvider.getTemperatureAt(x, z); float humidity = biomeProvider.getHumidityAt(x, z); Vector2f distanceToMountainBiome = new Vector2f(temp - 0.25f, humidity - 0.35f); double mIntens = TeraMath.clamp(1.0 - distanceToMountainBiome.length() * 3.0); double densityMountains = calcMountainDensity(x, y, z) * mIntens; double densityHills = calcHillDensity(x, y, z) * (1.0 - mIntens); int plateauArea = (int) (Chunk.SIZE_Y * 0.10); double flatten = TeraMath.clamp(((Chunk.SIZE_Y - 16) - y) / plateauArea); return -y + (((32.0 + height * 32.0) * TeraMath.clamp(river + 0.25) * TeraMath.clamp(ocean + 0.25)) + densityMountains * 1024.0 + densityHills * 128.0) * flatten; }
/** * 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); } }