Skip to content

Game Mechanic State pattern

Andrei Andreev edited this page Apr 28, 2019 · 6 revisions

Most of the game mechanics in AD follow similar 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, which 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 usually 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. 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. index property of state class. Allows saving up on object creation. If mechanic is GameDB-based, index should be created with mapGameData function.
  4. Accessor function. The very method of accessing state objects. Must be the name of the mechanic, e.g. Achievement, and return an item from index (based on id).
  5. (Very Optional) Additional method or getter declaration for accessor function. Very situational, most likely you want to place this functionality in the collection object (explained below). Example: NormalChallenge.current
  6. Collection object. Contains all sorts of functions for non-state-specific operations. Usually contains the all property that contains all state instances. Since mapGameData creates a sparse array, GameDB-based all should be created with compact array extension, for instance: all: AchievementState.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. `index` property of state class
NormalChallengeState.index = mapGameData(
  GameDatabase.challenges.normal,
  data => new NormalChallengeState(data)
);

// 4. Accessor function
function NormalChallenge(id) {
  return NormalChallengeState.index[id];
}

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

// 6. Collection object
const NormalChallenges = {
  all: NormalChallengeState.index.compact(),
  completeAll() {
    for (const challenge of NormalChallenges.all) challenge.complete();
  },
  ...
};

Clone this wiki locally