grid-engine
Version:
Phaser3 plugin for grid based movement on a 2D game board.
611 lines (610 loc) • 23.1 kB
TypeScript
import { Direction } from "./Direction/Direction.js";
import { MovementInfo } from "./Movement/Movement.js";
import { Finished, MoveToConfig } from "./Movement/TargetMovement/TargetMovement.js";
import { QueueMovementConfig, QueueMovementEntry, Finished as QueueMovementFinished } from "./Movement/QueueMovement/QueueMovement.js";
import { Observable } from "rxjs";
import { CharacterFilteringOptions } from "./GridCharacter/CharacterFilter/CharacterFilter.js";
import { CharId, PositionChange } from "./GridCharacter/GridCharacter.js";
import { ShortestPathAlgorithmType } from "./Pathfinding/ShortestPathAlgorithm.js";
import { IsPositionAllowedFn, PathfindingOptions } from "./Pathfinding/PathfindingOptions.js";
import { CharLayer, LayerPosition, Position } from "./Position.js";
/**
* Result of a pathfinding algorithm run.
*
* @category Pathfinding
*/
export interface PathfindingResult {
steps: number;
/**
* Actual shortest path. Contains an empty array if no path has
* been found.
*/
path: LayerPosition[];
/**
* Only set, if {@link PathfindingOptions.calculateClosestToTarget} is set.
* It will still be set in algorithms where it does not come with a
* performance penalty (like BFS).
* If no path could be found, it contains one position that has the closest
* distance to the target. The distance is either
* {@link https://en.wikipedia.org/wiki/Taxicab_geometry | manhattan distance}
* in case of 4 direction mode or
* {@link https://en.wikipedia.org/wiki/Chebyshev_distance | Chebyshev distance}
* in case of 8 direction mode.
*/
closestToTarget?: LayerPosition;
/**
* In case that {@link PathfindingOptions.maxPathLength} was set, this
* property indicates that pathfinding stopped because it reached that maximum
* path lenght.
*/
reachedMaxPathLength: boolean;
}
/**
* @category Pathfinding
*/
export interface FollowOptions {
/**
* Minimum distance to keep to `charIdToFollow` in
* {@link https://en.wikipedia.org/wiki/Taxicab_geometry | manhattan distance}
* in case of 4 direction mode and with and
* {@link https://en.wikipedia.org/wiki/Chebyshev_distance | Chebyshev distance}
* in case of 8 direction mode.
*/
distance?: number;
/**
* `charId` will move to the closest point
* ({@link https://en.wikipedia.org/wiki/Taxicab_geometry | manhattan distance}
* in case of 4 direction mode and with and
* {@link https://en.wikipedia.org/wiki/Chebyshev_distance | Chebyshev distance}
* in case of 8 direction mode)
* to `charIdToFollow` that is reachable from `charId` in case that there
* does not exist a path between `charId` and `charIdToFollow`.
*/
closestPointIfBlocked?: boolean;
/**
* If this is set, the algorithm will stop once it reaches a path length of
* this value. This is useful to avoid running out of memory on large or
* infinite maps.
*/
maxPathLength?: number;
/**
* Algorithm to use for pathfinding.
*/
algorithm?: ShortestPathAlgorithmType;
/**
* If set to `true`, pathfinding will only be performed on the char layer of
* the start position. If you don't use char layers, activating this setting
* can improve pathfinding performance.
*
* @default false
*/
ignoreLayers?: boolean;
/**
* This setting is ignored if you provide a {@link FollowOptions.distance}
* other than 0.
*
* An unblocked position adjacent to the target character with the shortest
* distance to the source character (the one following) is taken as a target.
* If there are multiple of these positions any one of them is picked.
* With this setting you can give an explicit position based on the current
* facing direction of the target character.
*
* For Example:
* If you provide a {@link FollowOptions.facingDirection} of 'down', that
* means that you want to follow the position the character is turned away
* from. So if the target character's facing direction is `right`, that would
* translate to this:
* ```
* down-left | left | up-left
* down | (=>) | up
* down-right | right | up-right
* ```
*/
facingDirection?: Direction;
/**
* Function to specify whether a certain position is allowed for pathfinding.
* If the function returns false, the tile will be consindered as blocked.
*
* It can be used to restrict pathfinding to specific regions.
*
* Beware that this method can become a performance bottleneck easily. So be
* careful and keep it as efficient as possible. An asymptotic runtime
* complexity of O(1) is recommended.
*/
isPositionAllowedFn?: IsPositionAllowedFn;
/**
* Only considered by A* algorithm.
* If set to `true`, pathfinding will consider costs. Costs are set via tile
* properties.
*
* @default false
*/
considerCosts?: boolean;
/**
* Set of characters to ignore at collision checking.
*/
ignoredChars?: CharId[];
}
/**
* Result of a modification of the internal characters array
*/
export interface CharacterShift {
/** the modified character */
charId: string;
/** The action that was performed when modifying the character */
action: CharacterShiftAction;
}
/**
* Type of modification of grid engine characters
*/
export declare enum CharacterShiftAction {
/** removed existing character */
REMOVED = "REMOVED",
/** added new character */
ADDED = "ADDED"
}
export interface IGridEngine {
/**
* Returns the character layer of the given character.
* You can read more about character layers and transitions
* {@link https://annoraaq.github.io/grid-engine/p/character-layers | here}
*
* @category Character
*/
getCharLayer(charId: string): string | undefined;
/**
* @returns The character layer that the transition on the given position and
* character layer leads to.
*
* @beta
*
* @category Tilemap
*/
getTransition(position: Position, fromLayer: string): string | undefined;
/**
* Sets the character layer `toLayer` that the transition on position
* `position` from character layer `fromLayer` should lead to.
* You can read more about character layers and transitions
* {@link https://annoraaq.github.io/grid-engine/p/character-layers | here}
*
* @param position Position of the new transition
* @param fromLayer Character layer the new transition should start at
* @param toLayer Character layer the new transition should lead to
*
* @beta
*
* @category Tilemap
*/
setTransition(position: Position, fromLayer: string, toLayer: string): void;
/**
* @returns The tile position of the character with the given id
*
* @category Character
*/
getPosition(charId: string): Position;
/**
* Initiates movement of the character with the given id. If the character is
* already moving nothing happens. If the movement direction is currently
* blocked, the character will only turn towards that direction. Movement
* commands are **not** queued.
*
* @category Basic Movement
*/
move(charId: string, direction: Direction): void;
/**
* Initiates random movement of the character with the given id. The
* character will randomly pick one of the non-blocking directions.
* Optionally a `delay` in milliseconds can be provided. This represents the
* waiting time after a finished movement, before the next is being initiated.
* If a `radius` other than -1 is provided, the character will not move
* further than that radius from its initial position (the position it has
* been, when `moveRandomly` was called). The distance is calculated with the
* {@link https://en.wikipedia.org/wiki/Taxicab_geometry | manhattan distance}
* in case of 4 direction mode and with and
* {@link https://en.wikipedia.org/wiki/Chebyshev_distance | Chebyshev distance}
* in case of 8 direction mode. Additionally, if a `radius` other than -1 was
* given, the character might move more than one tile into a random direction
* in one run (as long as the route is neither blocked nor outside of the
* radius).
*
* @category Random Movement
*/
moveRandomly(charId: string, delay: number, radius: number): void;
/**
* @returns Information about the current automatic movement (including
* random movement, follow movement and target movement)
*
* @category Character
*/
getMovement(charId: string): MovementInfo;
/**
* Initiates movement toward the specified `targetPos`. The movement will
* happen along one shortest path. Check out {@link MoveToConfig} for
* pathfinding configurations.
*
* @returns an observable that will fire
* whenever the moveTo movement is finished or aborted. It will provide a
* {@link MoveToResult | result code} as well as a description and a character
* layer.
*
* @category Pathfinding
*/
moveTo(charId: string, targetPos: Position, config?: MoveToConfig): Observable<{
charId: string;
} & Finished>;
/**
* Stops any automated movement such as random movement
* ({@link moveRandomly}), following ({@link follow}), moving to a
* specified position ({@link moveTo}) or queued movements ({@link addQueueMovements}).
*
* @category Character
*/
stopMovement(charId: string): void;
/**
* Sets the speed in tiles per second for a character.
*
* @category Character
*/
setSpeed(charId: string, speed: number): void;
/**
* @returns Speed in tiles per second for a character.
*
* @category Character
*/
getSpeed(charId: string): number;
/**
* @returns true if the character is able to collide with the tilemap. Don't
* confuse this with an actual collision check. You should use
* {@link isBlocked} or {@link isTileBlocked} for this.
*
* @category Character
*/
collidesWithTiles(charId: string): boolean;
/**
* @category Grid Engine
*/
update(_time: number, delta: number): void;
/**
* Checks whether a character with the given ID is registered.
*
* @category Grid Engine
*/
hasCharacter(charId: string): boolean;
/**
* Removes the character with the given ID from the plugin.
* Please note that the corresponding sprite and container need to be removed
* separately.
*
* @category Grid Engine
*/
removeCharacter(charId: string): void;
/**
* Removes all characters from the plugin.
* Please note that the corresponding sprites and containers need to be
* removed separately.
*
* @category Grid Engine
*/
removeAllCharacters(): void;
/**
* @returns All character IDs that are registered in the plugin, satisfying
* the provided filtering options.
*/
getAllCharacters(options?: CharacterFilteringOptions): string[];
/**
* @returns All labels, attached to the character.
*
* @category Character
*/
getLabels(charId: string): string[];
/**
* Add labels to the character.
*
* @category Character
*/
addLabels(charId: string, labels: string[]): void;
/**
* Remove labels from the character.
*
* @category Character
*/
removeLabels(charId: string, labels: string[]): void;
/**
* Removes all labels from the character.
*
* @category Character
*/
clearLabels(charId: string): void;
/**
* Character `charId` will start to walk towards `charIdToFollow` on a
* shortest path until it reaches the specified `distance`.
*
* @param charId ID of character that should follow
* @param charIdToFollow ID of character that should be followed
*
* @category Pathfinding
*/
follow(charId: string, charIdToFollow: string, options?: FollowOptions): void;
/**
* @deprecated
* Use follow(charId: string, charIdToFollow: string, options: FollowOptions): void;
* instead.
*
* Character `charId` will start to walk towards `charIdToFollow` on a
* shortest path until it reaches the specified `distance`.
*
* @param charId ID of character that should follow
* @param charIdToFollow ID of character that should be followed
* @param distance Minimum distance to keep to `charIdToFollow` in
* {@link https://en.wikipedia.org/wiki/Taxicab_geometry | manhattan distance}
* in case of 4 direction mode and with and
* {@link https://en.wikipedia.org/wiki/Chebyshev_distance | Chebyshev distance}
* in case of 8 direction mode.
* @param closestPointIfBlocked `charId` will move to the closest point
* ({@link https://en.wikipedia.org/wiki/Taxicab_geometry | manhattan distance}
* in case of 4 direction mode and with and
* {@link https://en.wikipedia.org/wiki/Chebyshev_distance | Chebyshev distance}
* in case of 8 direction mode)
* to `charIdToFollow` that is reachable from `charId` in case that there
* does not exist a path between `charId` and `charIdToFollow`.
*/
follow(charId: string, charIdToFollow: string, distance?: number, closestPointIfBlocked?: boolean): void;
follow(charId: string, charIdToFollow: string, distance?: FollowOptions | number, closestPointIfBlocked?: boolean): void;
/**
* @returns True if the character is currently moving.
*
* @category Chatacter State
*/
isMoving(charId: string): boolean;
/**
* @returns Direction the character is currently facing. At time of creation
* this is `down`.
*
* @category Character
*/
getFacingDirection(charId: string): Direction;
/**
* @returns Position the character is currently facing.
*
* @category Character
*/
getFacingPosition(charId: string): Position;
/**
* Turns the character towards the given direction without moving it.
*
* @category Basic Movement
*/
turnTowards(charId: string, direction: Direction): void;
/**
* Finds the identifiers of all characters at the provided tile position.
* @returns The identifiers of all characters on this tile.
*
* @category Tilemap
*/
getCharactersAt(position: Position, layer?: string): string[];
/**
* Places the character with the given id to the provided tile position. If
* that character is moving, the movement is stopped. The
* {@link positionChangeStarted} and {@link positionChangeFinished} observables will
* emit. If the character was moving, the {@link movementStopped} observable
* will also emit.
*
* @category Character
*/
setPosition(charId: string, pos: Position, layer?: string): void;
/**
* Checks whether the given position is blocked by either the tilemap or a
* blocking character. If you provide no layer, be sure not to use character
* layers in your tilemap.
*
* @returns True if position on given layer is blocked by the tilemap or a
* character
*
* @category Tilemap
*/
isBlocked(position: Position, layer?: string, collisionGroups?: string[]): boolean;
/**
* Checks whether the given position is blocked by the tilemap. If you provide
* no layer, be sure not to use character layers in your tilemap.
*
* @returns True if position on given layer is blocked by the tilemap.
*
* @category Tilemap
*/
isTileBlocked(position: Position, layer?: string): boolean;
/**
* Returns all collision groups of the given character.
* {@link https://annoraaq.github.io/grid-engine/examples/collision-groups | Collision Groups Example}
*
* @returns All collision groups of the given character.
*
* @category Character
*/
getCollisionGroups(charId: string): string[];
/**
* Sets collision groups for the given character. Previous collision groups
* will be overwritten.
*
* @category Character
*/
setCollisionGroups(charId: string, collisionGroups: string[]): void;
/**
* Sets collision groups for the given character. Previous collision groups
* will be overwritten.
*
* @category Character
*/
setIgnoreCollisionGroups(charId: string, ignoreCollisionGroups: string[]): void;
/**
* Returns all collision groups the character should ignore.
*
* @category Character
*/
getIgnoreCollisionGroups(charId: string): string[];
/**
* Gets the tile position and character layer adjacent to the given
* position in the given direction.
*
* @category Tilemap
*/
getTilePosInDirection(position: Position, charLayer: string | undefined, direction: Direction): LayerPosition;
/**
* Returns the shortest path from source to destination.
*
* @param source Source position
* @param dest Destination position
* @param options Pathfinding options
* @returns Shortest path. In case that no path could be found,
* `closestToTarget` is a position with a minimum distance to the target.
*
* @alpha
*
* @category Pathfinding
*/
findShortestPath(source: LayerPosition, dest: LayerPosition, options?: PathfindingOptions): PathfindingResult;
/**
* @returns Observable that, whenever a specified position is entered on optionally provided layers,
* will notify with the target characters position change
*
* @category Basic Movement
*/
steppedOn(charIds: string[], tiles: Position[], layer?: CharLayer[]): Observable<{
charId: string;
} & PositionChange>;
/**
* @returns Observable that emits when a new character is added or an existing is removed.
*
* @category Grid Engine
*/
characterShifted(): Observable<CharacterShift>;
/**
* @returns Observable that on each start of a movement will provide the
* character ID and the direction.
*
* @category Character
*/
movementStarted(): Observable<{
charId: string;
direction: Direction;
}>;
/**
* @returns Observable that on each stopped movement of a character will
* provide it’s ID and the direction of that movement.
*
* @category Character
*/
movementStopped(): Observable<{
charId: string;
direction: Direction;
}>;
/**
* @returns Observable that will notify about every change of direction that
* is not part of a movement. This is the case if the character tries to walk
* towards a blocked tile. The character will turn but not move.
* It also emits when you call {@link GridEngine.turnTowards}.
*
* This obsersable never emits more than one time in a row for the same
* direction.
* So for instance, if {@link GridEngine.turnTowards} is called multiple times
* in a row (without any facing direction change occurring inbetween) with the
* same direction, this observable would only emit once.
*
* @category Character
*/
directionChanged(): Observable<{
charId: string;
direction: Direction;
}>;
/**
* @returns Observable that will notify about every change of tile position.
* It will notify at the beginning of the movement.
*
* @category Character
*/
positionChangeStarted(): Observable<{
charId: string;
} & PositionChange>;
/**
* @returns Observable that will notify about every change of tile position.
* It will notify at the end of the movement.
*
* @category Character
*/
positionChangeFinished(): Observable<{
charId: string;
} & PositionChange>;
/**
* Returns the movement progress (0-1000) of a character to the next tile. For
* example, if a character has movement progress 400 that means that it has
* moved 400/1000th of the distance to the next tile already.
*
* @category Character
*/
getMovementProgress(charId: string): number;
/**
* Refresh the tile collision cache. For performance reasons, you should
* provide an area that needs to be rebuilt, if possible. You need to have
* {@link GridEngineConfigHeadless.cacheTileCollisions} enabled.
*
* For more information on pathfinding performance check out
* {@link https://annoraaq.github.io/grid-engine/p/pathfinding-performance/| pathfinding performance}.
*
* @category Grid Engine
*/
rebuildTileCollisionCache(x: number, y: number, width: number, height: number): void;
/**
* Adds new positions to the movement queue. Any other automatic movement of
* the character will be stopped.
* @param charId
* @param positions Positions to enqueue
* @param options Options for the queue movement. These options take effect
* immediately (also for previously enqueued but not yet executed movements).
*
* @category Queue Movement
*/
addQueueMovements(charId: string, positions: Array<LayerPosition | Direction>, options?: QueueMovementConfig): void;
/**
* Returns all enqueued movements for the given character.
*
* @category Queue Movement
*/
getEnqueuedMovements(charId: string): QueueMovementEntry[];
/**
* Clears the complete movement queue for the character, that was filled by
* using {@link IGridEngine.addQueueMovements}.
*
* @category Queue Movement
*/
clearEnqueuedMovements(charId: string): void;
/**
* Emits whenever queued movements for a character finish (with success or
* failure).
*
* @category Queue Movement
*/
queueMovementFinished(): Observable<{
charId: string;
} & QueueMovementFinished>;
/**
* Returns the {@link https://annoraaq.github.io/grid-engine/p/tile-properties/#pathfinding-costs | tile cost}
* for a position.
*
* @category Pathfinding
*/
getTileCost(position: Position, charLayer?: string, srcDirection?: Direction): number;
/**
* Reverts the current movement of a character. This makes the character turn
* around immediately and move in the opposite direction.
*
* @category Basic Movement
*/
revertCurrentMovement(charId: string): void;
/**
* Returns whether the current movement has been reverted. Note that as soon
* as the character reaches the tile from which they started before the
* movement got reverted, this returns `false` again.
*
* @category Basic Movement
*/
isCurrentMovementReverted(charId: string): boolean;
}