# NAME

Game::RaycastFOV - raycast field-of-view and related routines

# SYNOPSIS

```
use Game::RaycastFOV qw(bypair circle line);
bypair( { my ($x,$y) = @_; ... } $x1, $y1, $x2, $y2, ...);
# Bresenham in XS
circle( { my ($cx,$cy) = @_; ... } $x, $y, $radius);
line( { my ($lx,$ly) = @_; ... } $x0, $y0, $x1, $y1);
raycast( \&circle, sub { ... }, $x, $y, ...);
# alternative (faster, slower) circle constructions
cached_circle( { my ($cx,$cy) ... } $x, $y, $radius)
swing_circle( { my ($cx,$cy) ... } $x, $y, $radius, $swing);
```

# DESCRIPTION

This module contains various subroutines for fast integer calculation of lines and circles (and a slow one, too) that help perform Field Of View (FOV) calculations to show what cells are visible from a given cell via raycasting out from that cell. Raycasting visits adjacent squares lots especially as the FOV grows so will benefit from caching and more closed-in than open level layouts.

## Raycast Explained in One Thousand Words or Less

```
.#.##
.##.##### #
#.##..##... #.
.##.#.##.#... #.
#####..#.#### # #.
.#.#.#.###.##.. #.#.##
####....#.##... #....#
##...#.@#....## #.@#
#..#.###....#.# ###..
.##.#####..#... #..
.##...####.## ##.#
....#.###.#.. .
###.###.#..
.######.#
....#
```

# FUNCTIONS

**bypair***callback**...*-
Utility function for slicing up an arbitrary list pairwise. Sort of like

`pairwise`

of List::Util only in a void context, and that returning the value`-1`

from the*callback*subroutine will abort the processing of subsequent items in the input list. **bypairall***callback**...*-
Like

**bypair**but does not include code to abort processing the list. Since v1.01. **cached_circle***callback**x**y**radius*-
This routine looks up the

*radius*in the`%circle_points`

variable (which can be modified by users of this module) to obtain a pre-computed list of circle points that are fed to the*callback*as is done for the**circle**call.Will silently do nothing if the

*radius*is not found in the cache. This is by design so that**cached_circle**is fast.NOTE these cached points may change without notice; applications should if necessary set their own specific sets of points to use.

**circle***callback**x**y**radius*-
Bresenham circle via fast integer math. Note that this may not produce a completely filled-in FOV at various radius. Also note that this call will produce duplicate values for various points, especially for small

*radius*. **line***callback**x0**y0**x1**y1*-
Bresenham line via fast integer math. Returning the value

`-1`

from the*callback*subroutine will abort the processing of the line at the given point. **raycast***circle-fn**point-fn**x**y**...*-
Given a

*circle-fn*such as**circle**or**swing_circle**, the**raycast**calls**line**between*x*and*y*and the points returned by the circle function;**line**in turn will call the user-supplied**point-fn**to handle what should happen at each raycasted point. Additional arguments*...*will be passed to the*circle-fn*following*x*and*y*(the center of the circle. "EXAMPLES" may be of more help? **shadowcast***x**y**radius**blockcb**litcb**radiuscb*-
Performs a shadow cast FOV calculation of the given

*radius*around the point*x*,*y*. The*blockcb*is called with*nx*,*ny*and should determine whether that coordinate is blocked on the level map. The*litcb*is also called with coordinates and should indicate that that cell is visible.The

*radius*callback is given the*deltax*,*deltay*, and*radius*and should return true if the deltas are within the radious. This allows for different FOV shapes.The callbacks may be called with points outside of the level map. The

*radius*callback delta values may be negative so may need to be run through`abs`

or`** 2`

to determine the distance. **swing_circle***callback**x0**y0**radius**swing*-
Constructs points around the given

*radius*by rotating a ray by*swing*radians over a complete circle. Smaller*swing*values will result in a more complete circle at the cost of additional CPU and memory use.**cached_circle**uses values pre-computed from this call but only for specific*radius*.

# EXAMPLES

See also the `eg/`

directory of this module's distribution.

https://github.com/thrig/ministry-of-silly-vaults/ has a FOV subdirectory with example scripts.

```
use Game::RaycastFOV qw(circle raycast swing_circle);
use Math::Trig 'deg2rad';
# to only draw within the map area
our $MAX_X = 79;
our $MAX_Y = 23;
# assuming a rows/columns array-of-arrays with characters
our @map = ( ... );
sub plot { ... }
my ($x, $y, $radius) = ...;
raycast(
\&circle, sub {
my ($lx, $ly) = @_;
# whoops line has wandered outside of map
return -1 if $lx < 0 or $lx > $MAX_X
or $ly < 0 or $ly > $MAX_Y;
# may instead build up a string to print to terminal
my $ch = $map[$ly][$lx];
plot($lx, $ly, $ch);
# abort the line if FOV is blocked
return -1 if $ch eq '#';
}, $x, $y, $radius
);
# or instead using swing_circle
raycast(
\&swing_circle, sub {
my ($lx, $ly) = @_;
return -1 if $lx < 0 or $lx > $MAX_X
or $ly < 0 or $ly > $MAX_Y;
my $ch = $map[$ly][$lx];
plot($lx, $ly, $ch);
return -1 if $ch eq '#';
}, $x, $y, $radius, deg2rad(5) # different arguments!
);
```

The **plot** routine should cache whether something has been printed to the given cell to avoid repeated terminal or display updates.

# BUGS

or patches might best be applied towards

https://github.com/thrig/Game-RaycastFOV

# SEE ALSO

Game::Xomb uses a modified version of this module's raycast code to provide FOV.

https://github.com/thrig/ministry-of-silly-vaults/

There are other FOV algorithms and implementations to be found on the Internet.

# AUTHOR

thrig - Jeremy Mates (cpan:JMATES) `<jeremy.mates at gmail.com>`

# COPYRIGHT AND LICENSE

This software is Copyright (c) 2020 by Jeremy Mates.

This is free software, licensed under:

` The (three-clause) BSD License`