flood fill room discovery

v5stable
ondra 11 years ago
parent c5374f5f6e
commit 7f7b58733d
  1. 47
      src/mightypork/rogue/world/Sides.java
  2. 7
      src/mightypork/rogue/world/entity/Entity.java
  3. 2
      src/mightypork/rogue/world/entity/models/PlayerModel.java
  4. 6
      src/mightypork/rogue/world/gen/ScratchMap.java
  5. 49
      src/mightypork/rogue/world/level/Level.java
  6. 5
      src/mightypork/rogue/world/pathfinding/FillContext.java
  7. 30
      src/mightypork/rogue/world/pathfinding/FloodFill.java
  8. 9
      src/mightypork/rogue/world/pathfinding/PathFinder.java
  9. 3
      src/mightypork/rogue/world/pathfinding/PathFindingContext.java
  10. 1
      src/mightypork/rogue/world/tile/TileModel.java
  11. 1
      src/mightypork/util/files/ion/IonBinary.java

@ -2,26 +2,26 @@ package mightypork.rogue.world;
public class Sides { public class Sides {
//@formatter:off
public static final byte NW = (byte) 0b10000000; public static final byte NW = (byte) 0b10000000;
public static final byte N = 0b01000000; public static final byte N = 0b01000000;
public static final byte NE = 0b00100000; public static final byte NE = 0b00100000;
public static final byte E = 0b00010000; public static final byte E = 0b00010000;
public static final byte SE = 0b00001000; public static final byte SE = 0b00001000;
public static final byte S = 0b00000100; public static final byte S = 0b00000100;
public static final byte SW = 0b00000010; public static final byte SW = 0b00000010;
public static final byte W = 0b00000001; public static final byte W = 0b00000001;
public static final byte CARDINAL = N|S|E|W; public static final byte CARDINAL = N | S | E | W;
public static final byte DIAGONAL = NE|NW|SE|SW; public static final byte DIAGONAL = NE | NW | SE | SW;
public static final byte NW_CORNER = W|NW|N; public static final byte NW_CORNER = W | NW | N;
public static final byte NE_CORNER = E|NE|N; public static final byte NE_CORNER = E | NE | N;
public static final byte SW_CORNER = W|SW|S; public static final byte SW_CORNER = W | SW | S;
public static final byte SE_CORNER = E|SE|S; public static final byte SE_CORNER = E | SE | S;
private final static Coord[] side = { //@formatter:off
public final static Coord[] allSides = {
Coord.make(-1, -1), Coord.make(-1, -1),
Coord.make(0, -1), Coord.make(0, -1),
Coord.make(1, -1), Coord.make(1, -1),
@ -31,13 +31,28 @@ public class Sides {
Coord.make(-1, 1), Coord.make(-1, 1),
Coord.make(-1, 0) Coord.make(-1, 0)
}; };
public final static Coord[] cardinalSides = {
Coord.make(0, -1),
Coord.make(1, 0),
Coord.make(0, 1),
Coord.make(-1, 0)
};
//@formatter:on //@formatter:on
/**
* Get element from all sides
*
* @param i side index
* @return the side coord
*/
public static Coord get(int i) public static Coord get(int i)
{ {
return side[i]; // FIXME Coord is mutable return allSides[i]; // FIXME Coord is mutable
} }
public static byte bit(int i) public static byte bit(int i)
{ {
return (byte) (1 << (7 - i)); return (byte) (1 << (7 - i));

@ -6,6 +6,7 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import mightypork.rogue.world.Coord; import mightypork.rogue.world.Coord;
import mightypork.rogue.world.Sides;
import mightypork.rogue.world.World; import mightypork.rogue.world.World;
import mightypork.rogue.world.entity.models.EntityModel; import mightypork.rogue.world.entity.models.EntityModel;
import mightypork.rogue.world.entity.models.EntityMoveListener; import mightypork.rogue.world.entity.models.EntityMoveListener;
@ -78,6 +79,12 @@ public final class Entity implements IonBinary {
{ {
return model.getPathCost(Entity.this, from, to); return model.getPathCost(Entity.this, from, to);
} }
@Override
public Coord[] getWalkSides() {
return Sides.cardinalSides;
}
}; };

@ -46,7 +46,7 @@ public class PlayerModel extends EntityModel {
private void exploreSurroundings(Entity entity) private void exploreSurroundings(Entity entity)
{ {
entity.getLevel().markExplored(entity.getCoord(), 4.5); entity.getLevel().explore(entity.getCoord());
} }

@ -15,7 +15,6 @@ import mightypork.rogue.world.pathfinding.PathFinder;
import mightypork.rogue.world.pathfinding.PathFindingContext; import mightypork.rogue.world.pathfinding.PathFindingContext;
import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileModel; import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileType;
import mightypork.rogue.world.tile.Tiles; import mightypork.rogue.world.tile.Tiles;
import mightypork.util.logging.Log; import mightypork.util.logging.Log;
import mightypork.util.math.Calc; import mightypork.util.math.Calc;
@ -78,6 +77,11 @@ public class ScratchMap {
return PathFinder.CORNER_HEURISTIC; return PathFinder.CORNER_HEURISTIC;
} }
@Override
public Coord[] getWalkSides() {
return Sides.cardinalSides;
}
}; };
Coord genMin; Coord genMin;

@ -9,17 +9,20 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import mightypork.rogue.world.Coord; import mightypork.rogue.world.Coord;
import mightypork.rogue.world.Sides;
import mightypork.rogue.world.World; import mightypork.rogue.world.World;
import mightypork.rogue.world.entity.Entity; import mightypork.rogue.world.entity.Entity;
import mightypork.rogue.world.pathfinding.FillContext;
import mightypork.rogue.world.pathfinding.FloodFill;
import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.Tile;
import mightypork.rogue.world.tile.TileModel; import mightypork.rogue.world.tile.TileModel;
import mightypork.rogue.world.tile.TileType;
import mightypork.rogue.world.tile.Tiles; import mightypork.rogue.world.tile.Tiles;
import mightypork.util.files.ion.IonBinary; import mightypork.util.files.ion.IonBinary;
import mightypork.util.files.ion.IonBundle; import mightypork.util.files.ion.IonBundle;
import mightypork.util.files.ion.IonInput; import mightypork.util.files.ion.IonInput;
import mightypork.util.files.ion.IonOutput; import mightypork.util.files.ion.IonOutput;
import mightypork.util.logging.Log; import mightypork.util.logging.Log;
import mightypork.util.math.Calc;
import mightypork.util.math.noise.NoiseGen; import mightypork.util.math.noise.NoiseGen;
@ -319,20 +322,40 @@ public class Level implements MapAccess, IonBinary {
} }
public void markExplored(Coord coord, double radius) public void explore(Coord center)
{ {
final int cr = (int) Math.ceil(radius); Collection<Coord> filled = FloodFill.fill(center, exploreFc);
for(Coord c : filled) getTile(c).setExplored();
}
private FillContext exploreFc = new FillContext() {
final Coord c = Coord.zero(); @Override
for (c.y = coord.y - cr; c.y <= coord.y + cr; c.y++) { public Coord[] getSpreadSides()
for (c.x = coord.x - cr; c.x <= coord.x + cr; c.x++) { {
if (Calc.dist(coord.x, coord.y, c.x, c.y) > radius) continue; return Sides.allSides;
final Tile t = getTile(c);
if (!t.isNull()) {
t.setExplored();
}
}
} }
}
@Override
public double getMaxDistance()
{
return 6;
}
@Override
public boolean canSpreadFrom(Coord pos)
{
Tile t = getTile(pos);
return t.isWalkable() && t.getType() != TileType.DOOR;
}
@Override
public boolean canEnter(Coord pos)
{
return !getTile(pos).isNull();
}
};
} }

@ -9,13 +9,14 @@ public interface FillContext {
boolean canEnter(Coord pos); boolean canEnter(Coord pos);
boolean canSpread(Coord pos); boolean canSpreadFrom(Coord pos);
Coord[] getSpreadSides();
/** /**
* Get the max distance filled form start point. Use -1 for unlimited range. * Get the max distance filled form start point. Use -1 for unlimited range.
* *
* @return max distance * @return max distance
*/ */
int getMaxDistance(); double getMaxDistance();
} }

@ -1,37 +1,47 @@
package mightypork.rogue.world.pathfinding; package mightypork.rogue.world.pathfinding;
import java.util.*; import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.Stack;
import mightypork.rogue.world.Coord; import mightypork.rogue.world.Coord;
public class FloodFill { public class FloodFill {
private static final Coord[] spread = { Coord.make(0, -1), Coord.make(0, 1), Coord.make(1, 0), Coord.make(-1, 0) };
public static final Collection<Coord> fill(Coord start, FillContext context) public static final Collection<Coord> fill(Coord start, FillContext context)
{ {
Set<Coord> filled = new HashSet<>(); Set<Coord> filled = new HashSet<>();
Stack<Coord> active = new Stack<>(); Stack<Coord> active = new Stack<>();
int maxDist = context.getMaxDistance(); double maxDist = context.getMaxDistance();
active.push(start); active.push(start);
while (!active.isEmpty()) { Coord[] sides = context.getSpreadSides();
boolean first = true;
while (!active.isEmpty()) {
Coord current = active.pop(); Coord current = active.pop();
filled.add(current); filled.add(current);
for (Coord spr : spread) { if(!context.canSpreadFrom(current) && !first) continue;
first = false;
for (Coord spr : sides) {
Coord next = current.add(spr); Coord next = current.add(spr);
if(active.contains(next) || filled.contains(next)) continue;
if (next.dist(start) > maxDist) continue; if (next.dist(start) > maxDist) continue;
if (context.canSpread(next)) { if (context.canEnter(next)) {
active.push(next); active.push(next);
} else {
filled.add(next);
} }
} }
} }

@ -58,14 +58,7 @@ public class PathFinder {
open.add(n); open.add(n);
} }
//@formatter:off final Coord[] walkDirs = context.getWalkSides();
final Coord[] walkDirs = {
Coord.make(0, -1),
Coord.make(0, 1),
Coord.make(-1, 0),
Coord.make(1, 0)
};
//@formatter:on
Node current = null; Node current = null;

@ -33,4 +33,7 @@ public interface PathFindingContext {
* @return used heuristic * @return used heuristic
*/ */
Heuristic getHeuristic(); Heuristic getHeuristic();
Coord[] getWalkSides();
} }

@ -2,6 +2,7 @@ package mightypork.rogue.world.tile;
import java.io.IOException; import java.io.IOException;
import mightypork.util.files.ion.IonInput; import mightypork.util.files.ion.IonInput;
import mightypork.util.files.ion.IonOutput; import mightypork.util.files.ion.IonOutput;

@ -1,7 +1,6 @@
package mightypork.util.files.ion; package mightypork.util.files.ion;
import java.io.IOException;
/** /**

Loading…
Cancel
Save