Giter Club home page Giter Club logo

wally-fov's Introduction

WallyFOV

Dependencies Node.js CI License

Shadow-casting field-of-view algorithm with support for walls

See the demo, and check out the successor to this algorithm: WarpField, which supports portals.

Installation

npm install wally-fov

Usage

Create a map:

const WallyFOV = require('wally-fov');

const width = 5;
const height = 5;
const fovMap = new WallyFOV.FieldOfViewMap(width, height);

Add some walls and bodies:

fovMap.addWall(1, 1, WallyFOV.CardinalDirection.NORTH);
fovMap.addWall(1, 1, WallyFOV.CardinalDirection.WEST);
fovMap.addWall(2, 0, WallyFOV.CardinalDirection.SOUTH);
fovMap.addBody(2, 3);
fovMap.addBody(0, 4);
fovMap.addWall(2, 2, WallyFOV.CardinalDirection.EAST);
// keep the map up-to-date if a wall or body is removed:
fovMap.removeWall(1, 1, WallyFOV.CardinalDirection.NORTH);
fovMap.removeBody(0, 4);

Compute the field of view:

const playerX = 2;
const playerY = 2;
const visionRadius = 2;
const fov = WallyFOV.computeFieldOfView(fovMap, playerX, playerY, visionRadius);

See which tiles are visible:

fov.getVisible(4, 0); // -> true
fov.getVisible(4, 1); // -> false

Upgrading to version 2

Some API changes were made for version 2, here's what you need to do to upgrade:

  • The Direction enumeration has been renamed to CardinalDirection
  • Instead of calling fovMap.getFieldOfView(x, y, radius), call WallyFOV.computeFieldOfView(fovMap, x, y, radius)
  • Instead of calling fov.get(x, y), call fov.getVisible(x, y)

If you're using TypeScript, some of the type names have changed. For instance, the type for the field of view is now FieldOfView instead of MaskRectangle.

Details

WallyFOV works by scanning the four quadrants around the player, tracking the angles visible from the center of the player tile. A tile is considered visible if there exists an uninterrupted ray from the player center to any point in the tile. Bodies almost (but don't quite) fill the tile, to cover some conspicuous "corner" cases.

Example Image

In this example image, the shaded tiles are not seen. Blue lines represent edges of the shadows at various stages of the algorithm. Dashed lines indicate where a shadow edge is very slightly shifted because it was created by a body.

For more information, see the Algorithm Overview.

wally-fov's People

Contributors

dependabot[bot] avatar sbj42 avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar

wally-fov's Issues

addWall() fails at the edge of the map

Adding a wall at the very edge of the map fails. For instance:

const fovMap = new FieldOfViewMap(2, 2);
fovMap.addWall(0, 0, geom.Direction.NORTH);
fovMap.getWall(0, 0, geom.Direction.NORTH); // <-- returns false

addWall() is avoiding putting an opposing wall out of bounds, but in doing so it fails to put the requested in-bounds wall.

Walls on the edge of the map aren't of much use to the field-of-view algorithm, but in case someone relies on FieldOfViewMap to save wall positions, it should still remember them.

Let `FieldOfViewMap` support a map over an arbitrary rectangle, not just starting at 0,0

Let's add support for maps whose coordinates span an arbitrary rectangle. So you could have a map on, for example, (-20,-20)-(20,20) or (10000, 5000)-(10030, 5030). Basically we just need to use a Rectangle in FieldOfViewMap instead of a Size.

A possible interface would be:

const map = new FieldOfViewMap(-100, -50, 100, 100); // (x, y, w, h)
// map now ranges from (-100, -50) to (-1, 49)
map.addBody(-10, -30);

This shouldn't hurt performance, but it would help users avoid needing to map their own coordinates into a (0,0)-origin map space. See discussion in #1

Let computeFieldOfView allow fractional player locations

The algorithm should work just as well for player locations that are "in between" tile centers. For instance, a player at (1.25, 4) would be 25% of the way from (1, 4) to (2, 4). Their field of view could be computed as if they were at (1, 4), except that the shadow angles would be different.

This could be used for smooth transitions as the player moves from one tile to another.

getBody() returns number, should return boolean

FieldOfViewMap.getBody(x, y) should return a boolean, but instead it returns a number. This doesn't affect regular JavaScript usage, but would be annoying with TypeScript.

The return statement needs !== 0.

Negative X / Y addresses cause an infinite loop

Hi there. I know I'm the first to star your library, but I tried it out a bit last night in my project as a FoV calculation algorithm and found a modest bug:

Right now I've got a sample level stitched together from prefabs. I started from one room with 0, 0 as its upper left corner, and then just added new ones outside of it until I was happy with the level (this is a roguelike project I'm working on and haven't gotten world generation done yet).

The algorithm ran fine for awhile in my first room, but I found as soon as I went north and it needed to do calculations with the player's position being 4, -1 or whatever, the application would just hang indefinitely in WallyFOV code.

My fix was somewhat simple - in defining things to WallyFOV, I give it a small chunk of my world - a square equal to (ViewRadius * 2) + 1 in size, and I have the upper left corner of that square always be 0, 0, then I just offset tile addresses coming into and out of WallyFOV so that I can work around the negative positioning bug.

This is unlikely to be a problem for me again, but it was a modestly severe bug to encounter and might be worth fixing or failing with an error message instead of hanging.

On another note, I'm loving the library and appreciate the work you put into this as well as your two posts on the matter. This lets me shortcut some of the boring aspects of the project I'm not that interested in and get closer to the artificial intelligence aspects that are very appealing as well as just to get the thing closer to an actual prototype.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.