diff --git a/src/core/game.ts b/src/core/game.ts index 371a5eb..7c43094 100644 --- a/src/core/game.ts +++ b/src/core/game.ts @@ -10,7 +10,8 @@ import type { IGlobalStateChangedData, IObjectDeletedOrCreatedData, IEntityTagsChangedData, - ICommandBlocked + ICommandBlocked, + IGameMap } from "@interfaces"; import { EntityManager, UndoManager } from "@core"; import type { @@ -29,7 +30,9 @@ import type { CommandContext, OnTagsChangesDecoratorsProperties, OnUIEventDecoratorProperties, - OnConsoleKeyboardEventDecoratorProperites + OnConsoleKeyboardEventDecoratorProperites, + GeometryTypes, + GeometryToPosition } from "@types"; import { BASE_FPS, BASE_MAX_COMMAND_EXECUTING_ON_TICK_LIMIT, isServer } from "@const"; import { BluePrintsFactory, EffectFactory, IteractionsFactory, QuestsFactory, SoundsFactory } from "@factories"; @@ -64,8 +67,8 @@ import { import type { Entity, GameObject } from "@world"; import { ConflictResolverPlugin } from "@plugins"; -export class Game implements IGame { - readonly options: IGameOptions; +export class Game implements IGame { + readonly options: IGameOptions; /** * Flag indicates game start status @@ -394,9 +397,9 @@ export class Game implements IGame { } public constructor( - options?: IInitGameOptions + options?: IInitGameOptions ) { - const manager = new EntityManager([], this) + const manager = new EntityManager>([], this) this.options = { manager, @@ -518,7 +521,7 @@ export class Game implements IGame { return snapshot } - public load(snapshot: ISnapshot, onLoad?: (game: Game) => void) { + public load(snapshot: ISnapshot>, onLoad?: (game: Game) => void) { this.options.map.load(snapshot.objects) this.options.manager.load(snapshot.entities) diff --git a/src/core/manager.ts b/src/core/manager.ts index 09514a8..0f54b0d 100644 --- a/src/core/manager.ts +++ b/src/core/manager.ts @@ -5,21 +5,21 @@ import type { IDeadData, IEntityCreatedData } from "@interfaces"; -import type { GridPosition, Position } from "@types"; +import type { GeometryToPosition, GeometryTypes, GridPosition, GridPosition3D, Position, Position3D } from "@types"; import { Entity, GameMap } from "@world"; import { checkCollisions, convertPositionToGridPosition } from "@utils"; import { FactoryKeys } from "@enums"; -export class EntityManager implements Manager { - public readonly game: Game; - public readonly gameMap: GameMap; - public readonly grid = new Map>() +export class EntityManager> implements Manager { + public readonly game: Game; + public readonly gameMap: GameMap; + public readonly grid = new Map>>() - public entities = new Map() + public entities = new Map>() - public load(rawEntity: ITarget[]) { + public load(rawEntity: ITarget[]) { this.entities = new Map(rawEntity.map((raw) => { - const entity = Entity.fromSnapshot(raw, this, this.gameMap, this.game.getFactory(FactoryKeys.EFFECTS)) + const entity = Entity.fromSnapshot(raw, this, this.gameMap, this.game.getFactory(FactoryKeys.EFFECTS)) return [entity.id, entity] })) @@ -30,7 +30,7 @@ export class EntityManager implements Manager { * @param entity - Entity to add * @returns { void } */ - public addToGrid(entity: Entity): void { + public addToGrid(entity: Entity): void { const gridPosition = convertPositionToGridPosition(entity.position) if (!this.grid.has(gridPosition)) this.grid.set(gridPosition, new Set([entity])) @@ -42,7 +42,7 @@ export class EntityManager implements Manager { * @param entity - Entity to delete * @returns { void } */ - public deleteFromGrid(entity: Entity): void { + public deleteFromGrid(entity: Entity): void { const gridPosition = convertPositionToGridPosition(entity.position) const cell = this.grid.get(gridPosition) @@ -59,7 +59,7 @@ export class EntityManager implements Manager { * @param oldPosition - Entity old position * @returns { void } */ - public updateGrid(entity: Entity, oldPosition: Position): void { + public updateGrid(entity: Entity, oldPosition: Position | Position3D): void { const oldGrid = convertPositionToGridPosition(oldPosition) const newGrid = convertPositionToGridPosition(entity.position) @@ -77,8 +77,8 @@ export class EntityManager implements Manager { } } - public constructor(entities: Entity[], game: Game) { - this.gameMap = new GameMap(this, game) + public constructor(entities: Entity[], game: Game) { + this.gameMap = new GameMap(this, game) this.game = game this.entities = new Map(entities.map(e => [e.id, e])) } @@ -87,7 +87,7 @@ export class EntityManager implements Manager { return this.entities.get(id) } - public create(target: ITarget) { + public create(target: ITarget): Entity { const entity = new Entity(target, this, this.gameMap) this.addToGrid(entity) @@ -103,7 +103,7 @@ export class EntityManager implements Manager { return entity } - public update(id: number, target: Partial) { + public update(id: number, target: Partial>) { const entity = this.get(id) if (!entity) return undefined @@ -114,7 +114,7 @@ export class EntityManager implements Manager { entity.name = target.name ?? entity.name if (target.position) { - this.updateGrid(target as Entity, entity.position) + this.updateGrid(target as Entity, entity.position) entity.position = target.position } @@ -148,7 +148,7 @@ export class EntityManager implements Manager { entity.isDead = true entity.dropInventory() - this.game.processEvent('entityDead', { + this.game.processEvent>('entityDead', { entity, eventTime: this.game.currentTick, eventData: { diff --git a/src/index.ts b/src/index.ts index 1a501bb..0ed6b7f 100644 --- a/src/index.ts +++ b/src/index.ts @@ -4,6 +4,7 @@ import type { IGameMap, IInitGameOptions, } from "@interfaces"; +import type { GeometryTypes } from "@types"; export * from "./const/index.js" export * from "./core/index.js" @@ -23,8 +24,8 @@ export * from "./plugins/index.js" * @param options - Init game options * @returns { [game: Game, manager: IEntityManager, map: IGameMap] } - Array with main game iteract objects */ -export const createGame = (options?: IInitGameOptions): [game: Game, manager: IEntityManager, map: IGameMap] => { - const game = new Game(options) +export const createGame = (options?: IInitGameOptions): [game: Game, manager: IEntityManager, map: IGameMap] => { + const game = new Game(options) return [game, game.options.manager, game.options.map] as const } diff --git a/src/interfaces/core/engine/classes-engine.interfaces.ts b/src/interfaces/core/engine/classes-engine.interfaces.ts index b4156cf..e4ef429 100644 --- a/src/interfaces/core/engine/classes-engine.interfaces.ts +++ b/src/interfaces/core/engine/classes-engine.interfaces.ts @@ -15,18 +15,21 @@ import type { AnyPosition, CustomEventCallback, EventCallback, + GeometryToPosition, + GeometryTypes, MiddlewareFn, Position, + Position3D, Quad, SnapshotCallback } from "@types"; import type { Entity, GameObject } from "@world"; -export interface IGame { +export interface IGame { /** * Init game options */ - readonly options: IGameOptions; + readonly options: IGameOptions; /** * Subscribe to game event @@ -107,7 +110,7 @@ export interface IGame { * @param onLoad - Function will be executed after load snapshot * @returns { boolean } - True if correct load, else false */ - readonly load: (snapshot: ISnapshot, onLoad?: (game: Game) => void) => void; + readonly load: (snapshot: ISnapshot>, onLoad?: (game: Game) => void) => void; /** * Register a middleware @@ -137,35 +140,35 @@ export interface IGame { readonly stop: () => boolean; } -export interface IEntityManager { +export interface IEntityManager> { /** * Game reference */ - readonly game: IGame; + readonly game: IGame; /** * Game map reference */ - readonly gameMap: IGameMap; + readonly gameMap: IGameMap; /** * Map of all game entities */ - readonly entities: Map; + readonly entities: Map>; /** * Create Entity in world * @param target - Entity data * @returns { Entity } - Created entity. Entity can be not created, then executed entityCreatedCollision event */ - readonly create: (target: ITarget) => Entity; + readonly create: (target: ITarget) => Entity; /** * Get one Entity by id. * @param id - ID of Entity * @returns { Entity | undefined } - Entity if founded, else undefined */ - readonly get: (id: number) => Entity | undefined; + readonly get: (id: number) => Entity | undefined; /** * Update one Entity by id @@ -173,7 +176,7 @@ export interface IEntityManager { * @param target - Updating plants * @returns { Entity | undefined } - Updated Entity, undefined if not founded */ - readonly update: (id: number, target: Partial) => Entity | undefined; + readonly update: (id: number, target: Partial>) => Entity | undefined; /** * Delete one Entity by id @@ -201,34 +204,34 @@ export interface IEntityManager { * @param entities - Entities to load * @returns { void } */ - readonly load: (rawEntity: ITarget[]) => void; + readonly load: (rawEntity: ITarget[]) => void; } -export interface IGameMap { +export interface IGameMap> { /** * Entity Manager reference */ - readonly manager: IEntityManager; + readonly manager: IEntityManager; /** * Game reference */ - readonly game: Game; + readonly game: Game; /** * Map of all game objects */ - readonly objects: Map; + readonly objects: Map>; /** * Get world objects in quad * @param quad - Quad to search * @param returnType - Type of return values */ - getInQuad(quad: Quad, returnType?: 'ALL'): (Entity | GameObject)[]; - getInQuad(quad: Quad, returnType: 'ENTITES'): Entity[]; - getInQuad(quad: Quad, returnType: 'OBJECTS'): GameObject[]; - getInQuad(quad: Quad, returnType: 'ALL' | 'ENTITES' | 'OBJECTS'): Entity[] | GameObject[] | (Entity | GameObject)[]; + getInQuad(quad: Quad, returnType?: 'ALL'): (Entity | GameObject)[]; + getInQuad(quad: Quad, returnType: 'ENTITES'): Entity[]; + getInQuad(quad: Quad, returnType: 'OBJECTS'): GameObject[]; + getInQuad(quad: Quad, returnType: 'ALL' | 'ENTITES' | 'OBJECTS'): Entity[] | GameObject[] | (Entity | GameObject)[]; /** * Teleport one Entity to new position @@ -236,18 +239,18 @@ export interface IGameMap { * @param to - AnyPosition for TP * @returns { Entity | false } - Entity if teleported, else false */ - readonly teleport: (id: number, to: AnyPosition) => Entity | false; + readonly teleport: (id: number, to: AnyPosition) => Entity | false; /** * Get all world objects in provided position * @param position - Position to get objects * @returns { (Entity | GameObject)[] } - Array of world objects */ - getAllInPosition(position: Position, returnType?: 'ALL'): (Entity | GameObject)[]; - getAllInPosition(position: Position, returnType: 'ENTITES'): Entity[]; - getAllInPosition(position: Position, returnType: 'OBJECTS'): GameObject[]; - getAllInPosition(position: Position, returnType: 'ALL' | 'ENTITES' | 'OBJECTS'): Entity[] | GameObject[] | (Entity | GameObject)[]; - getAllInPosition(position: Position, returnType:'ALL' | 'ENTITES' | 'OBJECTS'): (Entity | GameObject)[]; + getAllInPosition(position: Position | Position3D, returnType?: 'ALL'): (Entity | GameObject)[]; + getAllInPosition(position: Position | Position3D, returnType: 'ENTITES'): Entity[]; + getAllInPosition(position: Position | Position3D, returnType: 'OBJECTS'): GameObject[]; + getAllInPosition(position: Position | Position3D, returnType: 'ALL' | 'ENTITES' | 'OBJECTS'): Entity[] | GameObject[] | (Entity | GameObject)[]; + getAllInPosition(position: Position | Position3D, returnType:'ALL' | 'ENTITES' | 'OBJECTS'): (Entity | GameObject)[]; /** * Create game object @@ -255,7 +258,7 @@ export interface IGameMap { * @param metadata - Object metadata * @returns { GameObject } - GameObject, also generates object error events, if need */ - readonly createObject: (obj: IGameObject, metadata?: T) => GameObject; + readonly createObject: (obj: IGameObject, metadata?: M) => GameObject; /** * Delete one object by id @@ -269,13 +272,13 @@ export interface IGameMap { * @param id - ID of object * @returns { GameObject | undefined } - GameObject if founded, else undefined */ - readonly getObject: (id: number) => GameObject | undefined; + readonly getObject: (id: number) => GameObject | undefined; /** * Get all Items on map * @returns { (GameObject & IGameObject & IWorldItem)[] } - Array of Items */ - readonly getAllItems: () => (GameObject & IGameObject & IWorldItem)[]; + readonly getAllItems: () => (GameObject & IGameObject & IWorldItem)[]; /** * Checks a given object by ID is ok: exists, no collisions in position, exists in position @@ -289,7 +292,7 @@ export interface IGameMap { * @param objects - Objects to load * @returns { void } */ - readonly load: (rawObjects: IGameObject[]) => void; + readonly load: (rawObjects: IGameObject[]) => void; /** * Apply effect to provided Quad area @@ -297,9 +300,9 @@ export interface IGameMap { * @param effect - Effect to apply * @param duration - Effect duration * @param excludeId - Optional ID of entity, effect will not be applied to her - * @returns { Entity[] } - Array of entities founded in quad on applying effect + * @returns { Entity[] } - Array of entities founded in quad on applying effect */ - readonly applyEffectToQuad: (quad: Quad, effect: IGameEffect, duration: number, excludeId?: number) => Entity[]; + readonly applyEffectToQuad: (quad: Quad, effect: IGameEffect, duration: number, excludeId?: number) => Entity[]; } export interface IDeligator { diff --git a/src/interfaces/core/engine/engine-options.intefaces.ts b/src/interfaces/core/engine/engine-options.intefaces.ts index 4d8ae56..7f33676 100644 --- a/src/interfaces/core/engine/engine-options.intefaces.ts +++ b/src/interfaces/core/engine/engine-options.intefaces.ts @@ -1,17 +1,18 @@ import type { Game, UndoManager } from "@core"; import type { IEntityManager, IGameMap } from "@interfaces"; import type { GlobalStore } from "@store"; +import type { GeometryToPosition, GeometryTypes } from "@types"; -export interface IGameOptions { +export interface IGameOptions { /** * Entities in game */ - readonly manager: IEntityManager; + readonly manager: IEntityManager>; /** * Game Map */ - readonly map: IGameMap; + readonly map: IGameMap>; /** * Global game state store @@ -54,6 +55,11 @@ export interface IGameOptions { * Optional command bus options */ readonly commandBusOptions?: ICommandBusOptions; + + /** + * Type of game geometry. By default, 2D + */ + readonly gameGeometry?: G; } export interface ICommandBusOptions { @@ -68,7 +74,7 @@ export interface ICommandBusOptions { readonly maxCommandsPerTick?: number; } -export interface IInitGameOptions extends Partial {} +export interface IInitGameOptions extends Partial> {} export interface IDeligatorOptions { /** diff --git a/src/interfaces/core/support/support.interfaces.ts b/src/interfaces/core/support/support.interfaces.ts index 18f52b8..3ebaeaf 100644 --- a/src/interfaces/core/support/support.interfaces.ts +++ b/src/interfaces/core/support/support.interfaces.ts @@ -1,18 +1,18 @@ import type { Game } from "@core"; import type { CommandType } from "@enums"; import type { IGameObject, ITarget } from "@interfaces"; -import type { CommandContext, LifecycleCallback } from "@types"; +import type { CommandContext, LifecycleCallback, Position, Position3D } from "@types"; -export interface ISnapshot { +export interface ISnapshot

{ /** * Array of game objects */ - readonly objects: IGameObject[]; + readonly objects: IGameObject[]; /** * Array of entities */ - readonly entities: ITarget[]; + readonly entities: ITarget

[]; /** * Global state diff --git a/src/interfaces/entities/items/items.interfaces.ts b/src/interfaces/entities/items/items.interfaces.ts index f8296e6..335b38a 100644 --- a/src/interfaces/entities/items/items.interfaces.ts +++ b/src/interfaces/entities/items/items.interfaces.ts @@ -1,10 +1,10 @@ -import type { Position } from "@types"; +import type { Position, Position3D } from "@types"; -export interface IWorldItem extends IItem { +export interface IWorldItem extends IItem { /** * Item position on world */ - readonly position: Position; + readonly position: T; } export interface IItem { diff --git a/src/interfaces/entities/world-objects/base-world-objects.interfaces.ts b/src/interfaces/entities/world-objects/base-world-objects.interfaces.ts index 904e6cb..f08ce2b 100644 --- a/src/interfaces/entities/world-objects/base-world-objects.interfaces.ts +++ b/src/interfaces/entities/world-objects/base-world-objects.interfaces.ts @@ -1,12 +1,12 @@ import type { GameObjectEnum } from "@enums"; import type { IItem } from "@interfaces"; -import type { Position } from "@types"; +import type { Position, Position3D } from "@types"; -export interface ITarget { +export interface ITarget { /** * Target position in world */ - position: Position; + position: T; /** * Target health @@ -36,7 +36,7 @@ export interface IChest { readonly items: IItem[] } -export interface IGameObject extends Pick { +export interface IGameObject extends Pick, 'position' | 'name'> { /** * Type of GameObject */ diff --git a/src/interfaces/event-datas/actions/attack.action.ts b/src/interfaces/event-datas/actions/attack.action.ts index b181fad..92e182d 100644 --- a/src/interfaces/event-datas/actions/attack.action.ts +++ b/src/interfaces/event-datas/actions/attack.action.ts @@ -1,7 +1,8 @@ import type { Entity, GameObject } from "@world"; import type { EntityManager } from "@core" +import type { GeometryTypes, Position, Position3D } from "@types"; -export interface IAttackResult { +export interface IAttackResult { /** * Count of deaths after attack */ @@ -10,7 +11,7 @@ export interface IAttackResult { /** * Who attack. If EntityManager, than using .kill() */ - readonly attacker: Entity | GameObject | EntityManager; + readonly attacker: Entity | GameObject | EntityManager; /** * Array of victims diff --git a/src/interfaces/event-datas/collisions-datas/collisions-datas.interfaces.ts b/src/interfaces/event-datas/collisions-datas/collisions-datas.interfaces.ts index 5d8e6d3..374f638 100644 --- a/src/interfaces/event-datas/collisions-datas/collisions-datas.interfaces.ts +++ b/src/interfaces/event-datas/collisions-datas/collisions-datas.interfaces.ts @@ -1,5 +1,5 @@ import type { ITarget } from "@interfaces"; -import type { AnyPosition, Position } from "@types"; +import type { AnyPosition, Position, Position3D } from "@types"; import type { Entity, GameObject } from "@world"; export interface IMovedCollisionData { @@ -11,7 +11,7 @@ export interface IMovedCollisionData { /** * Start entity position */ - readonly startPosition: Position; + readonly startPosition: Position | Position3D; /** * Collision position (entity cant moved to her) diff --git a/src/interfaces/event-datas/iteractions-datas/iteractions-datas.interfaces.ts b/src/interfaces/event-datas/iteractions-datas/iteractions-datas.interfaces.ts index 021e680..6eefa29 100644 --- a/src/interfaces/event-datas/iteractions-datas/iteractions-datas.interfaces.ts +++ b/src/interfaces/event-datas/iteractions-datas/iteractions-datas.interfaces.ts @@ -1,9 +1,9 @@ import type { EntityManager } from "@core"; import type { IGameSound } from "@interfaces"; -import type { AnyPosition, Position } from "@types"; +import type { AnyPosition, GeometryTypes, Position, Position3D } from "@types"; import type { Entity, GameObject } from "@world"; -export interface IAttackData { +export interface IAttackData { /** * Array of victims in attack */ @@ -12,10 +12,10 @@ export interface IAttackData { /** * Attacker in event */ - readonly attacker: Entity | GameObject | EntityManager; + readonly attacker: Entity | GameObject | EntityManager; } -export interface IDeadData { +export interface IDeadData { /** * Entity, who dead */ @@ -24,7 +24,7 @@ export interface IDeadData { /** * Killer, who kill entity */ - readonly killer: Entity | GameObject | EntityManager; + readonly killer: Entity | GameObject | EntityManager; } export interface IMovedData { @@ -36,7 +36,7 @@ export interface IMovedData { /** * Entity start position */ - readonly startPosition: Position; + readonly startPosition: Position | Position3D; /** * Entity position after move diff --git a/src/interfaces/event-datas/object-datas/metadata-objects-datas.interfaces.ts b/src/interfaces/event-datas/object-datas/metadata-objects-datas.interfaces.ts index e11dad0..06f1e79 100644 --- a/src/interfaces/event-datas/object-datas/metadata-objects-datas.interfaces.ts +++ b/src/interfaces/event-datas/object-datas/metadata-objects-datas.interfaces.ts @@ -1,5 +1,5 @@ import type { IChest, IItem, IWorldItem } from "@interfaces"; -import type { Position } from "@types"; +import type { Position, Position3D } from "@types"; import type { Entity, GameObject } from "@world"; export interface ITowerShootedData { @@ -77,7 +77,7 @@ export interface IItemDroppedData { /** * Position to drop item */ - readonly position: Position; + readonly position: Position | Position3D; } export interface ITriggerActivatedData { diff --git a/src/plugins/canvas.plugin.ts b/src/plugins/canvas.plugin.ts index ee0953e..e505e0a 100644 --- a/src/plugins/canvas.plugin.ts +++ b/src/plugins/canvas.plugin.ts @@ -1,7 +1,7 @@ import type { Game } from "@core"; import type { IPlugin, ICanvasPluginOptions } from "@interfaces"; import type { Entity, GameObject } from "@world"; -import type { Position } from "@types"; +import type { Position, Position3D } from "@types"; import { CANVAS_BASE_ELEMENT_HEIGHT, CANVAS_BASE_ELEMENT_WIDTH, CANVAS_BASE_HEIGHT, CANVAS_BASE_WIDTH } from "@const"; /** @@ -14,7 +14,7 @@ export class CanvasPlugin implements IPlugin { private readonly ctx: CanvasRenderingContext2D | null; private readonly assets = new Map(); - private drawImage(key: string, position: Position) { + private drawImage(key: string, position: Position | Position3D) { const img = this.assets.get(key) if (img) this.ctx!.drawImage(img, position[0], position[1], img.width || CANVAS_BASE_WIDTH, img.height || CANVAS_BASE_HEIGHT) diff --git a/src/types/geometry/base-geometry.types.ts b/src/types/geometry/base-geometry.types.ts index 36b3e18..9fcd878 100644 --- a/src/types/geometry/base-geometry.types.ts +++ b/src/types/geometry/base-geometry.types.ts @@ -3,6 +3,11 @@ */ export type Position = [number, number] +/** + * 3D Position type + */ +export type Position3D = [number, number, number] + /** * Quad type. (x1y1x2y2) */ @@ -11,9 +16,24 @@ export type Quad = [number, number, number, number] /** * AnyPosition type. Can be position, or quad (unknown) */ -export type AnyPosition = Position | Quad +export type AnyPosition = Position | Position3D | Quad /** * Grid position type */ -export type GridPosition = `${number}:${number}` \ No newline at end of file +export type GridPosition = `${number}:${number}` + +/** + * Grid 3D position type + */ +export type GridPosition3D = `${number}:${number}:${number}` + +/** + * Types of geometry + */ +export type GeometryTypes = '2D' | '3D' + +/** + * Help type to get pos type by geomety type + */ +export type GeometryToPosition = G extends '3D' ? Position3D : Position; diff --git a/src/utils/converters/geometry/convert-entities-to-positions-arrays.ts b/src/utils/converters/geometry/convert-entities-to-positions-arrays.ts index a60719c..c155223 100644 --- a/src/utils/converters/geometry/convert-entities-to-positions-arrays.ts +++ b/src/utils/converters/geometry/convert-entities-to-positions-arrays.ts @@ -1,12 +1,12 @@ -import type { Position } from "@types" +import type { Position, Position3D } from "@types" import type { Entity } from "@world" /** * Convert array of Targets to Positions format [[x, y], [x,y]]... * @param entities - Targets to convert - * @returns {Position[]} - Converted positions + * @returns {Position[] | Position3D[]} - Converted positions */ -export function convertEntitiesToPositionsArrays(entities: Entity[]): Position[] { +export function convertEntitiesToPositionsArrays(entities: Entity[]):( Position | Position3D)[] { const result = [] for (const entity of entities) { diff --git a/src/utils/converters/geometry/just-geometry.converters.ts b/src/utils/converters/geometry/just-geometry.converters.ts index f45af1a..0884420 100644 --- a/src/utils/converters/geometry/just-geometry.converters.ts +++ b/src/utils/converters/geometry/just-geometry.converters.ts @@ -1,31 +1,37 @@ -import type { AnyPosition, GridPosition, Position } from "@types" -import { getCenter, positionIsQuad } from "@utils" +import type { AnyPosition, GridPosition, GridPosition3D, Position, Position3D } from "@types" +import { getCenter, positionIsGridPosition, positionIsPosition, positionIsQuad } from "@utils" /** * Convert AnyPosition to Position (get center, is quad) * @param anyPosition - Quad or Position (unknown) * @returns {Position} - A concrete position */ -export function convertAnyPositionToPosition(anyPosition: AnyPosition): Position { +export function convertAnyPositionToPosition(anyPosition: AnyPosition): Position | Position3D { return positionIsQuad(anyPosition) ? getCenter(anyPosition) : anyPosition } /** * Convert position to Grid Position * @param position - Position to convert - * @returns { GridPosition } - Converted position + * @returns { GridPosition | GridPosition3D } - Converted position */ -export function convertPositionToGridPosition(position: Position): GridPosition { - return `${position[0]}:${position[1]}` +export function convertPositionToGridPosition(position: Position3D): GridPosition3D +export function convertPositionToGridPosition(position: Position): GridPosition +export function convertPositionToGridPosition(position: Position | Position3D): GridPosition | GridPosition3D +export function convertPositionToGridPosition(position: Position | Position3D): GridPosition | GridPosition3D { + return positionIsPosition(position, '2D') ? `${position[0]}:${position[1]}` : `${position[0]}:${position[1]}:${position[2]}` } /** * Convert grid position to default position * @param grid - Grid position - * @returns { Position } - Converted position + * @returns { Position | Position3D } - Converted position */ -export function convertGridPositionToPosition(grid: GridPosition): Position { +export function convertGridPositionToPosition(grid: GridPosition3D): Position3D +export function convertGridPositionToPosition(grid: GridPosition): Position +export function convertGridPositionToPosition(grid: GridPosition | GridPosition3D): Position | Position3D { const gridArray = grid.split(':').map(Number) + const [x, y, z] = gridArray - return [gridArray[0]!, gridArray[1]!] + return positionIsGridPosition(grid, '2D') ? [x!, y!] : [x!, y!, z!] } \ No newline at end of file diff --git a/src/utils/geometry/checkers/just-geometry.checkers.ts b/src/utils/geometry/checkers/just-geometry.checkers.ts index b3effd6..0aedf48 100644 --- a/src/utils/geometry/checkers/just-geometry.checkers.ts +++ b/src/utils/geometry/checkers/just-geometry.checkers.ts @@ -1,4 +1,5 @@ -import type { Position, Quad } from "@types" +import type { Position, Position3D, Quad } from "@types" +import { positionIsPosition } from "@utils" /** * Check Position A === Position B @@ -6,11 +7,11 @@ import type { Position, Quad } from "@types" * @param positionB - Position B * @returns {boolean} - True if positions equals, else false */ -export function checkTwoPositions(positionA: Position, positionB: Position): boolean { - const [xA, yA] = positionA - const [xB, yB] = positionB +export function checkTwoPositions(positionA: Position | Position3D, positionB: Position | Position3D): boolean { + const [xA, yA, zA] = positionA + const [xB, yB, zB] = positionB - return (xA === xB && yA === yB) + return positionIsPosition(positionA, '2D') ? (xA === xB && yA === yB) : (xA === xB && yA === yB && zA === zB) } /** diff --git a/src/utils/geometry/getters/creators.ts b/src/utils/geometry/getters/creators.ts index adba4ea..419b6de 100644 --- a/src/utils/geometry/getters/creators.ts +++ b/src/utils/geometry/getters/creators.ts @@ -1,4 +1,5 @@ -import type { Position, Quad } from "@types" +import type { Position, Position3D, Quad } from "@types" +import { positionIsPosition } from "@utils" /** * Create a Quad from Position @@ -6,8 +7,8 @@ import type { Position, Quad } from "@types" * @param radius - A radius of Quad (by default, 1) * @returns {Quad} - Quad from Position */ -export function createQuadFromPosition(position: Position, radius=1): Quad { - const [x, y] = position +export function createQuadFromPosition(position: Position | Position3D, radius=1): Quad { + const [x, y] = positionIsPosition(position, '2D') ? [position[0], position[1]] : [position[0], position[2]] return [x-1*radius, y-1*radius, x+1*radius, y+1*radius] } diff --git a/src/utils/hooks/use-link.hook.ts b/src/utils/hooks/use-link.hook.ts index 5e04ed3..83dec28 100644 --- a/src/utils/hooks/use-link.hook.ts +++ b/src/utils/hooks/use-link.hook.ts @@ -1,5 +1,5 @@ -import { anyWorldObjectIsGameObject, convertAnyPositionToPosition } from "@utils"; -import type { Linkable, Position } from "@types"; +import { anyWorldObjectIsGameObject, convertAnyPositionToPosition, positionIsPosition } from "@utils"; +import type { GeometryToPosition, Linkable, Position, Position3D } from "@types"; import type { IDeadData, ILink, ILinkOptions, IMovedData, IUseValidationContext } from "@interfaces"; import { USE_VALIDATION_EVENT_PREFIX } from "@const"; import { CommandType } from "@enums"; @@ -35,11 +35,11 @@ export function useLink(from: Linkable, to: Linkable, options?: ILinkOptions): I link: (options?: ILinkOptions) => link.isActive ? false : useLink(from, to, options) } as ILink - function checkMaximum(before: Position, after: Position): boolean { - const [x1, y1] = before - const [x2, y2] = after + function checkMaximum(before: Position | Position3D, after: Position | Position3D): boolean { + const [x1, y1, z1] = before + const [x2, y2, z2] = after - return (x2-x1 > options?.maxDistance! || y2-y1 > options?.maxDistance!) + return positionIsPosition(before, '2D') ? (x2-x1 > options?.maxDistance! || y2-y1 > options?.maxDistance!) : (x2-x1 > options?.maxDistance! || y2-y1 > options?.maxDistance! || z2!-z1! > options?.maxDistance!) } if (options?.enableMiddleware) game.use((cmd, next) => { diff --git a/src/utils/logic/can-checkers/can-see.ts b/src/utils/logic/can-checkers/can-see.ts index 401bd2e..b4722cc 100644 --- a/src/utils/logic/can-checkers/can-see.ts +++ b/src/utils/logic/can-checkers/can-see.ts @@ -1,15 +1,15 @@ import { GameObjectEnum } from "@enums" import type { IGameMap } from "@interfaces" -import type { Position } from "@types" +import type { GeometryTypes, Position, Position3D } from "@types" /** - * Checks a given world object can see position + * Checks a given world object can see position (Works in 2D games) * @param startPosition - Start position to check * @param newPosition - Position to check * @param map - GameMap reference * @returns { boolean } - True if can, else false */ -export function canSee(startPosition: Position, endPosition: Position, map: IGameMap): boolean { +export function canSee(startPosition: Position | Position3D, endPosition: Position | Position3D, map: IGameMap): boolean { let x0 = Math.round(startPosition[0]) let y0 = Math.round(startPosition[1]) diff --git a/src/utils/logic/getters/world-getters.ts b/src/utils/logic/getters/world-getters.ts index af5a513..041e61b 100644 --- a/src/utils/logic/getters/world-getters.ts +++ b/src/utils/logic/getters/world-getters.ts @@ -1,5 +1,5 @@ import type { IChest, IGameObject, IWorldItem } from "@interfaces" -import type { Position } from "@types" +import type { Position, Position3D } from "@types" import { checkTwoPositions, convertGameObjectToInventoryItem, gameObjectIsChest, gameObjectIsItem } from "@utils" import type { GameObject } from "@world" @@ -20,7 +20,7 @@ export function getItemInPosition(objects: (IWorldItem & IGameObject)[]): IWorld * @param objects - GameObject to searching in * @returns { IChest | undefined } - Chest if found, else undefined */ -export function getChestInPosition(position: Position, objects: (GameObject)[]): (GameObject & IChest) | undefined { +export function getChestInPosition(position: Position | Position3D, objects: (GameObject)[]): (GameObject & IChest) | undefined { const obj = objects.find((obj) => checkTwoPositions(obj.position, position)) if (!obj) return undefined diff --git a/src/utils/types-guards/geometry-guards/position-is.type-guards.ts b/src/utils/types-guards/geometry-guards/position-is.type-guards.ts index 341c0b7..195b6af 100644 --- a/src/utils/types-guards/geometry-guards/position-is.type-guards.ts +++ b/src/utils/types-guards/geometry-guards/position-is.type-guards.ts @@ -1,4 +1,4 @@ -import type { AnyPosition, GridPosition, Position, Quad } from "@types" +import type { AnyPosition, GeometryTypes, GridPosition, GridPosition3D, Position, Position3D, Quad } from "@types" /** * Check AnyPosition is Quad @@ -19,20 +19,24 @@ export function positionIsQuad(position: AnyPosition): position is Quad { /** * Check AnyPosition is Position * @param position - AnyPosition to check is Position + * @param type - Type of position (2D or 3D) * @returns { boolean } - True if position is Position, else false */ -export function positionIsPosition(position: AnyPosition): position is Position { +export function positionIsPosition(position: AnyPosition, type?:'2D'): position is Position +export function positionIsPosition(position: AnyPosition, type: '3D'): position is Position3D +export function positionIsPosition(position: AnyPosition, type:GeometryTypes='2D'): position is Position | Position3D { const [x, y] = position if (x === undefined || y === undefined) return false - else return (!isNaN(x) && !isNaN(y) && position.length === 2) ? true : false + else return (!isNaN(x) && !isNaN(y) && position.length === (type === '2D' ? 2 : 3)) ? true : false } /** * Checks given position is GridPosition * @param position - Position to check + * @param type - Type (2d or 3d) * @returns { boolean } - True if provided position is GridPosition, else false */ -export function positionIsGridPosition(position: Position | GridPosition): position is GridPosition { - return typeof position === "string" && position.split(":").length > 0 +export function positionIsGridPosition(position: Position | GridPosition | GridPosition3D, type:GeometryTypes='2D'): position is GridPosition { + return typeof position === "string" && position.split(":").length === (type === '2D' ? 2 : 3) } \ No newline at end of file diff --git a/src/utils/types-guards/world-guards/game-object-is.type-guards.ts b/src/utils/types-guards/world-guards/game-object-is.type-guards.ts index 15db539..d1acaa8 100644 --- a/src/utils/types-guards/world-guards/game-object-is.type-guards.ts +++ b/src/utils/types-guards/world-guards/game-object-is.type-guards.ts @@ -1,12 +1,13 @@ import { GameObjectEnum } from "@enums" import type { IChest, IGameObject, IWorldItem } from "@interfaces" +import type { Position, Position3D } from "@types" /** * Checks a given object is a really exists Item * @param obj - Any game object * @returns {obj is IGameObject & IWorldItem} - GameObject is Item */ -export function gameObjectIsItem(obj: IGameObject): obj is IWorldItem & IGameObject { +export function gameObjectIsItem

(obj: IGameObject): obj is IWorldItem & IGameObject { return obj.type === GameObjectEnum.ITEM && obj.metadata } diff --git a/src/world/entities/entity.ts b/src/world/entities/entity.ts index f338a99..84bcda1 100644 --- a/src/world/entities/entity.ts +++ b/src/world/entities/entity.ts @@ -14,7 +14,7 @@ import type { IGameEffect, } from "@interfaces"; import type { EntityManager } from "@core"; -import type { CreateUsableItemMetadata, Position } from "@types"; +import type { CreateUsableItemMetadata, GeometryToPosition, GeometryTypes, Position, Position3D } from "@types"; import { convertGameObjectToInventoryItem, createId, @@ -26,8 +26,8 @@ import { import { GameObjectEnum } from "@enums"; import type { EffectFactory } from "@factories"; -export class Entity implements ITarget { - public position: Position; +export class Entity implements ITarget { + public position: T; public health: number; public damage: number; public isDead: boolean; @@ -36,8 +36,8 @@ export class Entity implements ITarget { public readonly id = createId(); public currentActiveItem: IItem | undefined; - private readonly manager: EntityManager; - private readonly map: GameMap; + private readonly manager: EntityManager; + private readonly map: GameMap; private readonly tagsIdsMap = new Map(); private effects: (IGameEffect & { remaining: number })[] = []; @@ -91,7 +91,7 @@ export class Entity implements ITarget { dropItems.forEach((item) => this.dropItem(item as GameObject, this.position)) } - public constructor(target: ITarget, manager: EntityManager, map: GameMap) { + public constructor(target: ITarget & { readonly position: T }, manager: EntityManager, map: GameMap) { this.damage = target.damage this.position = target.position this.health = target.health @@ -140,10 +140,10 @@ export class Entity implements ITarget { * @param searchRadius - Radius to serach entities * @param returnType - Type of return array */ - public getNearEntitiesAndObjects(searchRadius: number, returnType?: 'ALL'): (Entity | GameObject)[]; - public getNearEntitiesAndObjects(searchRadius: number, returnType: 'ENTITES'): Entity[]; - public getNearEntitiesAndObjects(searchRadius: number, returnType: 'OBJECTS'): GameObject[]; - public getNearEntitiesAndObjects(searchRadius: number, returnType: 'ALL' | 'ENTITES' | 'OBJECTS'): Entity[] | GameObject[] | (Entity | GameObject)[]; + public getNearEntitiesAndObjects(searchRadius: number, returnType?: 'ALL'): (Entity | GameObject)[]; + public getNearEntitiesAndObjects(searchRadius: number, returnType: 'ENTITES'): Entity[]; + public getNearEntitiesAndObjects(searchRadius: number, returnType: 'OBJECTS'): GameObject[]; + public getNearEntitiesAndObjects(searchRadius: number, returnType: 'ALL' | 'ENTITES' | 'OBJECTS'): Entity[] | GameObject[] | (Entity | GameObject)[]; public getNearEntitiesAndObjects(searchRadius=BASE_SEARCH_RADIUS, returnType: 'ALL' | 'ENTITES' | 'OBJECTS'='ALL') { const entityQuad = createQuadFromPosition(this.position, searchRadius) @@ -155,7 +155,7 @@ export class Entity implements ITarget { * @param targets - Hard set targets to attack * @returns { IAttackResult } - Result of attack */ - public attack(targets?: Entity[]): IAttackResult { + public attack(targets?: Entity[]): IAttackResult { let entities: Entity[]; let counter = 0; @@ -171,7 +171,7 @@ export class Entity implements ITarget { if (isDead) counter++ } - this.manager.game.processEvent('attack', { + this.manager.game.processEvent>('attack', { eventTime: this.map.game.currentTick, entity: this, eventData: { @@ -192,7 +192,7 @@ export class Entity implements ITarget { * @param position - Position of item * @returns { IWorldItem } - IWorldItem */ - public pickUp(position: Position): IWorldItem { + public pickUp(position: Position | Position3D): IWorldItem { const item = getItemInPosition(this.map.getAllInPosition(position, 'OBJECTS'))! this.inventory.push(item) @@ -213,15 +213,15 @@ export class Entity implements ITarget { * @param item - Item in inventory * @param position - Position to drop */ - public dropItem(item: GameObject, position: Position): void + public dropItem(item: GameObject, position: T): void /** * Drop item to provided position * @param id - ID of item in inventory * @param position - Position to drop */ - public dropItem(id: number, position: Position): void - public dropItem(itemOrId: GameObject | number, position: Position): void { + public dropItem(id: number, position: T): void + public dropItem(itemOrId: GameObject | number, position: T): void { const item = this.getItemFromInventoryByItemOrId(typeof itemOrId === 'number' ? itemOrId : itemOrId.id)! this.map.createObject({ @@ -312,7 +312,7 @@ export class Entity implements ITarget { * @param position - Position to open chest * @returns { void } */ - public openChest(position: Position): void { + public openChest(position: Position | Position3D): void { const chest = getChestInPosition(position, this.map.getAllInPosition(position, 'OBJECTS'))! chest.metadata?.items.forEach((item: GameObject) => { @@ -492,8 +492,8 @@ export class Entity implements ITarget { * @param map - Game map reference * @returns { Entity } */ - public static fromSnapshot(data: any, manager: EntityManager, map: GameMap, effectFactory: EffectFactory): Entity { - const entity = new Entity(data, manager, map) + public static fromSnapshot

(data: any, manager: EntityManager, map: GameMap, effectFactory: EffectFactory): Entity { + const entity = new Entity(data, manager, map) if (data.inventory && Array.isArray(data.inventory)) entity.inventory = data.inventory if (data.currentActiveItem) entity.currentActiveItem = entity.inventory.find((item) => item.id === data.currentActiveItemId) diff --git a/src/world/entities/object.ts b/src/world/entities/object.ts index 5dce046..1805668 100644 --- a/src/world/entities/object.ts +++ b/src/world/entities/object.ts @@ -2,23 +2,23 @@ import type { Entity, GameMap } from "@world"; import { FactoryKeys, GameObjectEnum } from "@enums"; import type { IGameObject, ITriggerActivatedData, ITowerShootedData } from "@interfaces"; import type { EntityManager } from "@core"; -import type { Position } from "@types"; +import type { GeometryTypes, Position, Position3D } from "@types"; import { canSee, createId, createQuadFromPosition, useAttack } from "@utils"; import { IteractionsFactory } from "@factories" -export class GameObject implements IGameObject { +export class GameObject implements IGameObject { readonly id: number; type: GameObjectEnum; - position: Position; + position: T; name: string; iteractionId?: number | undefined; metadata?: any; - private readonly map: GameMap; - private readonly manager: EntityManager; + private readonly map: GameMap; + private readonly manager: EntityManager; - public constructor(obj: IGameObject, manager: EntityManager, map: GameMap, metadata?: any) { + public constructor(obj: IGameObject, manager: EntityManager, map: GameMap, metadata?: any) { this.name = obj.name this.position = obj.position this.type = obj.type @@ -116,12 +116,12 @@ export class GameObject implements IGameObject { * @param map - Game map reference * @returns { GameObject } */ - public static fromSnapshot(data: IGameObject, manager: EntityManager, map: GameMap): GameObject { + public static fromSnapshot

(data: IGameObject, manager: EntityManager, map: GameMap): GameObject { const metadata = data.metadata ?? {} if (data.type === GameObjectEnum.CHEST && data.metadata?.items) metadata.items = data.metadata.items.map((i: IGameObject) => GameObject.fromSnapshot(i, manager, map)) - const object = new GameObject(data, manager, map, metadata) + const object = new GameObject(data, manager, map, metadata) map.addToGrid(object) diff --git a/src/world/map.ts b/src/world/map.ts index b94b847..9056371 100644 --- a/src/world/map.ts +++ b/src/world/map.ts @@ -8,7 +8,8 @@ import type { ITriggerActivatedData, IWorldObjectHearedNoiseData, IObjectDeletedOrCreatedData, - IGameEffect + IGameEffect, + IWorldItem } from "@interfaces"; import type { Position, @@ -19,7 +20,11 @@ import type { CreateUsableItemMetadata, CreateChestMetadata, CreateTriggerMetadata, - GridPosition + GridPosition, + GridPosition3D, + Position3D, + GeometryTypes, + GeometryToPosition } from "@types"; import { convertAnyPositionToPosition, @@ -31,20 +36,20 @@ import { import { Entity, GameObject } from "@world"; import { BASE_HEARING_RADIUS } from "@const"; -export class GameMap implements Map { - private readonly grid = new Map>() +export class GameMap> implements Map { + private readonly grid = new Map>>() - public readonly manager: EntityManager; - public readonly game: Game; + public readonly manager: EntityManager; + public readonly game: Game; - public objects = new Map() + public objects = new Map>() /** * Validate and executing error events for new object * @param object - Object to create * @param metadata - Object metadata */ - private validateObject(object: GameObject, metadata?: T) { + private validateObject(object: GameObject, metadata?: M) { if (object.type === GameObjectEnum.ITEM) { const itemMetadata = metadata as Partial @@ -114,7 +119,7 @@ export class GameMap implements Map { * @param position - Position to get triggers * @returns { GameObject[] } - All triggers in position */ - public getTriggersInPosition(position: Position): GameObject[] { + public getTriggersInPosition(position: (Position | Position3D)): GameObject[] { const grid = this.grid.get(convertPositionToGridPosition(position)) return grid ? Array.from(grid).filter((o) => o.type === GameObjectEnum.TRIGGER) : [] @@ -125,14 +130,14 @@ export class GameMap implements Map { * @param obj - Game object to push * @returns { void } */ - public pushObject(obj: GameObject): void { + public pushObject(obj: GameObject): void { this.addToGrid(obj) this.objects.set(obj.id, obj) } - public load(rawObjects: IGameObject[]) { + public load(rawObjects: IGameObject[]) { this.objects = new Map(rawObjects.map((object) => { - const obj = GameObject.fromSnapshot(object, this.manager, this) + const obj = GameObject.fromSnapshot(object, this.manager, this) return [obj.id, obj] })) @@ -143,7 +148,7 @@ export class GameMap implements Map { * @param object - Object to add * @returns { void } */ - public addToGrid(object: GameObject): void { + public addToGrid(object: GameObject): void { const gridPosition = convertPositionToGridPosition(object.position) if (!this.grid.has(gridPosition)) this.grid.set(gridPosition, new Set([object])) @@ -155,7 +160,7 @@ export class GameMap implements Map { * @param entity - Object to delete * @returns { void } */ - public deleteFromGrid(object: GameObject): void { + public deleteFromGrid(object: GameObject): void { const gridPosition = convertPositionToGridPosition(object.position) const cell = this.grid.get(gridPosition) @@ -166,15 +171,15 @@ export class GameMap implements Map { } } - public constructor(manager: EntityManager, game: Game) { + public constructor(manager: EntityManager, game: Game) { this.manager = manager this.game = game } - public getInQuad(quad: Quad, returnType?: 'ALL'): (Entity | GameObject)[]; - public getInQuad(quad: Quad, returnType: 'ENTITES'): Entity[]; - public getInQuad(quad: Quad, returnType: 'OBJECTS'): GameObject[]; - public getInQuad(quad: Quad, returnType: 'ALL' | 'ENTITES' | 'OBJECTS'): Entity[] | GameObject[] | (Entity | GameObject)[]; + public getInQuad(quad: Quad, returnType?: 'ALL'): (Entity | GameObject)[]; + public getInQuad(quad: Quad, returnType: 'ENTITES'): Entity[]; + public getInQuad(quad: Quad, returnType: 'OBJECTS'): GameObject[]; + public getInQuad(quad: Quad, returnType: 'ALL' | 'ENTITES' | 'OBJECTS'): Entity[] | GameObject[] | (Entity | GameObject)[]; public getInQuad(quad: Quad, returnType:'ALL' | 'ENTITES' | 'OBJECTS' = 'ALL') { const [minX, minY, maxX, maxY] = quad; @@ -219,7 +224,7 @@ export class GameMap implements Map { const oldPosition = [...entity.position] as Position - entity.position = position + entity.position = position as T this.manager.updateGrid(entity, oldPosition) @@ -256,11 +261,11 @@ export class GameMap implements Map { return entity } - public getAllInPosition(position: Position, returnType?: 'ALL'): (Entity | GameObject)[]; - public getAllInPosition(position: Position, returnType: 'ENTITES'): Entity[]; - public getAllInPosition(position: Position, returnType: 'OBJECTS'): GameObject[]; - public getAllInPosition(position: Position, returnType: 'ALL' | 'ENTITES' | 'OBJECTS'): Entity[] | GameObject[] | (Entity | GameObject)[]; - public getAllInPosition(position: Position, returnType:'ALL' | 'ENTITES' | 'OBJECTS'='ALL') { + public getAllInPosition(position: Position | Position3D, returnType?: 'ALL'): (Entity | GameObject)[]; + public getAllInPosition(position: Position | Position3D, returnType: 'ENTITES'): Entity[]; + public getAllInPosition(position: Position | Position3D, returnType: 'OBJECTS'): GameObject[]; + public getAllInPosition(position: Position | Position3D,returnType: 'ALL' | 'ENTITES' | 'OBJECTS'): Entity[] | GameObject[] | (Entity | GameObject)[]; + public getAllInPosition(position: Position | Position3D, returnType:'ALL' | 'ENTITES' | 'OBJECTS'='ALL') { const gridPosition = convertPositionToGridPosition(position) const objects = Array.from(this.grid.get(gridPosition) ?? []) @@ -276,7 +281,7 @@ export class GameMap implements Map { } } - public createObject(obj: IGameObject, metadata?: T) { + public createObject(obj: IGameObject, metadata?: M) { const object = new GameObject(obj, this.manager, this, metadata ?? obj.metadata) this.objects.set(object.id, object) @@ -315,7 +320,7 @@ export class GameMap implements Map { } public getAllItems() { - return Array.from(this.objects.values()).filter(o => gameObjectIsItem(o)) + return Array.from(this.objects.values()).filter(o => gameObjectIsItem(o)) } public checkObjectOk(id: number): boolean { diff --git a/test/gametest.ts b/test/gametest.ts index 32eae41..a581347 100644 --- a/test/gametest.ts +++ b/test/gametest.ts @@ -11,7 +11,8 @@ import { useVisibility, checkTwoPositions, useValidation, useLink, useAsyncState const [game, manager, map] = createGame({ usingEntityMiddlewares: true, usingObjectMiddlewares: true, - disableConflictResolver: true + disableConflictResolver: true, + gameGeometry: "2D" }) game.registerPlugin([new RegenerationPlugin(20)])