diff --git a/res/img/tiles16.png b/res/img/tiles16.png index c972b97..b32c953 100644 Binary files a/res/img/tiles16.png and b/res/img/tiles16.png differ diff --git a/src/mightypork/gamecore/render/DisplaySystem.java b/src/mightypork/gamecore/render/DisplaySystem.java index 7e8fc28..44363dc 100644 --- a/src/mightypork/gamecore/render/DisplaySystem.java +++ b/src/mightypork/gamecore/render/DisplaySystem.java @@ -63,7 +63,8 @@ public class DisplaySystem extends AppModule implements RectBound { @Override protected void deinit() { - Display.destroy(); + // causes weird visual glitch +// Display.destroy(); } diff --git a/src/mightypork/rogue/Res.java b/src/mightypork/rogue/Res.java index 65cce3d..89ec554 100644 --- a/src/mightypork/rogue/Res.java +++ b/src/mightypork/rogue/Res.java @@ -79,20 +79,6 @@ public final class Res { textures.addQuad("xp_off", gui.makeQuad(.5, 1.5, .5, .5)); textures.addQuad("panel", gui.makeQuad(0, 3.75, 4, .25)); - // huge sheet -// texture = textures.loadTexture("tiles", "/res/img/tiles.png", FilterMode.NEAREST, WrapMode.CLAMP); -// tiles = texture.grid(32, 32); -// textures.addSheet("tile.wall.mossy_bricks", tiles.makeSheet(4, 0, 7, 1)); -// textures.addSheet("tile.wall.small_bricks", tiles.makeSheet(0, 0, 4, 1)); -// textures.addSheet("tile.floor.mossy_bricks", tiles.makeSheet(16, 5, 7, 1)); -// textures.addSheet("tile.floor.rect_bricks", tiles.makeSheet(23, 5, 4, 1)); -// textures.addSheet("tile.wall.sandstone", tiles.makeSheet(0, 3, 10, 1)); -// textures.addSheet("tile.floor.sandstone", tiles.makeSheet(0, 6, 10, 1)); -// textures.addSheet("tile.wall.brown_cobble", tiles.makeSheet(0, 8, 8, 1)); -// textures.addSheet("tile.floor.brown_cobble", tiles.makeSheet(0, 11, 9, 1)); -// textures.addSheet("tile.floor.crystal", tiles.makeSheet(4, 5, 6, 1)); -// textures.addSheet("tile.wall.crystal", tiles.makeSheet(12, 2, 14, 1)); - // sprites texture = textures.loadTexture("mob", "/res/img/dudes.png", FilterMode.NEAREST, WrapMode.CLAMP); tiles = texture.grid(8, 8); @@ -102,18 +88,21 @@ public final class Res { texture = textures.loadTexture("tiles16", "/res/img/tiles16.png", FilterMode.NEAREST, WrapMode.CLAMP); tiles = texture.grid(8, 8); - textures.addSheet("tile16.floor.dark", tiles.makeSheet(0, 1, 5, 1)); - textures.addSheet("tile16.wall.brick", tiles.makeSheet(0, 0, 5, 1)); + textures.addSheet("tile.floor.dark", tiles.makeSheet(0, 1, 5, 1)); + textures.addSheet("tile.wall.brick", tiles.makeSheet(0, 0, 5, 1)); + + textures.addQuad("tile.door.closed", tiles.makeQuad(1, 2)); + textures.addQuad("tile.door.open", tiles.makeQuad(2, 2)); - textures.addQuad("tile16.shadow.n", tiles.makeQuad(0, 7)); - textures.addQuad("tile16.shadow.s", tiles.makeQuad(0, 7).flipY()); - textures.addQuad("tile16.shadow.w", tiles.makeQuad(2, 7)); - textures.addQuad("tile16.shadow.e", tiles.makeQuad(2, 7).flipX()); + textures.addQuad("tile.shadow.n", tiles.makeQuad(0, 7)); + textures.addQuad("tile.shadow.s", tiles.makeQuad(0, 7).flipY()); + textures.addQuad("tile.shadow.w", tiles.makeQuad(2, 7)); + textures.addQuad("tile.shadow.e", tiles.makeQuad(2, 7).flipX()); - textures.addQuad("tile16.shadow.nw", tiles.makeQuad(1, 7)); - textures.addQuad("tile16.shadow.ne", tiles.makeQuad(1, 7).flipX()); - textures.addQuad("tile16.shadow.sw", tiles.makeQuad(1, 7).flipY()); - textures.addQuad("tile16.shadow.se", tiles.makeQuad(1, 7).flipY().flipX()); + textures.addQuad("tile.shadow.nw", tiles.makeQuad(1, 7)); + textures.addQuad("tile.shadow.ne", tiles.makeQuad(1, 7).flipX()); + textures.addQuad("tile.shadow.sw", tiles.makeQuad(1, 7).flipY()); + textures.addQuad("tile.shadow.se", tiles.makeQuad(1, 7).flipY().flipX()); } diff --git a/src/mightypork/rogue/screens/gamescreen/ScreenGame.java b/src/mightypork/rogue/screens/gamescreen/ScreenGame.java index 2354b40..a0751a5 100644 --- a/src/mightypork/rogue/screens/gamescreen/ScreenGame.java +++ b/src/mightypork/rogue/screens/gamescreen/ScreenGame.java @@ -8,8 +8,8 @@ import java.util.Random; import mightypork.gamecore.control.AppAccess; import mightypork.gamecore.gui.screens.LayeredScreen; import mightypork.rogue.Paths; -import mightypork.rogue.world.MapGenerator; import mightypork.rogue.world.World; +import mightypork.rogue.world.WorldCreator; import mightypork.util.files.ion.Ion; @@ -34,7 +34,7 @@ public class ScreenGame extends LayeredScreen { // SAVE - final World world = MapGenerator.createWorld(rand.nextLong()); + final World world = WorldCreator.createWorld(rand.nextLong()); addChildClient(world); try { diff --git a/src/mightypork/rogue/screens/gamescreen/WorldLayer.java b/src/mightypork/rogue/screens/gamescreen/WorldLayer.java index e70697e..0c8e123 100644 --- a/src/mightypork/rogue/screens/gamescreen/WorldLayer.java +++ b/src/mightypork/rogue/screens/gamescreen/WorldLayer.java @@ -3,8 +3,8 @@ package mightypork.rogue.screens.gamescreen; import mightypork.gamecore.gui.screens.Screen; import mightypork.gamecore.gui.screens.ScreenLayer; +import mightypork.rogue.screens.gamescreen.world.MIPClickPathfWalk; import mightypork.rogue.screens.gamescreen.world.MIPKeyWalk; -import mightypork.rogue.screens.gamescreen.world.MIPMouseWalk; import mightypork.rogue.screens.gamescreen.world.MapView; import mightypork.rogue.world.World; import mightypork.util.math.constraints.num.Num; @@ -25,7 +25,8 @@ public class WorldLayer extends ScreenLayer { // map input plugins worldView.addPlugin(new MIPKeyWalk()); - worldView.addPlugin(new MIPMouseWalk()); + worldView.addPlugin(new MIPClickPathfWalk()); + //worldView.addPlugin(new MIPMouseWalk()); // size of lower navbar final Num lownav = root.width().min(root.height()).max(700).perc(7); diff --git a/src/mightypork/rogue/screens/gamescreen/world/MIPClickPathfWalk.java b/src/mightypork/rogue/screens/gamescreen/world/MIPClickPathfWalk.java new file mode 100644 index 0000000..e22ff4d --- /dev/null +++ b/src/mightypork/rogue/screens/gamescreen/world/MIPClickPathfWalk.java @@ -0,0 +1,38 @@ +package mightypork.rogue.screens.gamescreen.world; + + +import mightypork.gamecore.input.InputSystem; +import mightypork.rogue.world.PlayerControl; +import mightypork.rogue.world.WorldPos; +import mightypork.util.math.constraints.vect.Vect; + + +public class MIPClickPathfWalk implements MapInteractionPlugin { + + @Override + public void onStepEnd(MapView wv, PlayerControl player) + { + if (InputSystem.isMouseButtonDown(0)) { + final WorldPos clicked = wv.toWorldPos(InputSystem.getMousePos()); + player.navigateTo(clicked); + } + } + + + @Override + public void onClick(MapView wv, PlayerControl player, Vect mouse, int button, boolean down) + { + if (!down) return; + + final WorldPos clicked = wv.toWorldPos(mouse); + + player.navigateTo(clicked); + } + + + @Override + public void onKey(MapView wv, PlayerControl player, int key, boolean down) + { + } + +} diff --git a/src/mightypork/rogue/screens/gamescreen/world/MIPKeyWalk.java b/src/mightypork/rogue/screens/gamescreen/world/MIPKeyWalk.java index 11c1473..81f4764 100644 --- a/src/mightypork/rogue/screens/gamescreen/world/MIPKeyWalk.java +++ b/src/mightypork/rogue/screens/gamescreen/world/MIPKeyWalk.java @@ -17,7 +17,7 @@ public class MIPKeyWalk implements MapInteractionPlugin { @Override - public void onClick(MapView wv, PlayerControl player, Vect mouse, boolean down) + public void onClick(MapView wv, PlayerControl player, Vect mouse, int button, boolean down) { } @@ -25,7 +25,7 @@ public class MIPKeyWalk implements MapInteractionPlugin { @Override public void onKey(MapView wv, PlayerControl player, int key, boolean down) { - if(down) walkByKey(player); + if (down) walkByKey(player); } diff --git a/src/mightypork/rogue/screens/gamescreen/world/MIPMouseWalk.java b/src/mightypork/rogue/screens/gamescreen/world/MIPMouseWalk.java index bb5d212..08f9e94 100644 --- a/src/mightypork/rogue/screens/gamescreen/world/MIPMouseWalk.java +++ b/src/mightypork/rogue/screens/gamescreen/world/MIPMouseWalk.java @@ -16,15 +16,15 @@ public class MIPMouseWalk implements MapInteractionPlugin { { if (InputSystem.isMouseButtonDown(0)) { // walk by holding btn - onClick(wv, player, InputSystem.getMousePos(), true); + onClick(wv, player, InputSystem.getMousePos(), 0, true); } } @Override - public void onClick(MapView wv, PlayerControl player, Vect mouse, boolean down) + public void onClick(MapView wv, PlayerControl player, Vect mouse, int button, boolean down) { - if(!down) return; + if (!down) return; final WorldPos plpos = player.getPos(); final WorldPos clicked = wv.toWorldPos(mouse); diff --git a/src/mightypork/rogue/screens/gamescreen/world/MapInteractionPlugin.java b/src/mightypork/rogue/screens/gamescreen/world/MapInteractionPlugin.java index 95edb7a..4c4da9d 100644 --- a/src/mightypork/rogue/screens/gamescreen/world/MapInteractionPlugin.java +++ b/src/mightypork/rogue/screens/gamescreen/world/MapInteractionPlugin.java @@ -10,7 +10,7 @@ public interface MapInteractionPlugin { void onStepEnd(MapView wv, PlayerControl player); - void onClick(MapView wv, PlayerControl player, Vect mouse, boolean down); + void onClick(MapView wv, PlayerControl player, Vect mouse, int button, boolean down); void onKey(MapView wv, PlayerControl player, int key, boolean down); diff --git a/src/mightypork/rogue/screens/gamescreen/world/MapView.java b/src/mightypork/rogue/screens/gamescreen/world/MapView.java index a62715c..001824f 100644 --- a/src/mightypork/rogue/screens/gamescreen/world/MapView.java +++ b/src/mightypork/rogue/screens/gamescreen/world/MapView.java @@ -31,7 +31,7 @@ public class MapView extends InputComponent implements KeyListener, MouseButtonL public MapView(World world) { this.world = world; - this.worldRenderer = new WorldRenderer(world, this, 8, 8, 64); + this.worldRenderer = new WorldRenderer(world, this, 12, 8, 40);//8, 8, 64 pc = world.getPlayerControl(); pc.addMoveListener(this); } @@ -96,7 +96,7 @@ public class MapView extends InputComponent implements KeyListener, MouseButtonL if (!event.isOver(this)) return; for (final MapInteractionPlugin p : plugins) { - p.onClick(this, pc, event.getPos(), event.isDown()); + p.onClick(this, pc, event.getPos(), event.getButton(), event.isDown()); } event.consume(); // only our clicks. diff --git a/src/mightypork/rogue/world/gen/Coord.java b/src/mightypork/rogue/world/Coord.java similarity index 51% rename from src/mightypork/rogue/world/gen/Coord.java rename to src/mightypork/rogue/world/Coord.java index cc75210..8331586 100644 --- a/src/mightypork/rogue/world/gen/Coord.java +++ b/src/mightypork/rogue/world/Coord.java @@ -1,4 +1,4 @@ -package mightypork.rogue.world.gen; +package mightypork.rogue.world; import mightypork.util.annotations.FactoryMethod; @@ -16,13 +16,15 @@ public class Coord { { return new Coord(x, y); } - + + @FactoryMethod public static Coord make(Coord other) { return new Coord(other); } + public Coord(int x, int y) { super(); @@ -44,14 +46,46 @@ public class Coord { } + public Coord add(Coord other) + { + return add(other.x, other.y); + } + + public Coord copy() { return make(this); } + @Override public String toString() { - return "Coord("+x+","+y+")"; + return "Coord(" + x + "," + y + ")"; + } + + + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + result = prime * result + x; + result = prime * result + y; + return result; + } + + + @Override + public boolean equals(Object obj) + { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof Coord)) return false; + final Coord other = (Coord) obj; + if (x != other.x) return false; + if (y != other.y) return false; + return true; } + } diff --git a/src/mightypork/rogue/world/PathStep.java b/src/mightypork/rogue/world/PathStep.java index 2018136..d319d09 100644 --- a/src/mightypork/rogue/world/PathStep.java +++ b/src/mightypork/rogue/world/PathStep.java @@ -65,4 +65,11 @@ public class PathStep implements IonBinary { return ION_MARK; } + + @Override + public String toString() + { + return "(" + x + "|" + y + ")"; + } + } diff --git a/src/mightypork/rogue/world/PlayerControl.java b/src/mightypork/rogue/world/PlayerControl.java index e6a5091..d0fbdb2 100644 --- a/src/mightypork/rogue/world/PlayerControl.java +++ b/src/mightypork/rogue/world/PlayerControl.java @@ -1,14 +1,43 @@ package mightypork.rogue.world; +import java.util.List; + import mightypork.rogue.world.entity.models.EntityMoveListener; import mightypork.rogue.world.level.Level; +import mightypork.rogue.world.pathfinding.PathCostProvider; +import mightypork.rogue.world.pathfinding.PathFinder; public class PlayerControl { private final World world; + PathCostProvider costProvider = new PathCostProvider() { + + @Override + public boolean isAccessible(Coord pos) + { + return getLevel().canWalkInto(pos.x, pos.y); + } + + + @Override + public int getMinCost() + { + return 10; + } + + + @Override + public int getCost(Coord from, Coord to) + { + return 10; + } + }; + + private final PathFinder pf = new PathFinder(costProvider, PathFinder.CORNER_HEURISTIC); + public PlayerControl(World w) { @@ -18,28 +47,45 @@ public class PlayerControl { public void goNorth() { + world.getPlayerEntity().cancelPath(); world.getPlayerEntity().addStep(PathStep.NORTH); } public void goSouth() { + world.getPlayerEntity().cancelPath(); world.getPlayerEntity().addStep(PathStep.SOUTH); } public void goEast() { + world.getPlayerEntity().cancelPath(); world.getPlayerEntity().addStep(PathStep.EAST); } public void goWest() { + world.getPlayerEntity().cancelPath(); world.getPlayerEntity().addStep(PathStep.WEST); } + public void navigateTo(WorldPos where) + { + final Coord start = world.getPlayerEntity().getPosition().toCoord(); + final Coord end = where.toCoord(); + final List path = pf.findPathRelative(start, end); + + if (path == null) return; + + world.getPlayerEntity().cancelPath(); + world.getPlayerEntity().addSteps(path); + } + + public void addMoveListener(EntityMoveListener eml) { world.getPlayerEntity().addMoveListener(eml); diff --git a/src/mightypork/rogue/world/World.java b/src/mightypork/rogue/world/World.java index 85e90e2..e49a0fe 100644 --- a/src/mightypork/rogue/world/World.java +++ b/src/mightypork/rogue/world/World.java @@ -84,13 +84,14 @@ public class World implements IonBundled, Updateable { { return eid++; } - - + + public void createPlayer(WorldPos pos, int level) { createPlayer(pos.x, pos.y, level); } + public void createPlayer(int x, int y, int level) { if (playerInfo.isInitialized()) { @@ -125,5 +126,5 @@ public class World implements IonBundled, Updateable { { return playerEntity; } - + } diff --git a/src/mightypork/rogue/world/MapGenerator.java b/src/mightypork/rogue/world/WorldCreator.java similarity index 82% rename from src/mightypork/rogue/world/MapGenerator.java rename to src/mightypork/rogue/world/WorldCreator.java index 12dc893..d7bc212 100644 --- a/src/mightypork/rogue/world/MapGenerator.java +++ b/src/mightypork/rogue/world/WorldCreator.java @@ -5,11 +5,9 @@ import java.util.Random; import mightypork.rogue.world.gen.LevelGenerator; import mightypork.rogue.world.level.Level; -import mightypork.rogue.world.tile.Tiles; -import mightypork.rogue.world.tile.models.TileModel; -public class MapGenerator { +public class WorldCreator { public static final Random rand = new Random(); diff --git a/src/mightypork/rogue/world/WorldPos.java b/src/mightypork/rogue/world/WorldPos.java index 05b1a79..85b14da 100644 --- a/src/mightypork/rogue/world/WorldPos.java +++ b/src/mightypork/rogue/world/WorldPos.java @@ -107,12 +107,14 @@ public class WorldPos implements IonBundled, Updateable { setTo(other.x, other.y); } + @Override public String toString() { - return "WorldPos("+x+","+y+")"; + return "WorldPos(" + x + "," + y + ")"; } + @Override public int hashCode() { @@ -157,4 +159,10 @@ public class WorldPos implements IonBundled, Updateable { return walkOffset.isFinished(); } + + public Coord toCoord() + { + return new Coord(x, y); + } + } diff --git a/src/mightypork/rogue/world/entity/Entity.java b/src/mightypork/rogue/world/entity/Entity.java index 218b1a6..1e418fb 100644 --- a/src/mightypork/rogue/world/entity/Entity.java +++ b/src/mightypork/rogue/world/entity/Entity.java @@ -275,4 +275,10 @@ public final class Entity implements IonBinary, IonBundled, EntityMoveListener { { moveListeners.add(listener); } + + + public void addSteps(List path) + { + this.path.addAll(path); + } } diff --git a/src/mightypork/rogue/world/gen/LevelGenerator.java b/src/mightypork/rogue/world/gen/LevelGenerator.java index 6317d6c..525c1b6 100644 --- a/src/mightypork/rogue/world/gen/LevelGenerator.java +++ b/src/mightypork/rogue/world/gen/LevelGenerator.java @@ -3,43 +3,38 @@ package mightypork.rogue.world.gen; import java.util.Random; -import mightypork.rogue.world.WorldPos; -import mightypork.rogue.world.gen.rooms.IntersectionRoom; -import mightypork.rogue.world.gen.rooms.SquareRoom; +import mightypork.rogue.world.Coord; +import mightypork.rogue.world.gen.rooms.SimpleRectRoom; import mightypork.rogue.world.gen.themes.ThemeDungeon; import mightypork.rogue.world.level.Level; -import mightypork.rogue.world.tile.Tile; -import mightypork.rogue.world.tile.Tiles; -import mightypork.util.logging.Log; public class LevelGenerator { public static final Theme DUNGEON_THEME = new ThemeDungeon(); - public static final RoomBuilder ROOM_SQUARE = new SquareRoom(); - public static final RoomBuilder ROOM_INTERSECTION = new IntersectionRoom(); + public static final RoomBuilder ROOM_SQUARE = new SimpleRectRoom(); public static Level build(long seed, Theme theme) { - Random rand = new Random(seed + 47); + final Random rand = new Random(seed + 13); - final int max_size = 500; + final int max_size = 512; - ScratchMap map = new ScratchMap(max_size, theme, rand); + final ScratchMap map = new ScratchMap(max_size, theme, rand); // start map.addRoom(ROOM_SQUARE); - for (int i = 0; i < 5+rand.nextInt(4); i++) { + for (int i = 0; i < 6 + rand.nextInt(6); i++) { map.addRoom(ROOM_SQUARE); - for(int j=0;j<4;j++) map.addRoom(ROOM_INTERSECTION); } + map.buildCorridors(); - Coord size = map.getNeededSize(); - Level lvl = new Level(size.x, size.y); + final Coord size = map.getNeededSize(); + final Level lvl = new Level(size.x, size.y); map.writeToLevel(lvl); diff --git a/src/mightypork/rogue/world/gen/RoomBuilder.java b/src/mightypork/rogue/world/gen/RoomBuilder.java index 67222aa..fd5c57c 100644 --- a/src/mightypork/rogue/world/gen/RoomBuilder.java +++ b/src/mightypork/rogue/world/gen/RoomBuilder.java @@ -1,12 +1,17 @@ package mightypork.rogue.world.gen; -import java.util.List; + import java.util.Random; -import mightypork.rogue.world.tile.Tile; +import mightypork.rogue.world.Coord; + -// room builder interface -public interface RoomBuilder { +/** + * Room model + * + * @author MightyPork + */ +public interface RoomBuilder { RoomDesc buildToFit(ScratchMap map, Theme theme, Random rand, Coord center); -} \ No newline at end of file +} diff --git a/src/mightypork/rogue/world/gen/RoomDesc.java b/src/mightypork/rogue/world/gen/RoomDesc.java index 44decba..c1d3313 100644 --- a/src/mightypork/rogue/world/gen/RoomDesc.java +++ b/src/mightypork/rogue/world/gen/RoomDesc.java @@ -1,25 +1,25 @@ package mightypork.rogue.world.gen; -import java.util.ArrayList; -import java.util.List; +import mightypork.rogue.world.Coord; -// room info +/** + * Room description + * + * @author MightyPork + */ public class RoomDesc { - final List doors = new ArrayList<>(); final Coord min; final Coord max; - public RoomDesc(Coord min, Coord max, List doors) + public RoomDesc(Coord min, Coord max) { super(); this.min = min; this.max = max; - - this.doors.addAll(doors); } diff --git a/src/mightypork/rogue/world/gen/ScratchMap.java b/src/mightypork/rogue/world/gen/ScratchMap.java index 4d6c600..be475a7 100644 --- a/src/mightypork/rogue/world/gen/ScratchMap.java +++ b/src/mightypork/rogue/world/gen/ScratchMap.java @@ -5,25 +5,60 @@ import java.util.ArrayList; import java.util.List; import java.util.Random; +import mightypork.rogue.world.Coord; import mightypork.rogue.world.WorldPos; import mightypork.rogue.world.level.Level; +import mightypork.rogue.world.pathfinding.PathCostProvider; +import mightypork.rogue.world.pathfinding.PathFinder; import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.Tiles; import mightypork.rogue.world.tile.models.TileModel; +import mightypork.util.logging.Log; public class ScratchMap { - private Tile[][] map; - private int width; - private int height; + private final Tile[][] map; + private final int width; + private final int height; - private List rooms = new ArrayList<>(); + private final List rooms = new ArrayList<>(); + private final List nodes = new ArrayList<>(); // points to connect with corridors + + private final PathCostProvider pcp = new PathCostProvider() { + + @Override + public boolean isAccessible(Coord pos) + { + return isIn(pos); // suffices for now + } + + + @Override + public int getCost(Coord last, Coord pos) + { + final Tile t = get(pos); + + if (t.isWalkable()) return 10; + + return 100; // wall + } + + + @Override + public int getMinCost() + { + return 10; + } + + }; + + private final PathFinder pathFinder = new PathFinder(pcp, PathFinder.CORNER_HEURISTIC); Coord genMin; Coord genMax; - private Theme theme; - private Random rand; + private final Theme theme; + private final Random rand; private Coord enterPoint; @@ -31,7 +66,7 @@ public class ScratchMap { { map = new Tile[max_size][max_size]; - genMin = Coord.make(max_size / 2, max_size / 2); + genMin = Coord.make((max_size / 2) - 1, (max_size / 2) - 1); genMax = genMin.add(1, 1); width = max_size; @@ -45,15 +80,33 @@ public class ScratchMap { public void addRoom(RoomBuilder rb) { - Coord center = Coord.make(0, 0); + final Coord center = Coord.make(0, 0); int failed = 0; while (true) { - center.x = genMin.x + rand.nextInt(genMax.x - genMin.x); - center.y = genMin.y + rand.nextInt(genMax.y - genMin.y); - RoomDesc rd = rb.buildToFit(this, theme, rand, center); + final int sizeX = genMax.x - genMin.x; + final int sizeY = genMax.y - genMin.y; + + center.x = genMin.x + rand.nextInt(sizeX + 1); + center.y = genMin.y + rand.nextInt(sizeY + 1); + + switch (rand.nextInt(4)) { + case 0: + center.x += 1 + rand.nextInt(3); + break; + case 1: + center.x -= 1 + rand.nextInt(3); + break; + case 2: + center.y += 1 + rand.nextInt(3); + break; + case 3: + center.y -= 1 + rand.nextInt(3); + } + + final RoomDesc rd = rb.buildToFit(this, theme, rand, center); if (rd != null) { if (rooms.isEmpty()) { enterPoint = center.copy(); @@ -67,19 +120,15 @@ public class ScratchMap { genMax.x = Math.max(genMax.x, rd.max.x); genMax.y = Math.max(genMax.y, rd.max.y); + nodes.add(center); + Log.f3("placed room: " + rd.min + " -> " + rd.max); + return; } else { failed++; - if (failed % 5 == 0) { - switch(rand.nextInt(4)) { - case 0: genMin.x--; break; - case 1: genMin.y--; break; - case 2: genMax.x++; break; - case 3: genMax.y++; break; - } - } - if (failed > 200) { + if (failed > 40) { + Log.w("Faild to build room."); return; } } @@ -97,7 +146,7 @@ public class ScratchMap { public Tile get(Coord pos) { if (!isIn(pos)) { - return Tiles.NULL_SOLID.createTile(); + throw new IndexOutOfBoundsException("Tile not in map: " + pos); } return map[pos.y][pos.x]; @@ -113,7 +162,7 @@ public class ScratchMap { public boolean set(Coord pos, Tile tile) { if (!isIn(pos)) { - return false; + throw new IndexOutOfBoundsException("Tile not in map: " + pos); } map[pos.y][pos.x] = tile; @@ -121,20 +170,10 @@ public class ScratchMap { } - public boolean canBuild(Coord pos) - { - if (!isIn(pos)) return false; - TileModel tm = get(pos).getModel(); - return tm.isNullTile() && tm.isWalkable(); - } - - public boolean isClear(Coord min, Coord max) { - if (!isIn(min)) return false; - if (!isIn(max)) return false; - - for (RoomDesc r : rooms) { + if (!isIn(min) || !isIn(max)) return false; + for (final RoomDesc r : rooms) { if (r.intersectsWith(min, max)) return false; } @@ -144,7 +183,9 @@ public class ScratchMap { public void fill(Coord min, Coord max, TileModel tm) { - Coord c = Coord.make(0, 0); + if (!isIn(min) || !isIn(max)) throw new IndexOutOfBoundsException("Tile(s) not in map: " + min + " , " + max); + + final Coord c = Coord.make(0, 0); for (c.y = min.y; c.y <= max.y; c.y++) for (c.x = min.x; c.x <= max.x; c.x++) set(c, tm.createTile()); @@ -153,7 +194,9 @@ public class ScratchMap { public void border(Coord min, Coord max, TileModel tm) { - Coord c = Coord.make(0, 0); + if (!isIn(min) || !isIn(max)) throw new IndexOutOfBoundsException("Tile(s) not in map: " + min + " , " + max); + + final Coord c = Coord.make(0, 0); for (c.y = min.y; c.y <= max.y; c.y++) { for (c.x = min.x; c.x <= max.x; c.x++) { @@ -165,6 +208,61 @@ public class ScratchMap { } + public void buildCorridors() + { + for (final Coord door1 : nodes) { + for (final Coord door2 : nodes) { + if (door1 == door2) continue; + + buildCorridor(door1, door2); + } + } + } + + + private void buildCorridor(Coord node1, Coord node2) + { + + final List steps = pathFinder.findPath(node1, node2); + + if (steps == null) { + Log.w("Could not build corridor " + node1 + "->" + node2); + return; + } + + for (final Coord c : steps) { + buildCorridorPiece(c); + } + } + + + private void buildCorridorPiece(Coord pos) + { + final Coord c = Coord.make(0, 0); + int i, j; + for (i = -1, c.x = pos.x - 1; c.x <= pos.x + 1; c.x++, i++) { + for (j = -1, c.y = pos.y - 1; c.y <= pos.y + 1; c.y++, j++) { + if (!isIn(c)) continue; + + genMin.x = Math.min(genMin.x, c.x); + genMin.y = Math.min(genMin.y, c.y); + + genMax.x = Math.max(genMax.x, c.x); + genMax.y = Math.max(genMax.y, c.y); + + final Tile current = get(c); + if (!current.getModel().isNullTile() && current.isWalkable()) continue; // floor already, let it be + + if (i == 0 && j == 0) { + set(c, theme.floor()); + } else { + set(c, theme.wall()); + } + } + } + } + + public Coord getNeededSize() { return Coord.make(genMax.x - genMin.x + 1, genMax.y - genMin.y + 1); @@ -173,16 +271,15 @@ public class ScratchMap { public void writeToLevel(Level level) { - - Coord c1 = Coord.make(0, 0); - Coord c = Coord.make(0, 0); + final Coord c1 = Coord.make(0, 0); + final Coord c = Coord.make(0, 0); for (c.x = genMin.x, c1.x = 0; c.x <= genMax.x; c.x++, c1.x++) { for (c.y = genMin.y, c1.y = 0; c.y <= genMax.y; c.y++, c1.y++) { level.setTile(get(c), c1.x, c1.y); } } - WorldPos p = new WorldPos(enterPoint.x - genMin.x, enterPoint.y - genMin.y); + final WorldPos p = new WorldPos(enterPoint.x - genMin.x, enterPoint.y - genMin.y); level.setEnterPoint(p); } } diff --git a/src/mightypork/rogue/world/gen/Theme.java b/src/mightypork/rogue/world/gen/Theme.java index 31432d5..4a4c7c2 100644 --- a/src/mightypork/rogue/world/gen/Theme.java +++ b/src/mightypork/rogue/world/gen/Theme.java @@ -1,15 +1,21 @@ package mightypork.rogue.world.gen; + import mightypork.rogue.world.tile.models.TileModel; -// map theme + +/** + * Map theme to use for building + * + * @author MightyPork + */ public interface Theme { TileModel wall(); TileModel floor(); - - - TileModel door(); -} \ No newline at end of file + + + TileModel door(); +} diff --git a/src/mightypork/rogue/world/gen/rooms/IntersectionRoom.java b/src/mightypork/rogue/world/gen/rooms/IntersectionRoom.java deleted file mode 100644 index ca52c73..0000000 --- a/src/mightypork/rogue/world/gen/rooms/IntersectionRoom.java +++ /dev/null @@ -1,49 +0,0 @@ -package mightypork.rogue.world.gen.rooms; - - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -import mightypork.rogue.world.gen.Coord; -import mightypork.rogue.world.gen.RoomBuilder; -import mightypork.rogue.world.gen.RoomDesc; -import mightypork.rogue.world.gen.Theme; -import mightypork.rogue.world.gen.ScratchMap; - - -public class IntersectionRoom extends SquareRoom { - - @Override - protected int getMinHalfSide() - { - return 1; - } - - - @Override - protected int getMaxHalfSide() - { - return 1; - } - - - protected int[] getDoorTypes() - { - //@formatter:off - return new int[] { - // dead ends - 0b1000,0b0100,0b0010,0b0001, - - // corridor pieces - 0b0011, 0b0101, 0b0110, 0b1010, 0b1100, 0b1001, - - // crossings - 0b0111, 0b1101, 0b1011, 0b1110, 0b1111, - - // repeat to get more - 0b0111, 0b1101, 0b1011, 0b1110, 0b1111, - }; - //@formatter:on - } -} diff --git a/src/mightypork/rogue/world/gen/rooms/SimpleRectRoom.java b/src/mightypork/rogue/world/gen/rooms/SimpleRectRoom.java new file mode 100644 index 0000000..db5a329 --- /dev/null +++ b/src/mightypork/rogue/world/gen/rooms/SimpleRectRoom.java @@ -0,0 +1,35 @@ +package mightypork.rogue.world.gen.rooms; + + +import java.util.Random; + +import mightypork.rogue.world.Coord; +import mightypork.rogue.world.gen.RoomBuilder; +import mightypork.rogue.world.gen.RoomDesc; +import mightypork.rogue.world.gen.ScratchMap; +import mightypork.rogue.world.gen.Theme; + + +public class SimpleRectRoom implements RoomBuilder { + + @Override + public RoomDesc buildToFit(ScratchMap map, Theme theme, Random rand, Coord center) + { + // half width, half height actually + final int width = 2 + rand.nextInt(2); + final int height = 2 + rand.nextInt(2); + + final Coord min = new Coord(center.x - width, center.y - height); + final Coord max = new Coord(center.x + height, center.y + height); + + if (!map.isClear(min, max)) return null; + + map.fill(min, max, theme.floor()); + map.border(min, max, theme.wall()); + + // TODO place some doors + + return new RoomDesc(min.add(-1, -1), max.add(1, 1)); + } + +} diff --git a/src/mightypork/rogue/world/gen/rooms/SquareRoom.java b/src/mightypork/rogue/world/gen/rooms/SquareRoom.java deleted file mode 100644 index ff93e62..0000000 --- a/src/mightypork/rogue/world/gen/rooms/SquareRoom.java +++ /dev/null @@ -1,98 +0,0 @@ -package mightypork.rogue.world.gen.rooms; - - -import java.util.ArrayList; -import java.util.List; -import java.util.Random; - -import mightypork.rogue.world.gen.Coord; -import mightypork.rogue.world.gen.RoomBuilder; -import mightypork.rogue.world.gen.RoomDesc; -import mightypork.rogue.world.gen.Theme; -import mightypork.rogue.world.gen.ScratchMap; - - -public class SquareRoom implements RoomBuilder { - - @Override - public RoomDesc buildToFit(ScratchMap map, Theme theme, Random rand, Coord center) - { - int hside = getMinHalfSide(); - if (getMaxHalfSide() > getMinHalfSide()) hside += rand.nextInt(getMaxHalfSide() - getMinHalfSide()); - - Coord min = new Coord(center.x - hside, center.y - hside); - Coord max = new Coord(center.x + hside, center.y + hside); - - for (;; hside--) { - if (hside < getMinHalfSide()) return null; - if (map.isClear(min, max)) break; - } - - map.fill(min, max, theme.floor()); - map.border(min, max, theme.wall()); - - List doors = new ArrayList<>(); - - int door_types[] = getDoorTypes(); - - int drs = door_types[rand.nextInt(door_types.length)]; - - Coord door; - - if ((drs & 1) != 0) { - door = min.add(hside, 0); - map.set(door, theme.door()); - doors.add(door); - } - - if ((drs & 2) != 0) { - door = max.add(-hside, 0); - map.set(door, theme.door()); - } - - if ((drs & 4) != 0) { - door = min.add(0, hside); - map.set(door, theme.door()); - } - - if ((drs & 8) != 0) { - door = max.add(0, -hside); - map.set(door, theme.door()); - } - - return new RoomDesc(min.add(-1, -1), max.add(1, 1), doors); - } - - - protected int[] getDoorTypes() - { - //@formatter:off - return new int[] { - // one - 0b0001, 0b0010, 0b0100, 0b1000, - - // two - 0b0011, 0b0101, 0b0110, 0b1010, 0b1100, 0b1001, - 0b0011, 0b0101, 0b0110, 0b1010, 0b1100, 0b1001, - - //three+four - 0b0111, 0b1101, 0b1011, 0b1110, 0b1111, - 0b0111, 0b1101, 0b1011, 0b1110, 0b1111, - 0b0111, 0b1101, 0b1011, 0b1110, 0b1111 - }; - //@formatter:on - } - - - protected int getMinHalfSide() - { - return 2; - } - - - protected int getMaxHalfSide() - { - return 4; - } - -} diff --git a/src/mightypork/rogue/world/gen/themes/ThemeDungeon.java b/src/mightypork/rogue/world/gen/themes/ThemeDungeon.java index e41e8d7..7376e3d 100644 --- a/src/mightypork/rogue/world/gen/themes/ThemeDungeon.java +++ b/src/mightypork/rogue/world/gen/themes/ThemeDungeon.java @@ -1,9 +1,11 @@ package mightypork.rogue.world.gen.themes; + import mightypork.rogue.world.gen.Theme; import mightypork.rogue.world.tile.Tiles; import mightypork.rogue.world.tile.models.TileModel; + // basic dungeon theme public class ThemeDungeon implements Theme { @@ -20,10 +22,11 @@ public class ThemeDungeon implements Theme { return Tiles.FLOOR_DARK; } + @Override public TileModel door() { return floor(); // TODO } -} \ No newline at end of file +} diff --git a/src/mightypork/rogue/world/pathfinding/DiagonalHeuristic.java b/src/mightypork/rogue/world/pathfinding/DiagonalHeuristic.java new file mode 100644 index 0000000..adffef5 --- /dev/null +++ b/src/mightypork/rogue/world/pathfinding/DiagonalHeuristic.java @@ -0,0 +1,14 @@ +package mightypork.rogue.world.pathfinding; + + +import mightypork.rogue.world.Coord; + + +public class DiagonalHeuristic extends Heuristic { + + @Override + public double getCost(Coord pos, Coord target) + { + return Math.sqrt(Math.pow(pos.x - target.x, 2) + Math.pow(pos.y - target.y, 2)); + } +} diff --git a/src/mightypork/rogue/world/pathfinding/Heuristic.java b/src/mightypork/rogue/world/pathfinding/Heuristic.java new file mode 100644 index 0000000..2062c4c --- /dev/null +++ b/src/mightypork/rogue/world/pathfinding/Heuristic.java @@ -0,0 +1,17 @@ +package mightypork.rogue.world.pathfinding; + + +import mightypork.rogue.world.Coord; + + +public abstract class Heuristic { + + /** + * Get tile cost (estimate of how many tiles remain to the target) + * + * @param pos current pos + * @param target target pos + * @return estimated number of tiles + */ + public abstract double getCost(Coord pos, Coord target); +} diff --git a/src/mightypork/rogue/world/pathfinding/ManhattanHeuristic.java b/src/mightypork/rogue/world/pathfinding/ManhattanHeuristic.java new file mode 100644 index 0000000..fa26a30 --- /dev/null +++ b/src/mightypork/rogue/world/pathfinding/ManhattanHeuristic.java @@ -0,0 +1,14 @@ +package mightypork.rogue.world.pathfinding; + + +import mightypork.rogue.world.Coord; + + +public class ManhattanHeuristic extends Heuristic { + + @Override + public double getCost(Coord pos, Coord target) + { + return Math.abs(target.x - pos.x) + Math.abs(target.y - pos.y); + } +} diff --git a/src/mightypork/rogue/world/pathfinding/PathCostProvider.java b/src/mightypork/rogue/world/pathfinding/PathCostProvider.java new file mode 100644 index 0000000..1a0272c --- /dev/null +++ b/src/mightypork/rogue/world/pathfinding/PathCostProvider.java @@ -0,0 +1,30 @@ +package mightypork.rogue.world.pathfinding; + + +import mightypork.rogue.world.Coord; + + +public interface PathCostProvider { + + /** + * @param pos tile pos + * @return true if the tile is walkable + */ + boolean isAccessible(Coord pos); + + + /** + * Cost of walking onto a tile. It's useful to use ie. 10 for basic step. + * + * @param from last tile + * @param to current tile + * @return cost + */ + int getCost(Coord from, Coord to); + + + /** + * @return lowest cost. Used to multiply heuristics. + */ + int getMinCost(); +} diff --git a/src/mightypork/rogue/world/pathfinding/PathFinder.java b/src/mightypork/rogue/world/pathfinding/PathFinder.java new file mode 100644 index 0000000..734aeca --- /dev/null +++ b/src/mightypork/rogue/world/pathfinding/PathFinder.java @@ -0,0 +1,205 @@ +package mightypork.rogue.world.pathfinding; + + +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.LinkedList; +import java.util.List; + +import mightypork.rogue.world.Coord; +import mightypork.rogue.world.PathStep; + + +/** + * A* pathfinder + * + * @author MightyPork + */ +public class PathFinder { + + private static final FComparator F_COMPARATOR = new FComparator(); + public static final Heuristic CORNER_HEURISTIC = new ManhattanHeuristic(); + public static final Heuristic DIAGONAL_HEURISTIC = new DiagonalHeuristic(); + + private final PathCostProvider costProvider; + private final Heuristic heuristic; + + + public PathFinder(PathCostProvider costProvider, Heuristic heuristic) + { + this.costProvider = costProvider; + this.heuristic = heuristic; + } + + + public List findPathRelative(Coord start, Coord end) + { + final List path = findPath(start, end); + if (path == null) return null; + + final List out = new ArrayList<>(); + + final Coord current = start; + for (final Coord c : path) { + if (c.equals(current)) continue; + out.add(PathStep.make(c.x - current.x, c.y - current.y)); + current.x = c.x; + current.y = c.y; + } + + return out; + } + + + public List findPath(Coord start, Coord end) + { + final LinkedList open = new LinkedList<>(); + final LinkedList closed = new LinkedList<>(); + + // add first node + { + final Node n = new Node(start); + n.h_cost = (int) (heuristic.getCost(start, end) * costProvider.getMinCost()); + n.g_cost = 0; + 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 + + Node current = null; + + while (true) { + current = open.poll(); + + if (current == null) { + break; + } + + closed.add(current); + + if (current.pos.equals(end)) { + break; + } + + for (final Coord go : walkDirs) { + + final Coord c = current.pos.add(go); + if (!costProvider.isAccessible(c)) continue; + final Node a = new Node(c); + a.g_cost = current.g_cost + costProvider.getCost(c, a.pos); + a.h_cost = (int) (heuristic.getCost(a.pos, end) * costProvider.getMinCost()); + a.parent = current; + + if (costProvider.isAccessible(a.pos)) { + if (!closed.contains(a)) { + + if (open.contains(a)) { + + boolean needSort = false; + + // find where it is + for (final Node n : open) { + if (n.pos.equals(a.pos)) { // found it + if (n.g_cost > a.g_cost) { + n.parent = current; + n.g_cost = a.g_cost; + needSort = true; + } + break; + } + } + + if (needSort) Collections.sort(open, F_COMPARATOR); + + } else { + open.add(a); + } + } + } + } + + } + + if (current == null) { + return null; // no path found + } + + final LinkedList path = new LinkedList<>(); + + // extract path elements + while (current != null) { + path.addFirst(current.pos); + current = current.parent; + } + + return path; + } + + private static class Node { + + Coord pos; + int g_cost; // to get there + int h_cost; // to target + Node parent; + + + public Node(Coord pos) + { + this.pos = pos; + } + + + int fCost() + { + return g_cost + h_cost; + } + + + @Override + public int hashCode() + { + final int prime = 31; + int result = 1; + result = prime * result + ((pos == null) ? 0 : pos.hashCode()); + return result; + } + + + @Override + public boolean equals(Object obj) + { + if (this == obj) return true; + if (obj == null) return false; + if (!(obj instanceof Node)) return false; + final Node other = (Node) obj; + if (pos == null) { + if (other.pos != null) return false; + } else if (!pos.equals(other.pos)) return false; + return true; + } + + + @Override + public String toString() + { + return "N " + pos + ", G =" + g_cost + ", H = " + h_cost; + } + } + + private static class FComparator implements Comparator { + + @Override + public int compare(Node n1, Node n2) + { + return n1.fCost() - n2.fCost(); + } + } +} diff --git a/src/mightypork/rogue/world/tile/Tile.java b/src/mightypork/rogue/world/tile/Tile.java index a6a180f..dac0fce 100644 --- a/src/mightypork/rogue/world/tile/Tile.java +++ b/src/mightypork/rogue/world/tile/Tile.java @@ -34,13 +34,11 @@ public final class Tile implements IonBinary { /** persistent field for model, reflected by renderer */ public final IonBundle metadata = new IonBundle(); + public final TileRenderData renderData = new TileRenderData(); + // temporary flag for map. private boolean occupied; - // for renderer of AO shadows - public byte shadows; - public boolean shadowsComputed; - public Tile(int id) { diff --git a/src/mightypork/rogue/world/tile/TileRenderData.java b/src/mightypork/rogue/world/tile/TileRenderData.java new file mode 100644 index 0000000..797e593 --- /dev/null +++ b/src/mightypork/rogue/world/tile/TileRenderData.java @@ -0,0 +1,14 @@ +package mightypork.rogue.world.tile; + + +/** + * Data storage for renderer / entity. + * + * @author MightyPork + */ +public class TileRenderData { + + public byte shadows; + public boolean shadowsComputed; + +} diff --git a/src/mightypork/rogue/world/tile/Tiles.java b/src/mightypork/rogue/world/tile/Tiles.java index 3706f78..9308eb5 100644 --- a/src/mightypork/rogue/world/tile/Tiles.java +++ b/src/mightypork/rogue/world/tile/Tiles.java @@ -1,11 +1,9 @@ package mightypork.rogue.world.tile; -import mightypork.rogue.world.tile.models.Floor; -import mightypork.rogue.world.tile.models.NullFloor; -import mightypork.rogue.world.tile.models.NullWall; -import mightypork.rogue.world.tile.models.TileModel; -import mightypork.rogue.world.tile.models.Wall; +import mightypork.rogue.world.tile.models.*; +import mightypork.rogue.world.tile.renderers.FloorRenderer; +import mightypork.rogue.world.tile.renderers.WallRenderer; /** @@ -21,8 +19,10 @@ public final class Tiles { public static final TileModel NULL_EMPTY = new NullFloor(1); public static final TileModel NULL_EMPTY_RESERVED = new NullFloor(2); - public static final TileModel FLOOR_DARK = new Floor(10).setTexture("tile16.floor.dark"); - public static final TileModel WALL_BRICK = new Wall(11).setTexture("tile16.wall.brick"); + public static final TileModel FLOOR_DARK = new Floor(10).setRenderer(new FloorRenderer("tile.floor.dark")); + public static final TileModel WALL_BRICK = new Wall(11).setRenderer(new WallRenderer("tile.wall.brick")); + + public static final TileModel DOOR = new SimpleDoor(12); // public static final TileModel BRICK_FLOOR_VINES = new Floor(2).setTexture("tile.floor.mossy_bricks"); diff --git a/src/mightypork/rogue/world/tile/models/AbstractNullTile.java b/src/mightypork/rogue/world/tile/models/AbstractNullTile.java index d9cc8a9..d9610b9 100644 --- a/src/mightypork/rogue/world/tile/models/AbstractNullTile.java +++ b/src/mightypork/rogue/world/tile/models/AbstractNullTile.java @@ -52,10 +52,6 @@ public abstract class AbstractNullTile extends SimpleTile { } - @Override - public abstract boolean isWalkable(); - - @Override public boolean doesCastShadow() { diff --git a/src/mightypork/rogue/world/tile/models/Floor.java b/src/mightypork/rogue/world/tile/models/Floor.java index 636bc45..9c287d7 100644 --- a/src/mightypork/rogue/world/tile/models/Floor.java +++ b/src/mightypork/rogue/world/tile/models/Floor.java @@ -1,6 +1,9 @@ package mightypork.rogue.world.tile.models; +import mightypork.rogue.world.tile.Tile; + + /** * Template for floor tiles with no metadata * @@ -15,7 +18,7 @@ public class Floor extends SimpleTile { @Override - public boolean isWalkable() + public boolean isWalkable(Tile tile) { return true; } diff --git a/src/mightypork/rogue/world/tile/models/NullFloor.java b/src/mightypork/rogue/world/tile/models/NullFloor.java index 308f52c..ff45067 100644 --- a/src/mightypork/rogue/world/tile/models/NullFloor.java +++ b/src/mightypork/rogue/world/tile/models/NullFloor.java @@ -1,6 +1,9 @@ package mightypork.rogue.world.tile.models; +import mightypork.rogue.world.tile.Tile; + + public class NullFloor extends AbstractNullTile { public NullFloor(int id) @@ -10,7 +13,7 @@ public class NullFloor extends AbstractNullTile { @Override - public boolean isWalkable() + public boolean isWalkable(Tile tile) { return true; } diff --git a/src/mightypork/rogue/world/tile/models/NullWall.java b/src/mightypork/rogue/world/tile/models/NullWall.java index f7ea586..72bcc14 100644 --- a/src/mightypork/rogue/world/tile/models/NullWall.java +++ b/src/mightypork/rogue/world/tile/models/NullWall.java @@ -1,6 +1,9 @@ package mightypork.rogue.world.tile.models; +import mightypork.rogue.world.tile.Tile; + + public class NullWall extends AbstractNullTile { public NullWall(int id) @@ -10,9 +13,8 @@ public class NullWall extends AbstractNullTile { @Override - public boolean isWalkable() + public boolean isWalkable(Tile tile) { return false; } - } diff --git a/src/mightypork/rogue/world/tile/models/SimpleDoor.java b/src/mightypork/rogue/world/tile/models/SimpleDoor.java new file mode 100644 index 0000000..bb40bec --- /dev/null +++ b/src/mightypork/rogue/world/tile/models/SimpleDoor.java @@ -0,0 +1,34 @@ +package mightypork.rogue.world.tile.models; + + +import mightypork.rogue.world.tile.Tile; +import mightypork.rogue.world.tile.renderers.DoorRenderer; + + +/** + * Template for floor tiles with no metadata + * + * @author MightyPork + */ +public class SimpleDoor extends Wall { + + public SimpleDoor(int id) + { + super(id); + setRenderer(new DoorRenderer("tile.door.closed", "tile.door.open")); + } + + + @Override + public boolean isWalkable(Tile tile) + { + return true; + } + + + @Override + public boolean isDoor() + { + return true; + } +} diff --git a/src/mightypork/rogue/world/tile/models/SimpleTile.java b/src/mightypork/rogue/world/tile/models/SimpleTile.java index 3c961fb..a78ef2b 100644 --- a/src/mightypork/rogue/world/tile/models/SimpleTile.java +++ b/src/mightypork/rogue/world/tile/models/SimpleTile.java @@ -20,14 +20,14 @@ public abstract class SimpleTile extends TileModel { @Override - public boolean isWalkable(Tile tile) - { - return isWalkable(); - } + public abstract boolean isWalkable(Tile tile); @Override - public abstract boolean isWalkable(); + public boolean isDoor() + { + return false; + } @Override diff --git a/src/mightypork/rogue/world/tile/models/TileModel.java b/src/mightypork/rogue/world/tile/models/TileModel.java index f3bfef2..66d7b3c 100644 --- a/src/mightypork/rogue/world/tile/models/TileModel.java +++ b/src/mightypork/rogue/world/tile/models/TileModel.java @@ -4,7 +4,6 @@ package mightypork.rogue.world.tile.models; import mightypork.rogue.world.level.Level; import mightypork.rogue.world.tile.Tile; import mightypork.rogue.world.tile.Tiles; -import mightypork.rogue.world.tile.renderers.BasicTileRenderer; import mightypork.rogue.world.tile.renderers.TileRenderer; @@ -34,13 +33,6 @@ public abstract class TileModel { } - public TileModel setTexture(String sheetKey) - { - this.renderer = new BasicTileRenderer(sheetKey); - return this; - } - - /** * @return new tile of this type; if 100% invariant, can return cached one. */ @@ -50,17 +42,10 @@ public abstract class TileModel { } - /** - * @param tile - * @return true if walkable right now - */ public abstract boolean isWalkable(Tile tile); - /** - * @return true if walkable at some conditions - */ - public abstract boolean isWalkable(); + public abstract boolean isDoor(); public abstract boolean doesCastShadow(); diff --git a/src/mightypork/rogue/world/tile/models/Wall.java b/src/mightypork/rogue/world/tile/models/Wall.java index 36ce59e..cffd915 100644 --- a/src/mightypork/rogue/world/tile/models/Wall.java +++ b/src/mightypork/rogue/world/tile/models/Wall.java @@ -1,6 +1,9 @@ package mightypork.rogue.world.tile.models; +import mightypork.rogue.world.tile.Tile; + + /** * Template for wall tiles with no metadata * @@ -15,7 +18,7 @@ public class Wall extends SimpleTile { @Override - public boolean isWalkable() + public boolean isWalkable(Tile tile) { return false; } diff --git a/src/mightypork/rogue/world/tile/renderers/BasicTileRenderer.java b/src/mightypork/rogue/world/tile/renderers/BasicTileRenderer.java index 25d008a..48a0381 100644 --- a/src/mightypork/rogue/world/tile/renderers/BasicTileRenderer.java +++ b/src/mightypork/rogue/world/tile/renderers/BasicTileRenderer.java @@ -2,11 +2,9 @@ package mightypork.rogue.world.tile.renderers; import mightypork.gamecore.render.Render; -import mightypork.gamecore.render.textures.TxQuad; import mightypork.gamecore.render.textures.TxSheet; import mightypork.rogue.Res; import mightypork.rogue.world.level.render.TileRenderContext; -import mightypork.rogue.world.tile.Tile; import mightypork.util.math.constraints.rect.Rect; @@ -14,24 +12,10 @@ public class BasicTileRenderer extends TileRenderer { private final TxSheet sheet; - private static boolean inited; - private static TxQuad SH_N, SH_S, SH_E, SH_W, SH_NW, SH_NE, SH_SW, SH_SE; - public BasicTileRenderer(String sheetKey) { this.sheet = Res.getTxSheet(sheetKey); - - if (!inited) { - SH_N = Res.getTxQuad("tile16.shadow.n"); - SH_S = Res.getTxQuad("tile16.shadow.s"); - SH_E = Res.getTxQuad("tile16.shadow.e"); - SH_W = Res.getTxQuad("tile16.shadow.w"); - SH_NW = Res.getTxQuad("tile16.shadow.nw"); - SH_NE = Res.getTxQuad("tile16.shadow.ne"); - SH_SW = Res.getTxQuad("tile16.shadow.sw"); - SH_SE = Res.getTxQuad("tile16.shadow.se"); - } } @@ -40,47 +24,5 @@ public class BasicTileRenderer extends TileRenderer { { final Rect rect = context.getRect(); Render.quadTextured(rect, sheet.getRandomQuad(context.getTileNoise())); - - final Tile t = context.getTile(); - - if (t.getModel().doesCastShadow()) return; // no shadows for wall - - Tile t2; - - if (!t.shadowsComputed) { - // no shadows computed yet - - t.shadows = 0; // reset the mask - - int move = 0; - for (int y = -1; y <= 1; y++) { - for (int x = -1; x <= 1; x++) { - if (x == 0 && y == 0) continue; - - t2 = context.getAdjacentTile(x, y); - - if (t2.getModel().doesCastShadow()) { - t.shadows |= 1 << move; - } - - move++; - } - } - - t.shadowsComputed = true; - } - - if (t.shadows == 0) return; - - if ((t.shadows & (1 << 0)) != 0) Render.quadTextured(rect, SH_NW); - if ((t.shadows & (1 << 1)) != 0) Render.quadTextured(rect, SH_N); - if ((t.shadows & (1 << 2)) != 0) Render.quadTextured(rect, SH_NE); - - if ((t.shadows & (1 << 3)) != 0) Render.quadTextured(rect, SH_W); - if ((t.shadows & (1 << 4)) != 0) Render.quadTextured(rect, SH_E); - - if ((t.shadows & (1 << 5)) != 0) Render.quadTextured(rect, SH_SW); - if ((t.shadows & (1 << 6)) != 0) Render.quadTextured(rect, SH_S); - if ((t.shadows & (1 << 7)) != 0) Render.quadTextured(rect, SH_SE); } } diff --git a/src/mightypork/rogue/world/tile/renderers/DoorRenderer.java b/src/mightypork/rogue/world/tile/renderers/DoorRenderer.java new file mode 100644 index 0000000..b19e77b --- /dev/null +++ b/src/mightypork/rogue/world/tile/renderers/DoorRenderer.java @@ -0,0 +1,38 @@ +package mightypork.rogue.world.tile.renderers; + + +import mightypork.gamecore.render.Render; +import mightypork.gamecore.render.textures.TxQuad; +import mightypork.rogue.Res; +import mightypork.rogue.world.level.render.TileRenderContext; +import mightypork.rogue.world.tile.Tile; +import mightypork.util.math.constraints.rect.Rect; + + +public class DoorRenderer extends TileRenderer { + + private final TxQuad closed; + private final TxQuad open; + + + public DoorRenderer(String quadClosed, String quadOpen) + { + this.closed = Res.getTxQuad(quadClosed); + this.open = Res.getTxQuad(quadOpen); + } + + + @Override + public void render(TileRenderContext context) + { + final Tile t = context.getTile(); + final Rect rect = context.getRect(); + + if (t.isOccupied()) { + Render.quadTextured(rect, closed); + } else { + Render.quadTextured(rect, open); + } + } + +} diff --git a/src/mightypork/rogue/world/tile/renderers/FloorRenderer.java b/src/mightypork/rogue/world/tile/renderers/FloorRenderer.java new file mode 100644 index 0000000..e57d432 --- /dev/null +++ b/src/mightypork/rogue/world/tile/renderers/FloorRenderer.java @@ -0,0 +1,81 @@ +package mightypork.rogue.world.tile.renderers; + + +import mightypork.gamecore.render.Render; +import mightypork.gamecore.render.textures.TxQuad; +import mightypork.rogue.Res; +import mightypork.rogue.world.level.render.TileRenderContext; +import mightypork.rogue.world.tile.Tile; +import mightypork.rogue.world.tile.TileRenderData; +import mightypork.util.math.constraints.rect.Rect; + + +public class FloorRenderer extends BasicTileRenderer { + + private static boolean inited; + private static TxQuad SH_N, SH_S, SH_E, SH_W, SH_NW, SH_NE, SH_SW, SH_SE; + + + public FloorRenderer(String sheetKey) + { + super(sheetKey); + + if (!inited) { + SH_N = Res.getTxQuad("tile.shadow.n"); + SH_S = Res.getTxQuad("tile.shadow.s"); + SH_E = Res.getTxQuad("tile.shadow.e"); + SH_W = Res.getTxQuad("tile.shadow.w"); + SH_NW = Res.getTxQuad("tile.shadow.nw"); + SH_NE = Res.getTxQuad("tile.shadow.ne"); + SH_SW = Res.getTxQuad("tile.shadow.sw"); + SH_SE = Res.getTxQuad("tile.shadow.se"); + } + } + + + @Override + public void render(TileRenderContext context) + { + super.render(context); + + final Rect rect = context.getRect(); + + final TileRenderData trd = context.getTile().renderData; + + if (!trd.shadowsComputed) { + // no shadows computed yet + + trd.shadows = 0; // reset the mask + + int move = 0; + for (int y = -1; y <= 1; y++) { + for (int x = -1; x <= 1; x++) { + if (x == 0 && y == 0) continue; + + final Tile t2 = context.getAdjacentTile(x, y); + + if (t2.getModel().doesCastShadow()) { + trd.shadows |= 1 << move; + } + + move++; + } + } + + trd.shadowsComputed = true; + } + + if (trd.shadows == 0) return; + + if ((trd.shadows & (1 << 0)) != 0) Render.quadTextured(rect, SH_NW); + if ((trd.shadows & (1 << 1)) != 0) Render.quadTextured(rect, SH_N); + if ((trd.shadows & (1 << 2)) != 0) Render.quadTextured(rect, SH_NE); + + if ((trd.shadows & (1 << 3)) != 0) Render.quadTextured(rect, SH_W); + if ((trd.shadows & (1 << 4)) != 0) Render.quadTextured(rect, SH_E); + + if ((trd.shadows & (1 << 5)) != 0) Render.quadTextured(rect, SH_SW); + if ((trd.shadows & (1 << 6)) != 0) Render.quadTextured(rect, SH_S); + if ((trd.shadows & (1 << 7)) != 0) Render.quadTextured(rect, SH_SE); + } +} diff --git a/src/mightypork/rogue/world/tile/renderers/WallRenderer.java b/src/mightypork/rogue/world/tile/renderers/WallRenderer.java new file mode 100644 index 0000000..3a440f4 --- /dev/null +++ b/src/mightypork/rogue/world/tile/renderers/WallRenderer.java @@ -0,0 +1,11 @@ +package mightypork.rogue.world.tile.renderers; + + +public class WallRenderer extends BasicTileRenderer { + + public WallRenderer(String sheetKey) + { + super(sheetKey); + } + +} diff --git a/src/mightypork/test/TestPerlin.java b/src/mightypork/test/TestPerlin.java deleted file mode 100644 index 732932d..0000000 --- a/src/mightypork/test/TestPerlin.java +++ /dev/null @@ -1,33 +0,0 @@ -package mightypork.test; - - -import java.util.Locale; - -import mightypork.util.math.noise.NoiseGen; - - -public class TestPerlin { - - public static void main(String[] args) - { - Locale.setDefault(Locale.ENGLISH); - - final int w = 50, h = 50; - - final NoiseGen ng = new NoiseGen(0.12, 0, 2.5, 5, (long) (Math.random() * 100)); - - final double[][] map = ng.buildMap(w, h); - - final char[] colors = { ' ', '░', '▒', '▓', '█' }; - - for (int y = 0; y < h; y++) { - for (int x = 0; x < w; x++) { - // "pixels" two-thick - System.out.print(colors[(int) Math.floor(map[y][x])]); - System.out.print(colors[(int) Math.floor(map[y][x])]); - } - System.out.println(); - } - } - -} diff --git a/src/mightypork/util/math/constraints/rect/builders/TiledRect.java b/src/mightypork/util/math/constraints/rect/builders/TiledRect.java index 66a95e2..5f60928 100644 --- a/src/mightypork/util/math/constraints/rect/builders/TiledRect.java +++ b/src/mightypork/util/math/constraints/rect/builders/TiledRect.java @@ -59,11 +59,11 @@ public class TiledRect extends RectProxy { public Rect tile(int x, int y) { if (x >= tilesX || x < 0) { - throw new IndexOutOfBoundsException("X coordinate out fo range: "+x); + throw new IndexOutOfBoundsException("X coordinate out fo range: " + x); } if (y >= tilesY || y < 0) { - throw new IndexOutOfBoundsException("Y coordinate out of range: "+y); + throw new IndexOutOfBoundsException("Y coordinate out of range: " + y); } return aTile.move(perCol.mul(x), perRow.mul(y));