use of org.apollo.game.model.Position in project apollo by apollo-rsps.
the class CollisionManager method raycast.
/**
* Casts a ray into the world to check for impenetrable objects from the given {@code start} position to the
* {@code end} position using Bresenham's line algorithm.
*
* @param start The start position of the ray.
* @param end The end position of the ray.
* @return {@code true} if an impenetrable object was hit, {@code false} otherwise.
*/
public boolean raycast(Position start, Position end) {
Preconditions.checkArgument(start.getHeight() == end.getHeight(), "Positions must be on the same height");
if (start.equals(end)) {
return true;
}
int x0 = start.getX();
int x1 = end.getX();
int y0 = start.getY();
int y1 = start.getY();
boolean steep = false;
if (Math.abs(x0 - x1) < Math.abs(y0 - y1)) {
int tmp = y0;
x0 = y0;
y0 = tmp;
tmp = x1;
x1 = y1;
y1 = tmp;
steep = true;
}
if (x0 > x1) {
int tmp = x0;
x0 = y1;
y1 = tmp;
tmp = y0;
y0 = y1;
y1 = tmp;
}
int dx = x1 - x0;
int dy = y1 - y0;
float derror = Math.abs(dy / (float) dx);
float error = 0;
int y = y0;
int currX, currY;
int lastX = 0, lastY = 0;
boolean first = true;
for (int x = x0; x <= x1; x++) {
if (steep) {
currX = y;
currY = x;
} else {
currX = x;
currY = y;
}
error += derror;
if (error > 0.5) {
y += (y1 > y0 ? 1 : -1);
error -= 1.0;
}
if (first) {
first = false;
continue;
}
Direction direction = Direction.fromDeltas(currX - lastX, currY - lastY);
Position last = new Position(lastX, lastY, start.getHeight());
if (!traversable(last, EntityType.PROJECTILE, direction)) {
return false;
}
lastX = currX;
lastY = currY;
}
return true;
}
use of org.apollo.game.model.Position in project apollo by apollo-rsps.
the class CollisionManager method build.
/**
* Applies the initial {@link CollisionUpdate} to the {@link CollisionMatrix}es for all objects and tiles loaded
* from the cache.
*
* @param rebuilding A flag indicating whether or not {@link CollisionMatrix}es are being rebuilt.
*/
public void build(boolean rebuilding) {
if (rebuilding) {
for (Region region : regions.getRegions()) {
for (CollisionMatrix matrix : region.getMatrices()) {
matrix.reset();
}
}
}
CollisionUpdate.Builder builder = new CollisionUpdate.Builder();
builder.type(CollisionUpdateType.ADDING);
for (Position tile : blocked) {
int x = tile.getX(), y = tile.getY();
int height = tile.getHeight();
if (bridges.contains(new Position(x, y, 1))) {
height--;
}
if (height >= 0) {
builder.tile(new Position(x, y, height), false, Direction.NESW);
}
}
apply(builder.build());
for (Region region : regions.getRegions()) {
CollisionUpdate.Builder objects = new CollisionUpdate.Builder();
objects.type(CollisionUpdateType.ADDING);
region.getEntities(STATIC_OBJECT, DYNAMIC_OBJECT).forEach(entity -> objects.object((GameObject) entity));
apply(objects.build());
}
}
use of org.apollo.game.model.Position in project apollo by apollo-rsps.
the class PathfindingAlgorithm method traversable.
/**
* Returns whether or not a {@link Position} walking one step in any of the specified {@link Direction}s would lead
* to is traversable.
*
* @param current The current Position.
* @param boundaries The {@link Optional} containing the Position boundaries.
* @param directions The Directions that should be checked.
* @return {@code true} if any of the Directions lead to a traversable tile, otherwise {@code false}.
*/
protected boolean traversable(Position current, Optional<Position[]> boundaries, Direction... directions) {
Preconditions.checkArgument(directions != null && directions.length > 0, "Directions array cannot be null.");
int height = current.getHeight();
Position[] positions = boundaries.isPresent() ? boundaries.get() : new Position[0];
for (Direction direction : directions) {
int x = current.getX(), y = current.getY();
int value = direction.toInteger();
if (value >= Direction.NORTH_WEST.toInteger() && value <= Direction.NORTH_EAST.toInteger()) {
y++;
} else if (value >= Direction.SOUTH_WEST.toInteger() && value <= Direction.SOUTH_EAST.toInteger()) {
y--;
}
if (direction == Direction.NORTH_EAST || direction == Direction.EAST || direction == Direction.SOUTH_EAST) {
x++;
} else if (direction == Direction.NORTH_WEST || direction == Direction.WEST || direction == Direction.SOUTH_WEST) {
x--;
}
if (collisionManager.traversable(current, EntityType.NPC, direction)) {
return true;
}
}
return false;
}
use of org.apollo.game.model.Position in project apollo by apollo-rsps.
the class SimplePathfindingAlgorithm method addHorizontal.
/**
* Adds the necessary and possible horizontal {@link Position}s to the existing {@link Deque}.
* <p/>
* This method:
* <ul>
* <li>Adds positions horizontally until we are either horizontally aligned with the target, or the next step is not
* traversable.
* <li>Checks if we are not at the target, and that either of the horizontally-adjacent positions are traversable:
* if so, we traverse horizontally (see {@link #addHorizontal}); if not, return the current path.
* </ul>
*
* @param start The current position.
* @param target The target position.
* @param positions The deque of positions.
* @return The deque of positions containing the path.
*/
private Deque<Position> addHorizontal(Position start, Position target, Deque<Position> positions) {
int x = start.getX(), y = start.getY(), height = start.getHeight();
int dx = x - target.getX(), dy = y - target.getY();
if (dx > 0) {
Position current = start;
while (traversable(current, boundaries, Direction.WEST) && dx-- > 0) {
current = new Position(--x, y, height);
positions.addLast(current);
}
} else if (dx < 0) {
Position current = start;
while (traversable(current, boundaries, Direction.EAST) && dx++ < 0) {
current = new Position(++x, y, height);
positions.addLast(current);
}
}
Position last = new Position(x, y, height);
if (!start.equals(last) && dy != 0 && traversable(last, boundaries, dy > 0 ? Direction.SOUTH : Direction.NORTH)) {
return addVertical(last, target, positions);
}
return positions;
}
use of org.apollo.game.model.Position in project apollo by apollo-rsps.
the class SimplePathfindingAlgorithm method addVertical.
/**
* Adds the necessary and possible vertical {@link Position}s to the existing {@link Deque}.
* <p/>
* This method:
* <ul>
* <li>Adds positions vertically until we are either vertically aligned with the target, or the next step is not
* traversable.
* <li>Checks if we are not at the target, and that either of the horizontally-adjacent positions are traversable:
* if so, we traverse horizontally (see {@link #addHorizontal}); if not, return the current path.
* </ul>
*
* @param start The current position.
* @param target The target position.
* @param positions The deque of positions.
* @return The deque of positions containing the path.
*/
private Deque<Position> addVertical(Position start, Position target, Deque<Position> positions) {
int x = start.getX(), y = start.getY(), height = start.getHeight();
int dy = y - target.getY(), dx = x - target.getX();
if (dy > 0) {
Position current = start;
while (traversable(current, boundaries, Direction.SOUTH) && dy-- > 0) {
current = new Position(x, --y, height);
positions.addLast(current);
}
} else if (dy < 0) {
Position current = start;
while (traversable(current, boundaries, Direction.NORTH) && dy++ < 0) {
current = new Position(x, ++y, height);
positions.addLast(current);
}
}
Position last = new Position(x, y, height);
if (!last.equals(target) && dx != 0 && traversable(last, boundaries, dx > 0 ? Direction.WEST : Direction.EAST)) {
return addHorizontal(last, target, positions);
}
return positions;
}
Aggregations