From 2bafbba1ad51742766dc3888b6bcfdf89f670ec7 Mon Sep 17 00:00:00 2001 From: Fabio Ticconi Date: Sat, 28 Oct 2017 13:30:31 +0200 Subject: [PATCH 1/5] upping minor snapshot version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 9af2b90..3e63d2b 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.github.fabioticconi rlforj-alt - 0.1.1 + 0.1.2-SNAPSHOT jar Roguelike Library For Java (Alternative version) From f93a365723931af335c689bb84056b105134bcd3 Mon Sep 17 00:00:00 2001 From: Fabio Ticconi Date: Mon, 6 Nov 2017 09:05:22 +0100 Subject: [PATCH 2/5] adding some basic documentation --- README.md | 162 +++++++++++++++++- .../{los/ILosBoard.java => IBoard.java} | 6 +- .../java/rlforj/examples/ExampleBoard.java | 4 +- src/main/java/rlforj/los/BresLos.java | 15 +- .../java/rlforj/los/BresOpportunisticLos.java | 13 +- .../java/rlforj/los/ConePrecisePremisive.java | 17 +- .../java/rlforj/los/IConeFovAlgorithm.java | 6 +- src/main/java/rlforj/los/IFovAlgorithm.java | 4 +- src/main/java/rlforj/los/ILosAlgorithm.java | 9 +- .../java/rlforj/los/PrecisePermissive.java | 30 ++-- .../rlforj/los/RecordQuadrantVisitBoard.java | 7 +- src/main/java/rlforj/los/ShadowCasting.java | 41 ++--- .../los/raymulticast/MultiRaysCaster.java | 8 +- src/main/java/rlforj/pathfinding/AStar.java | 14 +- src/test/java/rlforj/los/test/TestBoard.java | 4 +- .../rlforj/pathfinding/test/MockBoard.java | 4 +- src/test/java/rlforj/util/test/MockBoard.java | 4 +- 17 files changed, 255 insertions(+), 93 deletions(-) rename src/main/java/rlforj/{los/ILosBoard.java => IBoard.java} (95%) diff --git a/README.md b/README.md index 494d529..f7627c9 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -rlforj-alt -========= +# rlforj-alt +[![Latest Github release](https://img.shields.io/github/release/fabioticconi/rlforj-alt.svg)](https://github.com/fabioticconi/rlforj-alt/releases/latest) [![Build Status](https://travis-ci.org/fabioticconi/rlforj-alt.svg?branch=master)](https://travis-ci.org/fabioticconi/rlforj-alt) Roguelike Library For Java (Alternative version). @@ -15,16 +15,15 @@ the development of roguelikes and other games: no obstacles between them. It's useful for ranged attacks, for example. * **Pathfinding**: given a map, we want to find the optimal, nonlinear path between a start and end points. This - may also take account of the terrain, to give preference to paths avoiding slow-moving terrains for example. + may also take account of the terrain, to give preference to paths avoiding slow-moving terrains, for example. Some terrain generation utilities will also be available in the future. -Installation ------------- +## Install 1. First add Jitpack as a repository inside your pom.xml -```$xslt +```$xml jitpack.io @@ -36,7 +35,7 @@ Installation 2. Then add `rlforj-alt` as a dependency (make sure to change `version` to one of the [releases](https://github.com/fabioticconi/rlforj-alt/releases)): -```$xslt +```$xml com.github.fabioticconi rlforj-alt @@ -44,6 +43,155 @@ Installation ``` +## Use + +The main component of rlforj-alt is the so called `Board`. You must implement the [IBoard](src/main/java/rlforj/IBoard.java) +interface before doing anything: + +```$java +public interface IBoard +{ + boolean contains(int x, int y); + + boolean blocksLight(int x, int y); + + boolean blocksStep(int x, int y); + + void visit(int x, int y); +} +``` + +* `contains` should check boundaries of your map/level + +* `blocksLight` should return true for all positions that block vision (eg, walls). Used by Fov/Los algorithms + +* `blocksStep` should return true for all positions that block movement. Used by pathfinding algorithms + +* `visit` will be called by the Fov/Los algorithms on each visible cell. You may + use it to store the visible cells or to manipulate the map, or whatever you wish. See below for details on how it's + used. + +### Field of View + +To explore all the visible cells (what is generally called `Field of View`) you must choose one of the available +Fov algorithms implementing the [IFovAlgorithm](src/main/java/rlforj/los/IFovAlgorithm.java) interface: + +```$java +public interface IFovAlgorithm +{ + void visitFieldOfView(IBoard b, int x, int y, int distance); +} +``` + +Then you can use it like this: + +```$java +IBoard map = new MyMap(); + +// choose one of these +IFovAlgorithm a = new ShadowCasting(); +IFovAlgorithm a = new PrecisePermissive(); + +// visit all visible cells from the origin and up the given radius +a.visitFieldOfView(map, originX, originY, radius); +``` + +The method `IFovAlgorithm#visitFieldOfView` is guaranteed to call `IBoard#visit` **only once**, and always before +`IBoard#blocksLight`. This last thing is important for things like a bomb or fireball: whatever blocking cell the +Fov algorithm encounters, it's destroyed in the `FireballBoard#visit` - and thus the Fov will continue to visit surrounding +cells that were previously shadowed by this cell. + +`IBoard#blocksLight` and `IBoard#blocksStep` can be called multiple times at each location. + +### Conic Field of View + +In alternative to the above, if you want to only visit a **conic field of view** (eg, for breathing fire, or to simulate a +directional light), you can choose one of the algorithms implementing the [IConeFovAlgorithm](src/main/java/rlforj/los/IConeFovAlgorithm.java) +interface: + +```$java +public interface IConeFovAlgorithm +{ + void visitConeFieldOfView(IBoard b, int x, int y, int distance, int startAngle, int endAngle); +} +``` + +Then you can use it like this: + +```$java +IBoard map = new MyMap(); + +// choose one of these +IConeFovAlgorithm a = new ShadowCasting(); +IConeFovAlgorithm a = new ConePrecisePermissive(); + +// visit all visible cells from the origin and up the given radius, in a cone of 180 degrees +a.visitConeFieldOfView(map, originX, originY, radius, 0, 180); +``` + +### Line of Sight + +To find a straight, unobstructed line between a start and end point is a task called `Line of Sight`. This is very +useful for ranged attacks. + +rlforj-alt supports many Los algorithms, all implementing the [ILosAlgorithm](src/main/java/rlforj/los/ILosAlgorithm.java) +interface: + +```$java +public interface ILosAlgorithm +{ + boolean existsLineOfSight(IBoard b, int startX, int startY, int endX, int endY, boolean calculateProject); + + List getProjectPath(); +} + +``` + +If you only need to **test** for line of sight, set the last argument, `calculateProject`, to `false`. + +More commonly, you will need the path (if one exists), so do this: + +```$java +IBoard map = new MyMap(); + +// choose one of these +ILosAlgorithm a = new BresLos(symmetric); // symmetric can be true or false +ILosAlgorithm a = new BresOpportunisticLos(); +ILosAlgorithm a = new ShadowCasting(); +ILosAlgorithm a = new PrecisePermissive(); + +List path; +if (a.existsLineOfSight(map, startX, startY, endX, endY, true)) + path = a.getProjectPath(); +else + // do something else? +``` + +Note that if a line of sight cannot be established, the path will be `null`. + +If `path` is not `null`, it always includes the start and end point. + +### Pathfinding + +Pathfinding is the task of finding an unobstructed path from a start to an end point. Contrarily to Los, +the path does not need to be a line. + +Only one algorithm is supported for now, the king of pathfinding in games: AStar. Use it like this: + +```$java +IBoard map = new MyMap(); + +// choose one of these +diag = true; // true if you allow diagonal movement, false otherwise +AStar a = new AStar(map, map.width(), map.height(), diag); + +radius = -1; // this will search the whole board - it can be very expensive to do so! +radius = 10; // this will only search the cells in a radius of 10 cells from the starting point +Point[] path = a.findPath(startX, startY, endX, endY, radius) +``` + +If `path` is not `null`, it always includes the start and end point. + Disclaimer --------- diff --git a/src/main/java/rlforj/los/ILosBoard.java b/src/main/java/rlforj/IBoard.java similarity index 95% rename from src/main/java/rlforj/los/ILosBoard.java rename to src/main/java/rlforj/IBoard.java index bdd124f..34cae19 100644 --- a/src/main/java/rlforj/los/ILosBoard.java +++ b/src/main/java/rlforj/IBoard.java @@ -1,5 +1,7 @@ -package rlforj.los; +package rlforj; +import rlforj.los.IFovAlgorithm; +import rlforj.los.ILosAlgorithm; import rlforj.pathfinding.AStar; /** @@ -10,7 +12,7 @@ * * @author sdatta */ -public interface ILosBoard +public interface IBoard { /** * Is the location (x, y) inside the board ? diff --git a/src/main/java/rlforj/examples/ExampleBoard.java b/src/main/java/rlforj/examples/ExampleBoard.java index fc9c97c..f2fcbba 100644 --- a/src/main/java/rlforj/examples/ExampleBoard.java +++ b/src/main/java/rlforj/examples/ExampleBoard.java @@ -1,12 +1,12 @@ package rlforj.examples; -import rlforj.los.ILosBoard; +import rlforj.IBoard; import rlforj.math.Point; import java.util.HashMap; import java.util.Map; -public class ExampleBoard implements ILosBoard +public class ExampleBoard implements IBoard { public char visibleFloor = '.', invisibleFloor = ' ', invisibleWall = ' '; diff --git a/src/main/java/rlforj/los/BresLos.java b/src/main/java/rlforj/los/BresLos.java index 90c6be8..0cff28e 100644 --- a/src/main/java/rlforj/los/BresLos.java +++ b/src/main/java/rlforj/los/BresLos.java @@ -1,5 +1,6 @@ package rlforj.los; +import rlforj.IBoard; import rlforj.math.Point; import rlforj.util.BresenhamLine; @@ -27,10 +28,10 @@ public BresLos(final boolean symmetric) symmetricEnabled = symmetric; } - public boolean existsLineOfSight(final ILosBoard b, final int startX, final int startY, final int x1, final int y1, final boolean calculateProject) + public boolean existsLineOfSight(final IBoard b, final int startX, final int startY, final int endX, final int endY, final boolean calculateProject) { - final int dx = startX - x1; - final int dy = startY - y1; + final int dx = startX - endX; + final int dy = startY - endY; final int adx = dx > 0 ? dx : -dx; final int ady = dy > 0 ? dy : -dy; final int len = (adx > ady ? adx : ady) + 1;//Max number of points on the path. @@ -43,7 +44,7 @@ public boolean existsLineOfSight(final ILosBoard b, final int startX, final int final int[] py = new int[len]; //Start to finish path - BresenhamLine.plot(startX, startY, x1, y1, px, py); + BresenhamLine.plot(startX, startY, endX, endY, px, py); boolean los = false; for (int i = 0; i < len; i++) @@ -52,7 +53,7 @@ public boolean existsLineOfSight(final ILosBoard b, final int startX, final int { path.add(new Point(px[i], py[i])); } - if (px[i] == x1 && py[i] == y1) + if (px[i] == endX && py[i] == endY) { los = true; break; @@ -69,7 +70,7 @@ public boolean existsLineOfSight(final ILosBoard b, final int startX, final int px1 = new int[len]; py1 = new int[len]; // finish to start path. - BresenhamLine.plot(x1, y1, startX, startY, px1, py1); + BresenhamLine.plot(endX, endY, startX, startY, px1, py1); final Vector oldpath = path; path = new Vector<>(len); @@ -79,7 +80,7 @@ public boolean existsLineOfSight(final ILosBoard b, final int startX, final int { path.add(new Point(px1[i], py1[i])); } - if (px1[i] == x1 && py1[i] == y1) + if (px1[i] == endX && py1[i] == endY) { los = true; break; diff --git a/src/main/java/rlforj/los/BresOpportunisticLos.java b/src/main/java/rlforj/los/BresOpportunisticLos.java index 48aa404..a4300fe 100644 --- a/src/main/java/rlforj/los/BresOpportunisticLos.java +++ b/src/main/java/rlforj/los/BresOpportunisticLos.java @@ -1,5 +1,6 @@ package rlforj.los; +import rlforj.IBoard; import rlforj.math.Point; import rlforj.util.BresenhamLine; @@ -20,10 +21,10 @@ public class BresOpportunisticLos implements ILosAlgorithm private Vector path; - public boolean existsLineOfSight(final ILosBoard b, final int startX, final int startY, final int x1, final int y1, final boolean calculateProject) + public boolean existsLineOfSight(final IBoard b, final int startX, final int startY, final int endX, final int endY, final boolean calculateProject) { - final int dx = startX - x1; - final int dy = startY - y1; + final int dx = startX - endX; + final int dy = startY - endY; final int adx = dx > 0 ? dx : -dx; final int ady = dy > 0 ? dy : -dy; final int len = (adx > ady ? adx : ady) + 1; @@ -38,15 +39,15 @@ public boolean existsLineOfSight(final ILosBoard b, final int startX, final int py1 = new int[len]; //Compute both paths - BresenhamLine.plot(startX, startY, x1, y1, px, py); - BresenhamLine.plot(x1, y1, startX, startY, px1, py1); + BresenhamLine.plot(startX, startY, endX, endY, px, py); + BresenhamLine.plot(endX, endY, startX, startY, px1, py1); boolean los = false; boolean alternatePath = false; for (int i = 0; i < len; i++) { // Have we reached the end ? In that case quit - if (px[i] == x1 && py[i] == y1) + if (px[i] == endX && py[i] == endY) { if (calculateProject) { diff --git a/src/main/java/rlforj/los/ConePrecisePremisive.java b/src/main/java/rlforj/los/ConePrecisePremisive.java index 809909b..e9804c2 100644 --- a/src/main/java/rlforj/los/ConePrecisePremisive.java +++ b/src/main/java/rlforj/los/ConePrecisePremisive.java @@ -1,5 +1,6 @@ package rlforj.los; +import rlforj.IBoard; import rlforj.math.Point; import java.util.LinkedList; @@ -13,8 +14,8 @@ public class ConePrecisePremisive extends PrecisePermissive implements IConeFovAlgorithm { - public void visitConeFieldOfView(final ILosBoard b, final int x, final int y, final int distance, int startAngle, - int finishAngle) + public void visitConeFieldOfView(final IBoard b, final int x, final int y, final int distance, int startAngle, + int endAngle) { if (startAngle % 90 == 0 && startAngle % 360 != 0) startAngle--;//we dont like to start at 90, 180, 270 @@ -26,16 +27,16 @@ public void visitConeFieldOfView(final ILosBoard b, final int x, final int y, fi startAngle %= 360; startAngle += 360; } - if (finishAngle < 0) + if (endAngle < 0) { - finishAngle %= 360; - finishAngle += 360; + endAngle %= 360; + endAngle += 360; } if (startAngle > 360) startAngle %= 360; - if (finishAngle > 360) - finishAngle %= 360; + if (endAngle > 360) + endAngle %= 360; final permissiveMaskT mask = new permissiveMaskT(); mask.east = mask.north = mask.south = mask.west = distance; @@ -43,7 +44,7 @@ public void visitConeFieldOfView(final ILosBoard b, final int x, final int y, fi mask.fovType = FovType.CIRCLE; mask.distPlusOneSq = (distance + 1) * (distance + 1); mask.board = b; - permissiveConeFov(x, y, mask, startAngle, finishAngle); + permissiveConeFov(x, y, mask, startAngle, endAngle); } /** diff --git a/src/main/java/rlforj/los/IConeFovAlgorithm.java b/src/main/java/rlforj/los/IConeFovAlgorithm.java index 9ace8dd..d5d3bfd 100644 --- a/src/main/java/rlforj/los/IConeFovAlgorithm.java +++ b/src/main/java/rlforj/los/IConeFovAlgorithm.java @@ -1,5 +1,7 @@ package rlforj.los; +import rlforj.IBoard; + /** * FOV along a cone. Give starting and finish angle. * Note: Positive Y axis is down. @@ -18,7 +20,7 @@ public interface IConeFovAlgorithm extends IFovAlgorithm * @param y y position * @param distance maximum distance of cone of view * @param startAngle start angle - * @param finishAngle end angle + * @param endAngle end angle */ - void visitConeFieldOfView(ILosBoard b, int x, int y, int distance, int startAngle, int finishAngle); + void visitConeFieldOfView(IBoard b, int x, int y, int distance, int startAngle, int endAngle); } diff --git a/src/main/java/rlforj/los/IFovAlgorithm.java b/src/main/java/rlforj/los/IFovAlgorithm.java index c34f095..272e309 100644 --- a/src/main/java/rlforj/los/IFovAlgorithm.java +++ b/src/main/java/rlforj/los/IFovAlgorithm.java @@ -1,5 +1,7 @@ package rlforj.los; +import rlforj.IBoard; + /** * An interface for FOV algorithms. * @@ -25,6 +27,6 @@ public interface IFovAlgorithm * @param y Starting location:y * @param distance How far can this Field of View go */ - void visitFieldOfView(ILosBoard b, int x, int y, int distance); + void visitFieldOfView(IBoard b, int x, int y, int distance); } diff --git a/src/main/java/rlforj/los/ILosAlgorithm.java b/src/main/java/rlforj/los/ILosAlgorithm.java index 33a95f2..f493141 100644 --- a/src/main/java/rlforj/los/ILosAlgorithm.java +++ b/src/main/java/rlforj/los/ILosAlgorithm.java @@ -1,5 +1,6 @@ package rlforj.los; +import rlforj.IBoard; import rlforj.math.Point; import java.util.List; @@ -14,18 +15,18 @@ public interface ILosAlgorithm /** * Calculates if line of sight exists between point startX, startY and - * x1, y1. Optionally calculate the path of projection. + * endX, y1. Optionally calculate the path of projection. * * @param b The board to be visited. * @param startX Starting position:x * @param startY Starting position:y - * @param x1 Target location:x - * @param y1 Target location:y + * @param endX Target location:x + * @param endY Target location:y * @param calculateProject Whether to also calculate the path from the * source to the target. * @return true if a line of sight could be established */ - boolean existsLineOfSight(ILosBoard b, int startX, int startY, int x1, int y1, boolean calculateProject); + boolean existsLineOfSight(IBoard b, int startX, int startY, int endX, int endY, boolean calculateProject); /** * Obtain the path of the projection calculated during the last call diff --git a/src/main/java/rlforj/los/PrecisePermissive.java b/src/main/java/rlforj/los/PrecisePermissive.java index a67cf74..3ef1540 100644 --- a/src/main/java/rlforj/los/PrecisePermissive.java +++ b/src/main/java/rlforj/los/PrecisePermissive.java @@ -1,5 +1,6 @@ package rlforj.los; +import rlforj.IBoard; import rlforj.math.Line2I; import rlforj.math.Point; @@ -320,7 +321,7 @@ else if (mask.fovType == FovType.CIRCLE) return 1; } - public void visitFieldOfView(final ILosBoard b, final int x, final int y, final int distance) + public void visitFieldOfView(final IBoard b, final int x, final int y, final int distance) { final permissiveMaskT mask = new permissiveMaskT(); mask.east = mask.north = mask.south = mask.west = distance; @@ -335,17 +336,18 @@ public void visitFieldOfView(final ILosBoard b, final int x, final int y, final * Algorithm inspired by * http://groups.google.com/group/rec.games.roguelike.development/browse_thread/thread/f3506215be9d9f9a/2e543127f705a278#2e543127f705a278 * - * @see rlforj.los.ILosAlgorithm#existsLineOfSight(rlforj.los.ILosBoard, int, int, int, int, boolean) + * @see rlforj.los.ILosAlgorithm#existsLineOfSight(IBoard, int, int, int, int, boolean) */ - public boolean existsLineOfSight(final ILosBoard b, final int startX, final int startY, final int x1, final int y1, + public boolean existsLineOfSight(final IBoard b, final int startX, final int startY, final int endX, final int endY, final boolean calculateProject) { final permissiveMaskT mask = new permissiveMaskT(); - final int dx = x1 - startX; + final int dx = endX - startX; final int adx = dx > 0 ? dx : -dx; - final int dy = y1 - startY; + final int dy = endY - startY; final int ady = dy > 0 ? dy : -dy; - final RecordQuadrantVisitBoard fb = new RecordQuadrantVisitBoard(b, startX, startY, x1, y1, calculateProject); + final RecordQuadrantVisitBoard fb = new RecordQuadrantVisitBoard(b, startX, startY, endX, + endY, calculateProject); mask.east = mask.west = adx; mask.north = mask.south = ady; mask.mask = null; @@ -435,10 +437,10 @@ public boolean existsLineOfSight(final ILosBoard b, final int startX, final int if (calculateProject) { if (fb.endVisited) - path = GenericCalculateProjection.calculateProjecton(startX, startY, x1, y1, fb); + path = GenericCalculateProjection.calculateProjecton(startX, startY, endX, endY, fb); else { - fallBackLos.existsLineOfSight(b, startX, startY, x1, y1, true); + fallBackLos.existsLineOfSight(b, startX, startY, endX, endY, true); path = (Vector) fallBackLos.getProjectPath(); } // calculateProjecton(startX, startY, adx, ady, fb, state); @@ -464,13 +466,13 @@ class permissiveMaskT * Do not interact with the members directly. Use the provided * functions. */ int north; - int south; - int east; - int west; + int south; + int east; + int west; // int width; // int height; - int[] mask; - ILosBoard board; + int[] mask; + IBoard board; } class fovStateT @@ -482,7 +484,7 @@ class fovStateT Object context; Point quadrant; Point extent; - ILosBoard board; + IBoard board; } class bumpT diff --git a/src/main/java/rlforj/los/RecordQuadrantVisitBoard.java b/src/main/java/rlforj/los/RecordQuadrantVisitBoard.java index fc1d938..4b95931 100644 --- a/src/main/java/rlforj/los/RecordQuadrantVisitBoard.java +++ b/src/main/java/rlforj/los/RecordQuadrantVisitBoard.java @@ -1,5 +1,6 @@ package rlforj.los; +import rlforj.IBoard; import rlforj.math.Point; import java.util.HashSet; @@ -11,9 +12,9 @@ * * @author sdatta */ -public class RecordQuadrantVisitBoard implements ILosBoard, GenericCalculateProjection.VisitedBoard +public class RecordQuadrantVisitBoard implements IBoard, GenericCalculateProjection.VisitedBoard { - ILosBoard b; + IBoard b; int sx, sy, sxy; @@ -27,7 +28,7 @@ public class RecordQuadrantVisitBoard implements ILosBoard, GenericCalculateProj boolean calculateProject; private final Point visitedCheck = new Point(0, 0); - public RecordQuadrantVisitBoard(final ILosBoard b, final int sx, final int sy, final int dx, final int dy, final boolean calculateProject) + public RecordQuadrantVisitBoard(final IBoard b, final int sx, final int sy, final int dx, final int dy, final boolean calculateProject) { super(); this.b = b; diff --git a/src/main/java/rlforj/los/ShadowCasting.java b/src/main/java/rlforj/los/ShadowCasting.java index 6fe1b72..b01b356 100644 --- a/src/main/java/rlforj/los/ShadowCasting.java +++ b/src/main/java/rlforj/los/ShadowCasting.java @@ -1,5 +1,6 @@ package rlforj.los; +import rlforj.IBoard; import rlforj.math.Point; import java.util.*; @@ -57,7 +58,7 @@ public class ShadowCasting implements IConeFovAlgorithm, ILosAlgorithm BresLos fallBackLos = new BresLos(true); private Vector path; - static void go(final ILosBoard board, final Point ctr, final int r, final int maxDistance, double th1, final double th2) + static void go(final IBoard board, final Point ctr, final int r, final int maxDistance, double th1, final double th2) { if (r > maxDistance) throw new IllegalArgumentException(); @@ -177,7 +178,7 @@ else if (foundClear) * Compute and return the list of RLPoints in line-of-sight to the given * region. In general, this method should be very fast. */ - public void visitFieldOfView(final ILosBoard b, final int x, final int y, final int distance) + public void visitFieldOfView(final IBoard b, final int x, final int y, final int distance) { if (b == null) throw new IllegalArgumentException(); @@ -204,10 +205,10 @@ public void visitFieldOfView(final ILosBoard b, final int x, final int y, final // return points; } - public boolean existsLineOfSight(final ILosBoard b, final int startX, final int startY, final int x1, final int y1, final boolean calculateProject) + public boolean existsLineOfSight(final IBoard b, final int startX, final int startY, final int endX, final int endY, final boolean calculateProject) { - final int dx = x1 - startX; - final int dy = y1 - startY; + final int dx = endX - startX; + final int dy = endY - startY; final int signX, signY; final int adx, ady; @@ -231,11 +232,11 @@ public boolean existsLineOfSight(final ILosBoard b, final int startX, final int ady = -dy; signY = -1; } - final RecordQuadrantVisitBoard fb = new RecordQuadrantVisitBoard(b, startX, startY, x1, y1, calculateProject); + final RecordQuadrantVisitBoard fb = new RecordQuadrantVisitBoard(b, startX, startY, endX, endY, calculateProject); final Point p = new Point(startX, startY); - if (startY == y1 && x1 > startX) + if (startY == endY && endX > startX) { final int distance = dx + 1; final double deg1 = Math.toDegrees(Math.atan2(.25, dx));//very thin angle @@ -268,10 +269,10 @@ public boolean existsLineOfSight(final ILosBoard b, final int startX, final int if (calculateProject) { if (fb.endVisited) - path = GenericCalculateProjection.calculateProjecton(startX, startY, x1, y1, fb); + path = GenericCalculateProjection.calculateProjecton(startX, startY, endX, endY, fb); else { - fallBackLos.existsLineOfSight(b, startX, startY, x1, y1, true); + fallBackLos.existsLineOfSight(b, startX, startY, endX, endY, true); path = (Vector) fallBackLos.getProjectPath(); } // calculateProjecton(startX, startY, adx, ady, fb, state); @@ -284,28 +285,28 @@ public List getProjectPath() return path; } - public void visitConeFieldOfView(final ILosBoard b, final int x, final int y, final int distance, int startAngle, int finishAngle) + public void visitConeFieldOfView(final IBoard b, final int x, final int y, final int distance, int startAngle, int endAngle) { // Making Positive Y downwards final int tmp = startAngle; - startAngle = -finishAngle; - finishAngle = -tmp; + startAngle = -endAngle; + endAngle = -tmp; if (startAngle < 0) { startAngle %= 360; startAngle += 360; } - if (finishAngle < 0) + if (endAngle < 0) { - finishAngle %= 360; - finishAngle += 360; + endAngle %= 360; + endAngle += 360; } if (startAngle > 360) startAngle %= 360; - if (finishAngle > 360) - finishAngle %= 360; + if (endAngle > 360) + endAngle %= 360; // System.out.println(startAngle+" "+finishAngle); if (b == null) @@ -315,13 +316,13 @@ public void visitConeFieldOfView(final ILosBoard b, final int x, final int y, fi final Point p = new Point(x, y); b.visit(x, y); - if (startAngle > finishAngle) + if (startAngle > endAngle) { go(b, p, 1, distance, startAngle, 359.999); - go(b, p, 1, distance, 0.0, finishAngle); + go(b, p, 1, distance, 0.0, endAngle); } else - go(b, p, 1, distance, startAngle, finishAngle); + go(b, p, 1, distance, startAngle, endAngle); } static class ArcPoint implements Comparable diff --git a/src/main/java/rlforj/los/raymulticast/MultiRaysCaster.java b/src/main/java/rlforj/los/raymulticast/MultiRaysCaster.java index 29a2cdb..ea7bedb 100644 --- a/src/main/java/rlforj/los/raymulticast/MultiRaysCaster.java +++ b/src/main/java/rlforj/los/raymulticast/MultiRaysCaster.java @@ -1,7 +1,7 @@ package rlforj.los.raymulticast; import rlforj.los.IFovAlgorithm; -import rlforj.los.ILosBoard; +import rlforj.IBoard; import rlforj.math.Point; import java.util.LinkedList; @@ -26,7 +26,7 @@ public class MultiRaysCaster implements IFovAlgorithm { - private ILosBoard world; // holds obstruction data + private IBoard world; // holds obstruction data private Point origin; // the point at which the rays will be // cast from private Point offset; // offset for storing in results @@ -34,7 +34,7 @@ public class MultiRaysCaster implements IFovAlgorithm private RayData[][] results; // stores calculated data for external use private int dsq; - public MultiRaysCaster(final ILosBoard world, final int originX, final int originY, final int radius) + public MultiRaysCaster(final IBoard world, final int originX, final int originY, final int radius) { this.world = world; this.origin = new Point(originX, originY); @@ -51,7 +51,7 @@ public MultiRaysCaster() } @Override - public void visitFieldOfView(final ILosBoard b, final int x, final int y, final int distance) + public void visitFieldOfView(final IBoard b, final int x, final int y, final int distance) { this.world = b; this.origin = new Point(x, y); diff --git a/src/main/java/rlforj/pathfinding/AStar.java b/src/main/java/rlforj/pathfinding/AStar.java index 2639378..855131d 100644 --- a/src/main/java/rlforj/pathfinding/AStar.java +++ b/src/main/java/rlforj/pathfinding/AStar.java @@ -1,6 +1,6 @@ package rlforj.pathfinding; -import rlforj.los.ILosBoard; +import rlforj.IBoard; import rlforj.math.Point; import rlforj.util.HeapNode; import rlforj.util.SimpleHeap; @@ -9,17 +9,17 @@ public class AStar { - private final ILosBoard map; - private final int boardWidth; - private final int boardHeight; - private final boolean allowDiagonal; + private final IBoard map; + private final int boardWidth; + private final int boardHeight; + private final boolean allowDiagonal; - public AStar(final ILosBoard map, final int boardWidth, final int boardHeight) + public AStar(final IBoard map, final int boardWidth, final int boardHeight) { this(map, boardWidth, boardHeight, true); } - public AStar(final ILosBoard map, final int boardWidth, final int boardHeight, final boolean allowDiagonal) + public AStar(final IBoard map, final int boardWidth, final int boardHeight, final boolean allowDiagonal) { this.map = map; this.boardWidth = boardWidth; diff --git a/src/test/java/rlforj/los/test/TestBoard.java b/src/test/java/rlforj/los/test/TestBoard.java index be1636b..933f7e9 100644 --- a/src/test/java/rlforj/los/test/TestBoard.java +++ b/src/test/java/rlforj/los/test/TestBoard.java @@ -1,6 +1,6 @@ package rlforj.los.test; -import rlforj.los.ILosBoard; +import rlforj.IBoard; import rlforj.math.Point; import java.util.HashMap; @@ -8,7 +8,7 @@ import java.util.Map; import java.util.Set; -public class TestBoard implements ILosBoard +public class TestBoard implements IBoard { public boolean def; // true => obstacle diff --git a/src/test/java/rlforj/pathfinding/test/MockBoard.java b/src/test/java/rlforj/pathfinding/test/MockBoard.java index fcd61f5..9a6db7e 100644 --- a/src/test/java/rlforj/pathfinding/test/MockBoard.java +++ b/src/test/java/rlforj/pathfinding/test/MockBoard.java @@ -1,13 +1,13 @@ package rlforj.pathfinding.test; -import rlforj.los.ILosBoard; +import rlforj.IBoard; /** * A simple board for testing LOS, Pathfinding, etc * * @author vic */ -class MockBoard implements ILosBoard +class MockBoard implements IBoard { private final boolean[][] obstacle; diff --git a/src/test/java/rlforj/util/test/MockBoard.java b/src/test/java/rlforj/util/test/MockBoard.java index 81f0107..de280cc 100644 --- a/src/test/java/rlforj/util/test/MockBoard.java +++ b/src/test/java/rlforj/util/test/MockBoard.java @@ -1,13 +1,13 @@ package rlforj.util.test; -import rlforj.los.ILosBoard; +import rlforj.IBoard; /** * A simple board for testing LOS, Pathfinding, etc * * @author vic */ -class MockBoard implements ILosBoard +class MockBoard implements IBoard { private final boolean[][] obstacle; From 38e0a1f5e00177d935f7c7388ebe15fc5fe2fb47 Mon Sep 17 00:00:00 2001 From: Fabio Ticconi Date: Mon, 6 Nov 2017 09:25:19 +0100 Subject: [PATCH 3/5] adding also the demo --- README.md | 223 ++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 223 insertions(+) diff --git a/README.md b/README.md index f7627c9..25f8804 100644 --- a/README.md +++ b/README.md @@ -192,6 +192,229 @@ Point[] path = a.findPath(startX, startY, endX, endY, radius) If `path` is not `null`, it always includes the start and end point. +## Examples + +### Fov ShadowCasting + +``` + .. ..... ... + ... ..... ... + .... .... # ... + ......... .... # + .........#... ... + ......#...#.. .... + ........... ..... + ........#...# + .....#.......#..... + .........@......... + .........#......... + ......... ..#...... + #.....##. ... .... + .#... #. ... .. + .... .. ... + .. . ... + . .. ... + .. ... + . .. +``` + +### Fov PrecisePermissive + +``` + .... .. + ..... ... + ....... #..... + ....... ..... . + ........#.... ... + ......#...#.. ..... + #........... ..... + . .........#...# . + .....#.......#..... + .........@......... + .........#......... + ......... ..#...... + #.....##. ... ..... + .#... #. .... ... + ... .. .#... . + . .. .#.... + .. #..#... + .. . . + ... . +``` + +### Conic Fov ShadowCasting + +30 degrees to 70 degrees + +``` + @ + .... + .... + ...... + ......# + ....... + .....#.. + ........ + ....... + #....#. +``` + +### Conic Fov PrecisePermissive + +``` + @ + ... + ..... + ........ + ......# + ....... + .....# + ....... + ...... + ##... + # +``` + +### Los Shadowcasting + +Los exists: + +``` +.......#............. +......###.#.......... +..................... +..............#...... +..#......##.......... +...........#......... +................#.... +..................... +...............#..... +..................... +#.....----@.......... +..*#|/.......#.....#. +..................... +..................... +..............#...... +........#............ +..............#...... +...#..#.......#...... +##................... +..............#..#... +.#.....#.......#..... +``` + +### Los PrecisePermissive + +Los exists: + +``` +.......#............. +......###.#.......... +..................... +..............#...... +..#......##.......... +...........#......... +................#.... +..................... +...............#..... +..................... +#.....----@.......... +..*#|/.......#.....#. +..................... +..................... +..............#...... +........#............ +..............#...... +...#..#.......#...... +##................... +..............#..#... +.#.....#.......#..... +``` + +### Los Bresenham + +Los does not exist: + +``` +.......#............. +......###.#.......... +..................... +..............#...... +..#......##.......... +...........#......... +................#.... +..................... +...............#..... +..................... +#......---@.......... +..?---/......#.....#. +..................... +..................... +..............#...... +........#............ +..............#...... +...#..#.......#...... +##................... +..............#..#... +.#.....#.......#..... +``` + +### Los Symmetric Bresenham + +Los does not exist: + +``` +.......#............. +......###.#.......... +..................... +..............#...... +..#......##.......... +...........#......... +................#.... +..................... +...............#..... +..................... +#.....----@.......... +..?--/.......#.....#. +..................... +..................... +..............#...... +........#............ +..............#...... +...#..#.......#...... +##................... +..............#..#... +.#.....#.......#..... +``` + +### Los Opportunistic Bresenham + +Los does not exist: + +``` +.......#............. +......###.#.......... +..................... +..............#...... +..#......##.......... +...........#......... +................#.... +..................... +...............#..... +..................... +#......---@.......... +..?---/......#.....#. +..................... +..................... +..............#...... +........#............ +..............#...... +...#..#.......#...... +##................... +..............#..#... +.#.....#.......#..... +``` + Disclaimer --------- From bb171793f404fbd7332afd165f10d829ef8a55ab Mon Sep 17 00:00:00 2001 From: Fabio Ticconi Date: Mon, 6 Nov 2017 09:43:10 +0100 Subject: [PATCH 4/5] made shadowcasting use a circle fov, although line of sight algorithms are still all squared --- README.md | 38 ++++++++++----------- src/main/java/rlforj/los/ShadowCasting.java | 3 +- src/main/java/rlforj/math/Point.java | 13 +++++++ 3 files changed, 34 insertions(+), 20 deletions(-) diff --git a/README.md b/README.md index 25f8804..67e99c8 100644 --- a/README.md +++ b/README.md @@ -197,25 +197,25 @@ If `path` is not `null`, it always includes the start and end point. ### Fov ShadowCasting ``` - .. ..... ... - ... ..... ... - .... .... # ... - ......... .... # - .........#... ... - ......#...#.. .... - ........... ..... - ........#...# - .....#.......#..... - .........@......... - .........#......... - ......... ..#...... - #.....##. ... .... - .#... #. ... .. - .... .. ... - .. . ... - . .. ... - .. ... - . .. + .#...... + ......... + ........... + .......... + ......... + ........ + ... ...... ... + ...... ....##..... + #.....#.......... + #....@......... + ................... + ................... + ....#...#.....#.#.. + #. ..#...#...... + .. .. . ..#.... + . ... # ....... + #. ... ... + .. .... + .... ``` ### Fov PrecisePermissive diff --git a/src/main/java/rlforj/los/ShadowCasting.java b/src/main/java/rlforj/los/ShadowCasting.java index b01b356..afe2ac8 100644 --- a/src/main/java/rlforj/los/ShadowCasting.java +++ b/src/main/java/rlforj/los/ShadowCasting.java @@ -33,7 +33,8 @@ public class ShadowCasting implements IConeFovAlgorithm, ILosAlgorithm { for (int j = -radius; j <= radius; j++) { - final int distance = (int) floor(origin.distance(i, j)); + // final int distance = (int) floor(origin.distance(i, j)); + final int distance = origin.distance2(i, j); // If filled, add anything where floor(distance) <= radius // If not filled, require that floor(distance) == radius diff --git a/src/main/java/rlforj/math/Point.java b/src/main/java/rlforj/math/Point.java index 506931c..518fa9e 100644 --- a/src/main/java/rlforj/math/Point.java +++ b/src/main/java/rlforj/math/Point.java @@ -31,6 +31,19 @@ public int distance(final int x, final int y) return Math.max(Math.abs(this.x - x), Math.abs(this.y - y)); } + public int distance2(final Point p) + { + return distance2(p.x, p.y); + } + + public int distance2(final int x, final int y) + { + final float dx = this.x - x; + final float dy = this.y - y; + + return (int) Math.floor(Math.sqrt(dx*dx + dy*dy)); + } + @Override public boolean equals(final Object o) { From 91fa5941449bd157e48933366a83cb23718dff1f Mon Sep 17 00:00:00 2001 From: Fabio Ticconi Date: Mon, 6 Nov 2017 09:45:09 +0100 Subject: [PATCH 5/5] upping version since we changed the contract a bit --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3e63d2b..f5736ac 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.github.fabioticconi rlforj-alt - 0.1.2-SNAPSHOT + 0.2.0 jar Roguelike Library For Java (Alternative version)