improve river-fork angle restrictions
This commit is contained in:
parent
5b14cad343
commit
2996fff6bd
@ -153,7 +153,7 @@ public class Controller {
|
|||||||
case 'v':
|
case 'v':
|
||||||
try {
|
try {
|
||||||
Object data = Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor);
|
Object data = Toolkit.getDefaultToolkit().getSystemClipboard().getData(DataFlavor.stringFlavor);
|
||||||
newSeed = Integer.parseInt(data.toString());
|
newSeed = (int) Long.parseLong(data.toString());
|
||||||
} catch (Throwable t) {
|
} catch (Throwable t) {
|
||||||
t.printStackTrace();
|
t.printStackTrace();
|
||||||
}
|
}
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
package com.terraforged.app;
|
package com.terraforged.app;
|
||||||
|
|
||||||
import com.terraforged.app.biome.BiomeProvider;
|
import com.terraforged.app.biome.BiomeProvider;
|
||||||
import me.dags.noise.util.NoiseUtil;
|
|
||||||
import com.terraforged.core.cell.Cell;
|
import com.terraforged.core.cell.Cell;
|
||||||
import com.terraforged.core.world.biome.BiomeData;
|
import com.terraforged.core.world.biome.BiomeData;
|
||||||
import com.terraforged.core.world.biome.BiomeType;
|
import com.terraforged.core.world.biome.BiomeType;
|
||||||
import com.terraforged.core.world.terrain.Terrain;
|
import com.terraforged.core.world.terrain.Terrain;
|
||||||
|
import me.dags.noise.util.NoiseUtil;
|
||||||
|
|
||||||
import java.awt.*;
|
import java.awt.*;
|
||||||
import java.util.Random;
|
import java.util.Random;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.terraforged.app.mesh;
|
package com.terraforged.app.mesh;
|
||||||
|
|
||||||
import com.terraforged.app.renderer.Renderer;
|
|
||||||
import com.terraforged.app.Applet;
|
import com.terraforged.app.Applet;
|
||||||
|
import com.terraforged.app.renderer.Renderer;
|
||||||
import com.terraforged.core.cell.Cell;
|
import com.terraforged.core.cell.Cell;
|
||||||
import com.terraforged.core.world.terrain.Terrain;
|
import com.terraforged.core.world.terrain.Terrain;
|
||||||
import processing.core.PApplet;
|
import processing.core.PApplet;
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
package com.terraforged.app.mesh;
|
package com.terraforged.app.mesh;
|
||||||
|
|
||||||
import com.terraforged.app.renderer.Renderer;
|
|
||||||
import com.terraforged.app.Applet;
|
import com.terraforged.app.Applet;
|
||||||
|
import com.terraforged.app.renderer.Renderer;
|
||||||
|
|
||||||
public class TestRenderer extends Renderer {
|
public class TestRenderer extends Renderer {
|
||||||
|
|
||||||
|
@ -1,38 +0,0 @@
|
|||||||
package com.terraforged.core.util;
|
|
||||||
|
|
||||||
import java.util.concurrent.Future;
|
|
||||||
import java.util.concurrent.TimeUnit;
|
|
||||||
|
|
||||||
public class FutureValue<T> implements Future<T> {
|
|
||||||
|
|
||||||
private final T value;
|
|
||||||
|
|
||||||
public FutureValue(T value) {
|
|
||||||
this.value = value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean cancel(boolean mayInterruptIfRunning) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCancelled() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDone() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T get() {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public T get(long timeout, TimeUnit unit) {
|
|
||||||
return value;
|
|
||||||
}
|
|
||||||
}
|
|
@ -139,7 +139,7 @@ public class PosGenerator {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
private float getHeight(int x, int z) {
|
public float getHeight(int x, int z) {
|
||||||
heightmap.visit(lookup, x, z);
|
heightmap.visit(lookup, x, z);
|
||||||
return lookup.value;
|
return lookup.value;
|
||||||
}
|
}
|
||||||
|
@ -19,11 +19,8 @@ import java.util.Random;
|
|||||||
public class RiverRegion {
|
public class RiverRegion {
|
||||||
|
|
||||||
public static final int SCALE = 12;
|
public static final int SCALE = 12;
|
||||||
// private static final float LAKE_CHANCE = 0.05F;
|
private static final double MIN_FORK_ANGLE = 20D;
|
||||||
// private static final float LAKE_MIN_DIST = 0.025F;
|
private static final double MAX_FORK_ANGLE = 60D;
|
||||||
// private static final float LAKE_MAX_DIST = 0.05F;
|
|
||||||
// private static final float LAKE_MIN_SIZE = 50;
|
|
||||||
// private static final float LAKE_MAX_SIZE = 100;
|
|
||||||
|
|
||||||
private final Domain domain;
|
private final Domain domain;
|
||||||
private final Terrains terrains;
|
private final Terrains terrains;
|
||||||
@ -42,7 +39,8 @@ public class RiverRegion {
|
|||||||
this.secondary = secondary;
|
this.secondary = secondary;
|
||||||
this.tertiary = tertiary;
|
this.tertiary = tertiary;
|
||||||
this.terrains = context.terrain;
|
this.terrains = context.terrain;
|
||||||
this.domain = Domain.warp(seed, 400, 1, 400).add(Domain.warp(seed + 1, 50, 1, 25));
|
this.domain = Domain.warp(seed, 400, 1, 400)
|
||||||
|
.add(Domain.warp(seed + 1, 80, 1, 35));;
|
||||||
try (ObjectPool.Item<Cell<Terrain>> cell = Cell.pooled()) {
|
try (ObjectPool.Item<Cell<Terrain>> cell = Cell.pooled()) {
|
||||||
PosGenerator pos = new PosGenerator(heightmap, domain, cell.getValue(),1 << SCALE, River.VALLEY_WIDTH);
|
PosGenerator pos = new PosGenerator(heightmap, domain, cell.getValue(),1 << SCALE, River.VALLEY_WIDTH);
|
||||||
this.rivers = generate(regionX, regionZ, pos);
|
this.rivers = generate(regionX, regionZ, pos);
|
||||||
@ -68,24 +66,22 @@ public class RiverRegion {
|
|||||||
Random random = new Random(regionSeed);
|
Random random = new Random(regionSeed);
|
||||||
List<River> rivers = new LinkedList<>();
|
List<River> rivers = new LinkedList<>();
|
||||||
|
|
||||||
// generates main rivers until either 10 attempts have passed or 2 rivers generate
|
for (int i = 0; rivers.size() < 4 && i < 50; i++) {
|
||||||
for (int i = 0; rivers.size() < 2 && i < 50; i++) {
|
|
||||||
generateRiver(x, z, pos, primary, random, rivers);
|
generateRiver(x, z, pos, primary, random, rivers);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; rivers.size() < 10 && i < 15; i++) {
|
for (int i = 0; rivers.size() < 10 && i < 50; i++) {
|
||||||
generateRiver(x, z, pos, secondary, random, rivers);
|
generateRiver(x, z, pos, secondary, random, rivers);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; rivers.size() < 10 && i < 15; i++) {
|
for (int i = 0; rivers.size() < 20 && i < 50; i++) {
|
||||||
generateConnectingRiver(x, z, pos, tertiary, random, rivers);
|
generateRiverFork(x, z, pos, tertiary, random, rivers);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; rivers.size() < 20 && i < 40; i++) {
|
for (int i = 0; rivers.size() < 30 && i < 50; i++) {
|
||||||
generateRiver(x, z, pos, tertiary, random, rivers);
|
generateRiver(x, z, pos, tertiary, random, rivers);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Collections.reverse(rivers);
|
Collections.reverse(rivers);
|
||||||
|
|
||||||
return rivers;
|
return rivers;
|
||||||
@ -124,7 +120,7 @@ public class RiverRegion {
|
|||||||
* Attempts to generate an inland position (p1), finds the nearest river (AB) to it, and tries to connect
|
* Attempts to generate an inland position (p1), finds the nearest river (AB) to it, and tries to connect
|
||||||
* a line from p1 to some position along AB
|
* a line from p1 to some position along AB
|
||||||
*/
|
*/
|
||||||
private boolean generateConnectingRiver(int x, int z, PosGenerator pos, RiverConfig config, Random random, List<River> rivers) {
|
private boolean generateRiverFork(int x, int z, PosGenerator pos, RiverConfig config, Random random, List<River> rivers) {
|
||||||
// generate a river start node
|
// generate a river start node
|
||||||
RiverNode p1 = pos.nextType(x, z, random, 50, RiverNode.Type.START);
|
RiverNode p1 = pos.nextType(x, z, random, 50, RiverNode.Type.START);
|
||||||
if (p1 == null) {
|
if (p1 == null) {
|
||||||
@ -147,25 +143,37 @@ public class RiverRegion {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// p1 is too close to start of the closest river
|
// connection should occur no less than 20% along the river length and no greater than 40%
|
||||||
if (startDist2 < 640000) {
|
float distance = 0.3F + (random.nextFloat() * 0.3F);
|
||||||
|
Vec2i fork = closest.bounds.pos(distance).toInt();
|
||||||
|
|
||||||
|
// connection should not occur in the ocean
|
||||||
|
float height = pos.getHeight(fork.x, fork.y);
|
||||||
|
RiverNode.Type type = RiverNode.getType(height);
|
||||||
|
if (type == RiverNode.Type.END) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// p1 should be closer to the main river start than it's end, otherwise we're likely to get forks
|
// calc angle between vector a (AB) & b (CB)
|
||||||
// in the wrong direction (ie one river splitting into two, rather two rivers joining)
|
// A - existing river's start
|
||||||
float endDist2 = dist2(p1.x, p1.z, closest.bounds.x2(), closest.bounds.y2());
|
// B - connection point
|
||||||
if (endDist2 < startDist2) {
|
// C - new river's start
|
||||||
|
int ax = fork.x - closest.bounds.x1();
|
||||||
|
int az = fork.y - closest.bounds.y1();
|
||||||
|
int bx = fork.x - p1.x;
|
||||||
|
int bz = fork.y - p1.z;
|
||||||
|
|
||||||
|
// radians = arccos(AB.BC / |AB||BC|)
|
||||||
|
int dotAB = ax * bx + az * bz;
|
||||||
|
double lenA = Math.sqrt(ax * ax + az * az);
|
||||||
|
double lenB = Math.sqrt(bx * bx + bz * bz);
|
||||||
|
double radians = Math.acos(dotAB / (lenA * lenB));
|
||||||
|
double angle = Math.toDegrees(radians);
|
||||||
|
if (angle < MIN_FORK_ANGLE || angle > MAX_FORK_ANGLE) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// pick a point some random distance along the main river, between 30%-70% along the main river length
|
RiverBounds bounds = new RiverBounds(p1.x, p1.z, fork.x, fork.y, 300);
|
||||||
// 0.4 offset should ensure the main river has become sufficiently wide for it not to look weird having
|
|
||||||
// a second river connect to it
|
|
||||||
float dist = 0.4F + (random.nextFloat() * 0.3F);
|
|
||||||
Vec2i p2 = closest.bounds.pos(dist).toInt();
|
|
||||||
RiverBounds bounds = new RiverBounds(p1.x, p1.z, p2.x, p2.y, 300);
|
|
||||||
|
|
||||||
// check that the new river does not clash/overlap any other nearby rivers
|
// check that the new river does not clash/overlap any other nearby rivers
|
||||||
for (River river : rivers) {
|
for (River river : rivers) {
|
||||||
if (river == closest) {
|
if (river == closest) {
|
||||||
|
@ -1 +1 @@
|
|||||||
Subproject commit d8b7591c569df9f4a24a2d4e2f1bed447ccf1788
|
Subproject commit 04b79407108d3b2cf84d1c0cd287b887ebc4d0cd
|
Loading…
Reference in New Issue
Block a user