Roguelike Library For Java (Alternative version).
The main aim of this library is to provide a set of simple, yet efficient, algorithms for common problems in the development of roguelikes and other games:
-
FoV: the field of view is the area around a game entity that is visible. Commonly, things like walls and trees block vision. This is provided in both circular and conic format.
-
LoS: the line of sight is a linear path from a starting position to a target position, provided there 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.
Some terrain generation utilities will also be available in the future.
- First add Jitpack as a repository inside your pom.xml
<repositories>
<repository>
<id>jitpack.io</id>
<url>https://jitpack.io</url>
</repository>
</repositories>
- Then add
rlforj-alt
as a dependency (make sure to changeversion
to one of the releases):
<dependency>
<groupId>com.github.fabio-t</groupId>
<artifactId>rlforj-alt</artifactId>
<version>version</version>
</dependency>
The main component of rlforj-alt is the so called Board
. You must implement the IBoard
interface before doing anything:
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.
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 interface:
public interface IFovAlgorithm
{
void visitFov(IBoard b, int x, int y, int distance);
}
Then you can use it like this:
IBoard map = new MyMap();
// choose one of these
IFovAlgorithm a = new ShadowCasting();
IFovAlgorithm a = new PrecisePermissive();
// calls IBoard#visit on all visible cells from the origin and up to the given radius
a.visitFov(map, originX, originY, radius);
The method IFovAlgorithm#visitFov
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.
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 interface:
public interface IConeFovAlgorithm
{
void visitConeFov(IBoard b, int x, int y, int distance, int startAngle, int endAngle);
}
Then you can use it like this:
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.visitConeFov(map, originX, originY, radius, 0, 180);
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 interface:
public interface ILosAlgorithm
{
boolean exists(IBoard b, int startX, int startY, int endX, int endY, boolean savePath);
List<Point> getPath();
}
If you only need to test for line of sight, set the last argument, savePath
, to false
.
More commonly, you will need the path (if one exists), so do this:
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<Point> path;
if (a.exists(map, startX, startY, endX, endY, true))
path = a.getPath();
else
// do something else?
Example of line of sight path:
...##...........#
.................
#...........#..*#
###...#......./..
............./...
..........#/-....
#........./......
........#/..#....
....#...@..#.....
........#........
.......#...#.....
...#......#......
...#..#......#...
#.........#......
...#.#...........
...#.............
.............#...
If you are unsure which Los algorithm to use, consider this:
-
If you need absolute certainty that if a point is in your Field of View, then is also in your Line of Sight, then use the same algorithm,
ShadowCasting
orPrecisePermissive
, for Los too -
If you need faster and prettier Line of Sight, then choose one of the
Bresenham
. We advise you to useBresLos(true)
, eg symmetric Bresenham, unless you have a reason not to -
all algorithms return the same or very similar paths in "good" cases, but may vary wildly in more complicated ones
A final note: 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 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: AStar. Use it like this:
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.
Let's see some of the algorithms in action. If you wish to run them yourself, have a look at the examples folder.
.#...
...... .
. ..... ...
...#...##....
...........
#.........
#.@......
............
.............
..#.#....#.#.
...##...# .
# .....
.....
.#...
...... .
. ..... ...
...#...##....
............
#.........
#.@......
.............
.............
..#.#....#.#.
..##...# .
# .....
.....
@
....
....
......
......#
.......
.....#..
........
.......
#....#.
@
...
.....
........
......#
.......
.....#
.......
......
##...
#
This was originally a fork from kba/rlforj (version 3.0), but has since diverged. See the LICENSE file for copyright information.