From 7f7b58733d2caf84268c416d69e9289f68e453b4 Mon Sep 17 00:00:00 2001 From: ondra Date: Mon, 28 Apr 2014 14:05:47 +0200 Subject: [PATCH] flood fill room discovery --- src/mightypork/rogue/world/Sides.java | 47 ++++++++++++------ src/mightypork/rogue/world/entity/Entity.java | 7 +++ .../world/entity/models/PlayerModel.java | 2 +- .../rogue/world/gen/ScratchMap.java | 6 ++- src/mightypork/rogue/world/level/Level.java | 49 ++++++++++++++----- .../rogue/world/pathfinding/FillContext.java | 5 +- .../rogue/world/pathfinding/FloodFill.java | 30 ++++++++---- .../rogue/world/pathfinding/PathFinder.java | 9 +--- .../world/pathfinding/PathFindingContext.java | 3 ++ .../rogue/world/tile/TileModel.java | 1 + src/mightypork/util/files/ion/IonBinary.java | 1 - 11 files changed, 108 insertions(+), 52 deletions(-) diff --git a/src/mightypork/rogue/world/Sides.java b/src/mightypork/rogue/world/Sides.java index 78e018a..0441378 100644 --- a/src/mightypork/rogue/world/Sides.java +++ b/src/mightypork/rogue/world/Sides.java @@ -2,26 +2,26 @@ package mightypork.rogue.world; public class Sides { - - //@formatter:off + 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 E = 0b00010000; + public static final byte E = 0b00010000; 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 W = 0b00000001; + public static final byte W = 0b00000001; - public static final byte CARDINAL = N|S|E|W; - public static final byte DIAGONAL = NE|NW|SE|SW; + public static final byte CARDINAL = N | S | E | W; + public static final byte DIAGONAL = NE | NW | SE | SW; - public static final byte NW_CORNER = W|NW|N; - public static final byte NE_CORNER = E|NE|N; - public static final byte SW_CORNER = W|SW|S; - public static final byte SE_CORNER = E|SE|S; + public static final byte NW_CORNER = W | NW | N; + public static final byte NE_CORNER = E | NE | N; + public static final byte SW_CORNER = W | SW | 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(0, -1), Coord.make(1, -1), @@ -31,13 +31,28 @@ public class Sides { Coord.make(-1, 1), 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 - + + /** + * Get element from all sides + * + * @param i side index + * @return the side coord + */ 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) { return (byte) (1 << (7 - i)); diff --git a/src/mightypork/rogue/world/entity/Entity.java b/src/mightypork/rogue/world/entity/Entity.java index 5e8f676..fa31ab8 100644 --- a/src/mightypork/rogue/world/entity/Entity.java +++ b/src/mightypork/rogue/world/entity/Entity.java @@ -6,6 +6,7 @@ import java.util.ArrayList; import java.util.List; import mightypork.rogue.world.Coord; +import mightypork.rogue.world.Sides; import mightypork.rogue.world.World; import mightypork.rogue.world.entity.models.EntityModel; import mightypork.rogue.world.entity.models.EntityMoveListener; @@ -78,6 +79,12 @@ public final class Entity implements IonBinary { { return model.getPathCost(Entity.this, from, to); } + + + @Override + public Coord[] getWalkSides() { + return Sides.cardinalSides; + } }; diff --git a/src/mightypork/rogue/world/entity/models/PlayerModel.java b/src/mightypork/rogue/world/entity/models/PlayerModel.java index 9c910ff..5f2b641 100644 --- a/src/mightypork/rogue/world/entity/models/PlayerModel.java +++ b/src/mightypork/rogue/world/entity/models/PlayerModel.java @@ -46,7 +46,7 @@ public class PlayerModel extends EntityModel { private void exploreSurroundings(Entity entity) { - entity.getLevel().markExplored(entity.getCoord(), 4.5); + entity.getLevel().explore(entity.getCoord()); } diff --git a/src/mightypork/rogue/world/gen/ScratchMap.java b/src/mightypork/rogue/world/gen/ScratchMap.java index bc3803f..544b42f 100644 --- a/src/mightypork/rogue/world/gen/ScratchMap.java +++ b/src/mightypork/rogue/world/gen/ScratchMap.java @@ -15,7 +15,6 @@ import mightypork.rogue.world.pathfinding.PathFinder; import mightypork.rogue.world.pathfinding.PathFindingContext; import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.TileModel; -import mightypork.rogue.world.tile.TileType; import mightypork.rogue.world.tile.Tiles; import mightypork.util.logging.Log; import mightypork.util.math.Calc; @@ -78,6 +77,11 @@ public class ScratchMap { return PathFinder.CORNER_HEURISTIC; } + @Override + public Coord[] getWalkSides() { + return Sides.cardinalSides; + } + }; Coord genMin; diff --git a/src/mightypork/rogue/world/level/Level.java b/src/mightypork/rogue/world/level/Level.java index 671ad8c..8697ff4 100644 --- a/src/mightypork/rogue/world/level/Level.java +++ b/src/mightypork/rogue/world/level/Level.java @@ -9,17 +9,20 @@ import java.util.Map; import java.util.Set; import mightypork.rogue.world.Coord; +import mightypork.rogue.world.Sides; import mightypork.rogue.world.World; 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.TileModel; +import mightypork.rogue.world.tile.TileType; import mightypork.rogue.world.tile.Tiles; import mightypork.util.files.ion.IonBinary; import mightypork.util.files.ion.IonBundle; import mightypork.util.files.ion.IonInput; import mightypork.util.files.ion.IonOutput; import mightypork.util.logging.Log; -import mightypork.util.math.Calc; 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 filled = FloodFill.fill(center, exploreFc); + for(Coord c : filled) getTile(c).setExplored(); + } + + private FillContext exploreFc = new FillContext() { - final Coord c = Coord.zero(); - for (c.y = coord.y - cr; c.y <= coord.y + cr; c.y++) { - 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; - final Tile t = getTile(c); - if (!t.isNull()) { - t.setExplored(); - } - } + @Override + public Coord[] getSpreadSides() + { + return Sides.allSides; } - } + + @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(); + } + }; } diff --git a/src/mightypork/rogue/world/pathfinding/FillContext.java b/src/mightypork/rogue/world/pathfinding/FillContext.java index 10c3cb8..1f6c1d8 100644 --- a/src/mightypork/rogue/world/pathfinding/FillContext.java +++ b/src/mightypork/rogue/world/pathfinding/FillContext.java @@ -9,13 +9,14 @@ public interface FillContext { 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. * * @return max distance */ - int getMaxDistance(); + double getMaxDistance(); } diff --git a/src/mightypork/rogue/world/pathfinding/FloodFill.java b/src/mightypork/rogue/world/pathfinding/FloodFill.java index 6decd8d..0c2dc88 100644 --- a/src/mightypork/rogue/world/pathfinding/FloodFill.java +++ b/src/mightypork/rogue/world/pathfinding/FloodFill.java @@ -1,37 +1,47 @@ 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; -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 class FloodFill { public static final Collection fill(Coord start, FillContext context) { Set filled = new HashSet<>(); Stack active = new Stack<>(); - int maxDist = context.getMaxDistance(); + double maxDist = context.getMaxDistance(); active.push(start); - while (!active.isEmpty()) { + Coord[] sides = context.getSpreadSides(); + boolean first = true; + + while (!active.isEmpty()) { Coord current = active.pop(); - filled.add(current); - for (Coord spr : spread) { + if(!context.canSpreadFrom(current) && !first) continue; + + first = false; + + + for (Coord spr : sides) { Coord next = current.add(spr); + if(active.contains(next) || filled.contains(next)) continue; if (next.dist(start) > maxDist) continue; - if (context.canSpread(next)) { + if (context.canEnter(next)) { active.push(next); + } else { + filled.add(next); } } } diff --git a/src/mightypork/rogue/world/pathfinding/PathFinder.java b/src/mightypork/rogue/world/pathfinding/PathFinder.java index 755be29..b104bc8 100644 --- a/src/mightypork/rogue/world/pathfinding/PathFinder.java +++ b/src/mightypork/rogue/world/pathfinding/PathFinder.java @@ -58,14 +58,7 @@ public class PathFinder { open.add(n); } - //@formatter:off - final Coord[] walkDirs = { - Coord.make(0, -1), - Coord.make(0, 1), - Coord.make(-1, 0), - Coord.make(1, 0) - }; - //@formatter:on + final Coord[] walkDirs = context.getWalkSides(); Node current = null; diff --git a/src/mightypork/rogue/world/pathfinding/PathFindingContext.java b/src/mightypork/rogue/world/pathfinding/PathFindingContext.java index 9bfca49..8745e5c 100644 --- a/src/mightypork/rogue/world/pathfinding/PathFindingContext.java +++ b/src/mightypork/rogue/world/pathfinding/PathFindingContext.java @@ -33,4 +33,7 @@ public interface PathFindingContext { * @return used heuristic */ Heuristic getHeuristic(); + + + Coord[] getWalkSides(); } diff --git a/src/mightypork/rogue/world/tile/TileModel.java b/src/mightypork/rogue/world/tile/TileModel.java index 04cc856..f87543f 100644 --- a/src/mightypork/rogue/world/tile/TileModel.java +++ b/src/mightypork/rogue/world/tile/TileModel.java @@ -2,6 +2,7 @@ package mightypork.rogue.world.tile; import java.io.IOException; + import mightypork.util.files.ion.IonInput; import mightypork.util.files.ion.IonOutput; diff --git a/src/mightypork/util/files/ion/IonBinary.java b/src/mightypork/util/files/ion/IonBinary.java index 455918b..0696db1 100644 --- a/src/mightypork/util/files/ion/IonBinary.java +++ b/src/mightypork/util/files/ion/IonBinary.java @@ -1,7 +1,6 @@ package mightypork.util.files.ion; -import java.io.IOException; /**