0.0.20 • Published 4 years ago

@meka-js/core v0.0.20

Weekly downloads
19
License
MIT
Repository
-
Last release
4 years ago

meka-core

The meka-core library is written in Typescript and includes all of the MEKA game engine logic.

Getting started

Install meka-core via Yarn:

yarn add @meka-js/core

And import classes from the library using es6:

import { Game, Team } from "@meka-js/core";

If you'd like to see example code that uses meka-core, check out meka-boilerplate. Otherwise, read on for documentation about the game engine, classes, and helper functions.

Classes

Game

The Game class is the source of truth for the game, holding references to all relevant data.

Properties

id: string

The ID of the game, used across MEKA.

width: number

The width of the game in number of positions. The left-most position has property x set to 0, and the right-most position has x value of width - 1.

height: number

The height of the game in number of positions. The top position has y set to 0, and the bottom position has y of height - 1.

turn: number

While MEKA is a real-time strategy game, actions are still batched into turns. Turns proceed in ascending order from 0 upwards.

teams: Team[]

An array of the teams competing in the game. Each is structured as a Team.

wallsList: Wall[]

An array of walls, each structured as a Wall.

foodsList: Food[]

An array of food objects, each structured as a Food.

citizensList: Citizen[]

An array of citizens, each structured as a Citizen. The list includes citizens from both teams.

fightersList: Fighter[]

An array of fighters, each structured as a Fighter. The list includes fighters from both teams. The Fighter class is an abstract class, so each fighter object is actually either InfantryFighter, RangedFighter or CavalaryFighter (all extensions of Fighter).

hqsList: HQ[]

An array of HQs, each structured as an HQ. The list includes the HQs from both teams.

isOver: boolean

Returns true if the game is over.

winnerId: string | null | undefined

The ID of the winning team (if applicable). If undefined, the game is still in progress. If null, the game is a draw.

positions: Position[]

An array of all positions on the game map, each structured as a Position.

lookup: {[id: string]: Unit | Food}

A map for looking up an arbitrary HQ, citizen, fighter, or food by its ID.

Methods

getTeam(teamId: string): Team

Look up a team by its ID.

Position

The Position class wraps a particular x, y coordinate pair. Nearly everything in MEKA has a position.

import { Position } from "@meka-js/core";
const position = new Position(2, 5);

Properties

x: number

The x coordinate for the position.

y: number

The y coordinate for the position.

key: string

A standardized key that is used in maps indexed by positions, like foods on Game. Returns a string of format <x>,<y>.

adjacents: Position[]

Returns list of directly adjacent positions. For example:

const position = new Position(4, 4);
position.adjacents
> [
  Position { x: 5, y: 4 },
  Position { x: 3, y: 4 },
  Position { x: 4, y: 5 },
  Position { x: 4, y: 3 }
]

Methods

isEqualTo(position: Position | PositionJSON): boolean

Compares position with another position (either as an instance of Position or serialized Position).

isAdjacentTo(position: Position): boolean

Checks whether position is adjacent to provided position (structured as Position).

isAdjacentToAny(positions: Position[] | Position): boolean

Takes any number of positions and checks whether any of them are adjacent to the position.

adjacentsWithinDistance(distance: number): Position[]

Like the adjacents property, but it returns a list of positions that are within distance steps from the position.

ObjectWithPosition

The ObjectWithPosition is a generic class extended by classes which have a position, like Food, Citizen, Fighter, and HQ. All of the properties and methods below are available in those classes too.

Properties

position: Position

The position of the object.

key: string

The key property of the object's position.

x: number

The x coordinate of the object's position.

y: number

The y coordinate of the object's position.

width: number

The number of positions the object covers on the x-axis.

height: number

The number of positions the object covers on the y-xis.

covering: Position[]

An array of the positions covered by the object. Note that instances of ObjectWithPosition are anchored to their top-left corner. So an HQ with position {x: 2, y: 2}, width 2, and height 2 would cover {x: 2, y: 2}, {x: 3, y: 2}, {x: 2, y: 3}, and {x: 3, y: 3}.

Food

The Food class represents the primary resource in MEKA. Food can be collected by citizens, dropped off at HQs, and used to pay for spawning new units. Food is an extension of ObjectWithPosition, so it has access to all the same properties.

Properties

id: string

The ID of the food, which is used to reference the food when it's picked up by a citizen or looked up in Game#lookup.

eatenBy: Citizen

If the food has been collected (or "eaten") by a citizen, eatenBy will return that citizen.

Wall

Walls are blockages on the map, and units or food cannot be placed on positions with a wall. The Wall class extends ObjectWithPosition, so all properties and methods from ObjectWithPosition are available on an instance of Wall too. Note that while a unit cannot move through a wall, ranged fighters can still attack over a wall.

Team

The Team class holds information about each player and references to that team's units and HQ.

Properties

id: string

The ID of the team. This ID is the same as the given user's ID.

color: string

The color of the team. This is used primarily for rendering on the game map.

pop: number

Returns the population of the team, including citizens and fighters.

hq: HQ

A reference for the team's HQ. Each team has one HQ.

citizens: Citizen[]

An array of citizens for the team.

fighters: Fighter[]

An array of fighters for the team. This list includes fighters of all types: InfantryFighter, RangedFighter, and CavalryFighter.

foodCount: number

Returns the amount of food the team has available to spend. This number increases when citizens drop-off additional food.

settings: SettingsObject

Returns an object with default values for the cost, speed, HP, range, and attack damage of each unit. You can use this object for checking the cost of future units, for instance. Here's the default for a team:

{
  cost: {
    Citizen: 2,
    InfantryFighter: 4,
    RangedFighter: 4,
    CavalryFighter: 3
  },
  speed: {
    Citizen: 1,
    InfantryFighter: 1,
    RangedFighter: 1,
    CavalryFighter: 2
  },
  baseHP: {
    Citizen: 10,
    HQ: 500,
    InfantryFighter: 32,
    RangedFighter: 24,
    CavalryFighter: 30
  },
  range: {
    HQ: 3,
    InfantryFighter: 1,
    RangedFighter: 3,
    CavalryFighter: 1
  },
  baseAttackDamage: {
    HQ: 6,
    InfantryFighter: 10,
    RangedFighter: 7,
    CavalryFighter: 6
  }
}

Citizen

Citizens are responsible for collecting food. They don't have any attack ability, but they're the only unit that can pick-up food. In a typical game, each team starts with one citizen. The Citizen class extends ObjectWithPosition, so all properties and methods on ObjectWithPosition are also available on Citizen.

Properties

id: string

The ID for the citizen, used for identification across the game.

food: Food

If a citizen has collected a food, the food property will return it.

validMoves: Position[]

An array of adjacent positions that would be valid moves for the citizen. Note that a citizen cannot move onto a wall, onto another unit, or onto the opponent's HQ (though it can be positioned on its own HQ).

team: Team

Returns the citizen's team.

hp: number

The current hit points (HP) of the citizen.

baseHP: number

The original hit points (HP) of the citizen. Citizen's normally start with 10 HP, as you can see in the team's settings object.

speed: number

The speed of the citizen, structured as positions available to move per tick. The default is 1.

Methods

getPathTo(position: Position)

If a path is available from the citizen's position to the position argument, this method returns that path as an array of positions. The first position in the array is the citizen's current position, the second position is the first move, and the last position is the target position. If no path is available, this method returns null.

getPathToTarget(target: Unit)

Returns the shortest path from the citizen's current position to any of the positions covered by the specified target. For instance, if an instance of HQ with width of 2 and height of 2 is passed as target, then this method will return the shortest path to any of the HQs four positions.

Fighter

The Fighter class is not itself a class, but there are various properties and methods shared by the fighter classes: InfantryFighter, RangedFighter, and CavalryFighter. All fighter classes extend ObjectWithPosition, so all properties and methods on ObjectWithPosition are also available in Fighter.

Properties

id: string

The ID for the fighter.

className: ["InfantryFighter", "CavalryFighter", "RangedFighter"]

The child class name of the fighter (i.e. "InfantryFighter").

team: Team

The team for the fighter.

baseAttackDamage: number

The fighter's default damage when attacking another unit. Note that fighters have attack bonuses versus other fighter classes. Here is a table of the default HP, attack, and bonus for the three fighter classes:

UnitClassHPAttackBonus
InfantryInfantryFighter3210+5 against Cavalry
CavalryCavalryFighter306+6 attack against Ranged
RangedRangedFighter247+4 attack against Infantry

hp: number

The current hit points (HP) for the fighter.

baseHP: number

The original hit points (HP) for the fighter.

speed: number

The speed (represented as positions to move per tick) of the fighter.

range: number

The range (represented as number of positions) of the fighter.

validMoves: Position[]

An array of in-range positions that would be valid moves for the fighter.

Methods

isValidMove(position: Position): boolean

Checks whether the given position would be a valid move for the fighter.

isValidAttack(target: Unit, position: Position): boolean

Checks whether the given target and position would be a valid attack, meaning the target is in range and the given position would hit the target.

getAttackPositionsFor(unit: Unit): Position[]

Returns an array of positions from which the fighter can attack the given unit. For a fighter of range 1 (like infantry or cavalry), this method returns the positions adjacent to the target unit. However, there are more options for a ranged fighter, for instance.

getPathTo(position: Position): Position[]

Returns an array of positions representing a path from the fighter's current position to the given position. The first position in the array is the fighter's current position, the last position is the target position, and each position in between represents a step in the path. If the method returns null, it means there is no current path between the two positions.

getPathToTarget(target: Unit): Position[]

Returns an array of positions representing the shortest path to any of the positions covered by the given target.

HQ

The HQ class. The HQ class extends ObjectWithPosition, so all properties and methods on ObjectWithPosition are also available on HQ. By default instances of HQ have width of 2 and height of 2.

Properties

id: string

The ID of the HQ.

hp: number

The current hit points (HP) for the HQ.

baseHP: number

The original hit points (HP) for the HQ.

baseAttackDamage: number

The HQ's default damage when attacking another unit. While fighters have attack bonuses versus other classes, the HQ has the same attack against all types. The default is 6.

range: number

The range (represented as number of positions) of the HQ.

team: Team

The HQ's team.

nextSpawnPosition: Position

Returns one of the unoccupied positions covered by the HQ, selected at random. If there are no open positions, this property returns null.

Methods

isValidAttack(target: Unit, position: Position): boolean

Checks whether the given target and position would be a valid attack, meaning the target is in range of the HQ and the given position would hit the target.

Command

There are multiple types of commands that extend a shared AbstractCommand class: MoveCommand, AttackCommand, SpawnCommand, DropOffFoodCommand, and PickUpFoodCommand. When a command is processed, it provides the game engine with an action (see types of actions below), depending on the current state of the game.

Properties

id: string

The ID of the command.

unit: Unit

The unit is the subject of the command (i.e. the unit who is performing an action as a result of the command).

args: {...}

The args object provides the command with whatever custom data is needed for execution. Each child command specifies its own format for args.

MoveCommand

The MoveCommand tells a unit to move to a particular position. The unit for MoveCommand should be a Fighter or Citizen.

args format

{
  position: Position;
  autoPickUpFood?: boolean = false;
  autoDropOffFood?: boolean = false;
}

The position is the position the unit should move to. If autoPickUpFood (default is false) is set to true and the unit is a citizen, the citizen will pick-up food if it moves over it. If autoDropOffFood (default is false) is set to true and the unit is a citizen, the citizen will drop-off food when it moves over its own HQ and has foo to drop-off.

getNextAction(game: Game): MoveCitizenAction | MoveFighterAction

An instance of MoveCommand will try to create a MoveAction each tick. If a path cannot be found between the unit's current position and args.position, no action is returned.

Example

const citizen = new Citizen(...)
const position = new Position(...)
const command = new MoveCommand({ unit: citizen, args: { position: position } })

AttackCommand

The AttackCommand tells a unit to attack a particular target unit. The unit for AttackCommand should be a Fighter or HQ.

args format

{
  targetId: string;
}

targetId is the ID of the target unit.

getNextAction(game: Game): MoveFighterAction | AttackAction

If the target is in range of the unit, the command will return an AttackAction. Otherwise (and only if the unit is a fighter) it will try to find a path to a position in range of the target and return a MoveFighterAction with the next move in that path.

Example

const fighter = new InfantryFighter(...)
const enemyFighter = new CavalryFighter(...)
const command = new AttackCommand({ unit: fighter, args: { targetId: enemyFighter.id } })

SpawnCommand

The SpawnCommand tells an HQ (the unit) to spawn (i.e. create) a new unit.

args format

{
  position?: Position;
  unitType: "Citizen" | "InfantryFighter" | "RangedFighter" | "CavalryFighter";
}

The position argument is optional, but if it is included, the command will try to spawn the new unit on the given position if it is one of the positions covered by the HQ. The unitType argument specifies what kind of unit to spawn.

getNextAction(game: Game): SpawnCitizenAction | SpawnFighterAction

If the HQ has enough food to pay for the new unit, this method returns either a SpawnCitizenAction or a SpawnFighterAction.

Example

const hq = new HQ(...)
const command = new SpawnCommand({ unit: hq, args: { unitType: "RangedFighter" } })

PickUpFoodCommand

The PickUpFoodCommand tells a citizen (as unit) to pick-up a given food.

args format

{
  foodId: string;
}

The foodId argument is the ID of the food to pick-up.

getNextAction(game: Game): PickUpFoodAction | MoveCitizenAction

If the specified food is adjacent to the citizen, the command returns a PickUpFoodAction. Otherwise, the shortest path to a position adjacent to the given food is found, and a MoveCitizenAction is returned. If no path is found, no action is returned.

Example

const citizen = new Citizen(...)
const food = new Food(...)
const command = new PickUpFoodCommand({ unit: citizen, args: { foodId: food.id } });

DropOffFoodCommand

The DropOffFoodCommand tells a citizen (as unit) to drop-off their food at a position or HQ.

args format

{
  position?: Position;
  hqId?: string;
}

Either position or hqId must be included. A citizen can drop-off a food at an arbitrary position, which is specified by position. Otherwise, hqId specifies the HQ where the food should be dropped off.

getNextAction(game: Game): DropOffFoodAction | MoveCitizenAction

If the citizen is adjacent to the HQ or drop-off position, a DropOffFoodAction is returned by the command. Otherwise, a path is found from the citizen's current position to a position adjacent to the drop-off spot and MoveCitizenAction is returned. If no path is found, no action is returned.

Example

const citizen = new Citizen(...) // Citizen has food
const hq = new HQ(...)
const command = new DropOffFoodCommand({ unit: citizen, args: { hqId: hq.id } });

commandFromJSON(game: Game, json: CommandJSON): Command

To de-serialize a command, you can look at the className property to determine the right constructor. Or you can use the commandfromJSON helper function, which will select the right command class for you and return the command.

Action

Actions are how the game state is mutated. Each tick, commands provide the game with actions based on the current state. Actions can also be used to recreate the state of a game.

Properties

id: string

The ID of the action.

command: Command

A reference to the command that initiated the action.

unit: Unit

The unit responsible for undertaking the action.

args: AbstractActionArgs

An object with data particular to the given action class.

className: string

A string representation of the action child class (i.e. "AttackAction").

AttackAction

AttackAction executes an attack from the unit to a target. The response is the new state of the target.

DropOffFoodAction

DropOffFoodAction directs a citizen (as unit) to drop-off food at a position. The response is the new state of the citizen.

MoveCitizenAction

MoveCitizenAction directs a citizen to move to a position. The response is the new state of the citizen.

MoveFighterAction

MoveFighterAction directs a fighter to move to a position (within the range of its speed). The response is the new state of the fighter.

PickUpFoodAction

PickUpFoodAction directs a citizen to pick-up a food at a particular position. The response is the new state of the citizen.

SpawnCitizenAction

SpawnCitizenAction executes a spawn of a new citizen by an HQ. The response is the newly spawned citizen.

SpawnFighterAction

SpawnFighterAction executes a spawn of a new fighter by an HQ. The response is the newly spawned fighter.

actionFromJSON(game: Game, json: ActionJSON): Action

If you want to de-serialize an action, you can look at the className property to determine the right constructor. Or you can use actionfromJSON, which will select the right action class for you and return the action.

CommandResponse

The CommandResponse class is used to tell a user what happened for a particular command.

Properties

command: Command

The command that this object is in response to.

status: "success" | "failure"

The status of the command. A failure status either means no action was generated for the command or there was an issue with the action. A success status means the associated action was implemented in the game.

action?: Action

The action created by the command.

error?: string

Any error message for describing why the command or action may have failed.

Helpers

isInBounds(game: Game, position: Position): boolean

The isInBounds helper function checks whether a position is inside the game board.

import { isInBounds } from "@meka-js/core";

const game = new Game({width: 10, height: 10});
const inPosition = new Position(2, 2);
const outPosition = new Position(20, 20);
isInBounds(game, inPosition); // TRUE
isInBounds(game, outPosition); // FALSE

isValidPosition(game: Game, position: Position, teamId?: string)

The isValidPosition function checks whether a position is available for a unit to move to. The function will return false if the position is out of bounds, has a wall, has another unit, or has an HQ. The one exception is when teamId is specified, a position inside the team's HQ will be valid when it otherwise would not. A position with a food will be valid, because units can move on top of foods.

isValidFoodPosition

The isValidFoodPosition function checks whether a position is available for a food to be placed. The function will return false if the position is out of bounds, has a wall, or has another food already on it.

0.0.20

4 years ago

0.0.19

4 years ago

0.0.18

4 years ago

0.0.17

4 years ago

0.0.16

4 years ago

0.0.15

4 years ago

0.0.14

4 years ago

0.0.13

4 years ago

0.0.12

4 years ago

0.0.11

4 years ago

0.0.10

4 years ago

0.0.9

4 years ago

0.0.8

4 years ago

0.0.7

4 years ago

0.0.6

4 years ago

0.0.5

4 years ago

0.0.3

4 years ago

0.0.4

4 years ago

0.0.2

4 years ago