Skip to content

Game Mechanic State pattern

Andrei Andreev edited this page Dec 14, 2019 · 6 revisions

Most of the game mechanics in AD follow consistent logic and structure. Based on this assumption, we created a framework for working with them in the form of GameMechanicState class which simplified and made cleaner game state access all over the code. This generalization also works in favor of Effects system that is explained here: https://github.com/IvarK/HahaSlabWontGetHere/wiki/Effects-system-explained

But, the game mechanic declaration doesn't consist only of state class - additionally we need to bind gameDB configs, add declaration function, add some additional functions/accessors that are tightly coupled with the game mechanic. Currently, there's no standard for such declarations and the following pattern is expected to give the guidelines for a consistent game mechanic code.

Structure

  1. (Optional) GameDB declaration. For game mechanics that have configurable elements. Reference: https://github.com/IvarK/HahaSlabWontGetHere/wiki/How-to-GameDatabase-(draft)
  2. State class that extends GameMechanicState. This is a staple element between player object (PO) and game logic that allows separation of PO structure from logic code.
  3. Accessor object created with the createAccessor function. It has index property which contains all the GameDB entries wrapped into State class instances. Apart from that it is itself a callable function which accepts an index as an argument. Example: Achievement(101). This is the very method which should be used when accessing state objects in game logic code.
  4. (Very Optional) Additional method or getter declaration for Accessor object. Very situational, most likely you want to place this functionality in the collection object (explained below). Example: NormalChallenge.current
  5. Collection object. Contains all sorts of functions for non-state-specific operations. Usually contains the all property that contains all state instances. Since createAccessor creates a sparse array, GameDB-based all should be created with compact array extension, for instance: all: Achievement.index.compact()

Example

GameDB file

// 1. GameDB declaration
GameDatabase.challenges.normal = [
  {
    id: 1,
    legacyId: 1,
    isQuickResettable: false,
    description: "Reach Infinity for the first time.",
    reward: "First Dimension Autobuyer"
  },
  ...
};

File with game logic

// 2. Class that extends `GameMechanicState`
class NormalChallengeState extends GameMechanicState {
  constructor(config) {
    super(config);
    ...
  }
  ...
}

// 3. Accessor object
/**
 * @param {number} id
 * @return {NormalChallengeState}
 */
const NormalChallenge = NormalChallengeState.createAccessor(GameDatabase.challenges.normal);

// 4. Additional method or getter declaration for Accessor object
Object.defineProperty(NormalChallenge, "current", {
  get: () => (player.challenge.normal.current > 0
    ? NormalChallenge(player.challenge.normal.current)
    : undefined),
});

// 5. Collection object
const NormalChallenges = {
  /** @type {NormalChallengeState[]} */
  all: NormalChallenge.index.compact(),
  completeAll() {
    for (const challenge of NormalChallenges.all) challenge.complete();
  },
  ...
};

Clone this wiki locally