-
Notifications
You must be signed in to change notification settings - Fork 265
Game Mechanic State pattern
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.
- (Optional) GameDB declaration. For game mechanics that have configurable elements. Reference: https://github.com/IvarK/HahaSlabWontGetHere/wiki/How-to-GameDatabase-(draft)
- 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. -
indexproperty of state class. Allows saving up on object creation. If mechanic is GameDB-based,indexshould be created withmapGameDatafunction. - Accessor function. The very method of accessing state objects. Must be the name of the mechanic, e.g.
Achievement, and return an item fromindex(based on id). - (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 - Collection object. Contains all sorts of functions for non-state-specific operations. Usually contains the
allproperty that contains all state instances. SincemapGameDatacreates a sparse array, GameDB-basedallshould be created withcompactarray extension, for instance:all: AchievementState.index.compact()
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();
},
...
};