1.0.2 • Published 9 months ago

flow-field-ts v1.0.2

Weekly downloads
-
License
-
Repository
github
Last release
9 months ago

Flow Field

Implements a flow field using typescript.

Installation

npm i flow-field-ts

Usage

1. Create an InitialGrid

This is the first structure to create that represents the entire grid area.

import { InitialGrid, vec } from 'flow-field-ts'
const grid = new InitialGrid(vec(10, 10));

2. Convert to CostGrid

The next step is to convert to a CostGrid by providing the destination vector, the initial cost value, and a tuple array of vectors that have different weights.

import { InitialGrid, vec } from 'flow-field-ts'

const grid = new InitialGrid(vec(10, 10));
const costGrid = grid.toCostGrid(vec(9, 9), 1, []); // destination would be GridCell at 9,9

3. Convert to IntegrationGrid

The final step to to convert to IntegrationGrid which will create the destination vector of each GridCell.

import { InitialGrid, vec } from 'flow-field-ts'

const grid = new InitialGrid(vec(10, 10));
const costGrid = grid.toCostGrid(vec(9, 9), 1, []);
const iGrid = costGrid.toIntegrationGrid();

The integration grid is what you will use to determine the flow of entities.

Example

// Using ExcaliburJs to demo game loop
import { Actor, CollisionType, Color, Engine, Vector, vec } from 'excalibur'
import { InitialGrid, vec as ffVec } from 'flow-field-ts'

/**
 *  Grid can represent any dimensions.  It's best not to represent 1 pixel.
 * In this case, 1x1 grid square represent 60 width and 80 height
 **/
const WIDTH = 800;
const HEIGHT = 600;

const xGridLength = 10;
const yGridLength = 10;

const xCellWidth = WIDTH / xGridLength;
const yCellHeight = HEIGHT / yGridLength;
const SPEED = 30;

const g = new InitialGrid(ffVec(10, 10));
const cg = g.toCostGrid(ffVec(9, 9), 1, []);
const ig = cg.toIntegrationGrid();

const game = new Engine({
    width: WIDTH,
    height: HEIGHT,
});

game.start().then(() => {
    // generating 1000 actors
    for (let i = 0; i < 1000; i++) {
        // Create random location for actor to spawn
        const randomX = Math.trunc(Math.random() * WIDTH);
        const randomY = Math.trunc(Math.random() * HEIGHT);

        const actor = new Actor({
            x: randomX,
            y: randomY,
            width: 2,
            height: 2,
            color: Color.Black,
            collisionType: CollisionType.Active
        });
        
        // Calculate velocity in update loop
        actor.on('postupdate', () => {
            // Here is where the actor position is converted to GridCell
            const xCellValue = Math.trunc(actor.pos.x / xCellWidth);
            const yCellValue = Math.trunc(actor.pos.y / yCellHeight);
            const gridCell = ig.getCell(ffVec(xCellValue, yCellValue));
            
            if (gridCell) {
                // Sets velocity to move actor
                // note: This is an excaliburjs Vector
                actor.vel = vec(
                    gridCell.direction.x * SPEED,
                    gridCell.direction.y * SPEED
                );
            }
            
            if (actor.vel.equals(Vector.Zero)) {
                // kill if reaches destination
                setTimeout(() => {
                    actor.kill();
                }, 300);
            }
        });
        game.add(actor);
    }
});

Demo.gif