WarriorJS Docs
  • Player
  • Maker
  • Community
  • Deutsch
    • English
    • العربية
    • Català
    • Čeština
    • Ελληνικά
    • Español
    • Français
    • Italiano
    • Polskie
    • Русский
    • Српски језик (Ћирилица)
    • Svenska
    • Türkçe
    • 中文
    • 繁體中文
    • Hilf bei der Übersetzung
  • GitHub

›Guide

Guide

  • Einführung
  • Eigenen Turm erstellen
  • Level hinzufügen
  • Fähigkeiten definieren
  • Einheiten definieren
  • Refactoring
  • Testen
  • Veröffentlichen

Ersteller-API

  • Space API
  • Unit API
Translate

Refactoring

An dieser Stelle sollte dein Code wie folgt aussehen:

function valyrianSteelSwordAttack(unit) {
  return {
    action: true,
    description:
      'Attack a unit in the given direction (forward by default) with your Valyrian steel sword, dealing 5 HP of damage.',
    perform(direction = 'forward') {
      const receiver = unit.getSpaceAt(direction).getUnit();
      if (receiver) {
        unit.log(`attacks ${direction} and hits ${receiver}`);
        unit.damage(receiver, 5);
      } else {
        unit.log(`attacks ${direction} and hits nothing`);
      }
    },
  };
}

function iceCrystalSwordAttack(unit) {
  return {
    action: true,
    description:
      'Attack a unit in the given direction (forward by default) with your ice blade, dealing 3 HP of damage.',
    perform(direction = 'forward') {
      const receiver = unit.getSpaceAt(direction).getUnit();
      if (receiver) {
        unit.log(`attacks ${direction} and hits ${receiver}`);
        unit.damage(receiver, 3);
      } else {
        unit.log(`attacks ${direction} and hits nothing`);
      }
    },
  };
}

function feel(unit) {
  return {
    description:
      'Return the adjacent space in the given direction (forward by default).',
    perform(direction = 'forward') {
      return unit.getSensedSpaceAt(direction);
    },
  };
}

function walk(unit) {
  return {
    action: true,
    description: 'Move one space in the given direction (forward by default).',
    perform(direction = 'forward') {
      const space = unit.getSpaceAt(direction);
      if (space.isEmpty()) {
        unit.move(direction);
        unit.log(`walks ${direction}`);
      } else {
        unit.log(`walks ${direction} and bumps into ${space}`);
      }
    },
  };
}

const WhiteWalker = {
  name: 'White Walker',
  character: 'w',
  maxHealth: 12,
  abilities: {
    attack: iceCrystalSwordAttack,
    feel: feel,
  },
  playTurn(whiteWalker) {
    const enemyDirection = ['forward', 'right', 'backward', 'left'].find(
      direction => {
        const unit = whiteWalker.feel(direction).getUnit();
        return unit && unit.isEnemy();
      },
    );
    if (enemyDirection) {
      whiteWalker.attack(enemyDirection);
    }
  },
};

const Level1 = {
  description:
    "You've entered the ancient castle of Eastwatch to escape from a blizzard. But it's deadly cold inside too.",
  tip:
    "Call `warrior.walk()` to walk forward in the Player's `playTurn` method.",
  timeBonus: 15,
  aceScore: 10,
  floor: {
    size: {
      width: 8,
      height: 1,
    },
    stairs: {
      x: 7,
      y: 0,
    },
    warrior: {
      character: '@',
      maxHealth: 20,
      position: {
        x: 0,
        y: 0,
        facing: 'east',
      },
      abilities: {
        walk: walk,
      },
    },
  },
};

const Level2 = {
  description:
    'The cold became more intense. In the distance, you see a pair of deep and blue eyes, a blue that burns like ice.',
  tip:
    "Use `warrior.feel().isEmpty()` to see if there's anything in front of you, and `warrior.attack()` to fight it. Remember, you can only do one action per turn.",
  clue:
    'Add an if/else condition using `warrior.feel().isEmpty()` to decide whether to attack or walk.',
  timeBonus: 20,
  aceScore: 26,
  floor: {
    size: {
      width: 8,
      height: 1,
    },
    stairs: {
      x: 7,
      y: 0,
    },
    warrior: {
      character: '@',
      maxHealth: 20,
      position: {
        x: 0,
        y: 0,
        facing: 'east',
      },
      abilities: {
        attack: valyrianSteelSwordAttack,
        feel: feel,
      },
    },
    units: [
      {
        ...WhiteWalker,
        position: {
          x: 4,
          y: 0,
          facing: 'west',
        },
      },
    ],
  },
};

module.exports = {
  name: 'Game of Thrones',
  description:
    'There is only one war that matters: the Great War. And it is here.',
  levels: [Level1, Level2],
};

Wie bei der Definierung des Weißen Wanderers können wir die gemeinsamen Felder des Kämpfers in ein Objekt auslagern und dann Spread-Properties verwenden, um sie jedem Level hinzuzufügen:

const Warrior = {
  character: '@',
  maxHealth: 20,
};

const Level1 = {
  description:
    "You've entered the ancient castle of Eastwatch to escape from a blizzard. But it's deadly cold inside too.",
  tip:
    "Call `warrior.walk()` to walk forward in the Player's `playTurn` method.",
  timeBonus: 15,
  aceScore: 10,
  floor: {
    size: {
      width: 8,
      height: 1,
    },
    stairs: {
      x: 7,
      y: 0,
    },
    warrior: {
      ...Warrior,
      abilities: {
        walk: walk,
      },
      position: {
        x: 0,
        y: 0,
        facing: 'east',
      },
    },
  },
};

const Level2 = {
  description:
    'The cold became more intense. In the distance, you see a pair of deep and blue eyes, a blue that burns like ice.',
  tip:
    "Use `warrior.feel().isEmpty()` to see if there's anything in front of you, and `warrior.attack()` to fight it. Remember, you can only do one action per turn.",
  clue:
    'Add an if/else condition using `warrior.feel().isEmpty()` to decide whether to attack or walk.',
  timeBonus: 20,
  aceScore: 26,
  floor: {
    size: {
      width: 8,
      height: 1,
    },
    stairs: {
      x: 7,
      y: 0,
    },
    warrior: {
      ...Warrior,
      abilities: {
        attack: valyrianSteelSwordAttack,
        feel: feel,
      },
      position: {
        x: 0,
        y: 0,
        facing: 'east',
      },
    },
    units: [
      {
        ...WhiteWalker,
        position: {
          x: 4,
          y: 0,
          facing: 'west',
        },
      },
    ],
  },
};

In Bezug auf die Fähigkeiten können wir feststellen, dass beide Angriff-Fähigkeiten sehr ähnlich sind. Da können wir etwas gegen tun:

function attackCreator({ power, weapon }) {
  return unit => ({
    action: true,
    description: `Attack a unit in the given direction (forward by default) with your ${weapon}, dealing ${power} HP of damage.`,
    perform(direction = 'forward') {
      const receiver = unit.getSpaceAt(direction).getUnit();
      if (receiver) {
        unit.log(`attacks ${direction} and hits ${receiver}`);
        unit.damage(receiver, power);
      } else {
        unit.log(`attacks ${direction} and hits nothing`);
      }
    },
  });
}

const valyrianSteelSwordAttack = attackCreator({
  power: 5,
  weapon: 'Valyrian steel sword',
});

const iceCrystalSwordAttack = attackCreator({
  power: 3,
  weapon: 'ice blade',
});

Wir nennen dies das "Ability Creator"-Muster, bei dem wir eine Funktion (den Ability-Creator) definieren, die eine andere Funktion angepasst anhand der übergebenen Paramater zurückgibt (die Fähigkeit).

Um das Refactoring abzuschließen, lass uns alle Magic-Strings loswerden, die Richtungen angeben. Es gibt ein offizielles Package namens @warriorjs/geography, das eine Reihe von Konstanten und Methoden in Bezug auf Richtungen bereit stellt. Lass uns das nutzen:

const {
  EAST,
  FORWARD,
  RELATIVE_DIRECTIONS,
  WEST,
} = require('@warriorjs/geography');

function attackCreator({ power, weapon }) {
  return unit => ({
    action: true,
    description: `Attack a unit in the given direction (forward by default) with your ${weapon}, dealing ${power} HP of damage.`,
    perform(direction = FORWARD) {
      const receiver = unit.getSpaceAt(direction).getUnit();
      if (receiver) {
        unit.log(`attacks ${direction} and hits ${receiver}`);
        unit.damage(receiver, power);
      } else {
        unit.log(`attacks ${direction} and hits nothing`);
      }
    },
  });
}

const valyrianSteelSwordAttack = attackCreator({
  power: 5,
  weapon: 'Valyrian steel sword',
});

const iceCrystalSwordAttack = attackCreator({
  power: 3,
  weapon: 'ice blade',
});

function feel(unit) {
  return {
    description:
      'Return the adjacent space in the given direction (forward by default).',
    perform(direction = FORWARD) {
      return unit.getSensedSpaceAt(direction);
    },
  };
}

function walk(unit) {
  return {
    action: true,
    description: 'Move one space in the given direction (forward by default).',
    perform(direction = FORWARD) {
      const space = unit.getSpaceAt(direction);
      if (space.isEmpty()) {
        unit.move(direction);
        unit.log(`walks ${direction}`);
      } else {
        unit.log(`walks ${direction} and bumps into ${space}`);
      }
    },
  };
}

const Warrior = {
  character: '@',
  maxHealth: 20,
};

const WhiteWalker = {
  name: 'White Walker',
  character: 'w',
  maxHealth: 12,
  abilities: {
    attack: iceCrystalSwordAttack,
    feel: feel,
  },
  playTurn(whiteWalker) {
    const enemyDirection = RELATIVE_DIRECTIONS.find(direction => {
      const unit = whiteWalker.feel(direction).getUnit();
      return unit && unit.isEnemy();
    });
    if (enemyDirection) {
      whiteWalker.attack(enemyDirection);
    }
  },
};

const Level1 = {
  description:
    "You've entered the ancient castle of Eastwatch to escape from a blizzard. But it's deadly cold inside too.",
  tip:
    "Call `warrior.walk()` to walk forward in the Player's `playTurn` method.",
  timeBonus: 15,
  aceScore: 10,
  floor: {
    size: {
      width: 8,
      height: 1,
    },
    stairs: {
      x: 7,
      y: 0,
    },
    warrior: {
      ...Warrior,
      abilities: {
        walk: walk,
      },
      position: {
        x: 0,
        y: 0,
        facing: EAST,
      },
    },
  },
};

const Level2 = {
  description:
    'The cold became more intense. In the distance, you see a pair of deep and blue eyes, a blue that burns like ice.',
  tip:
    "Use `warrior.feel().isEmpty()` to see if there's anything in front of you, and `warrior.attack()` to fight it. Remember, you can only do one action per turn.",
  clue:
    'Add an if/else condition using `warrior.feel().isEmpty()` to decide whether to attack or walk.',
  timeBonus: 20,
  aceScore: 26,
  floor: {
    size: {
      width: 8,
      height: 1,
    },
    stairs: {
      x: 7,
      y: 0,
    },
    warrior: {
      ...Warrior,
      abilities: {
        attack: valyrianSteelSwordAttack,
        feel: feel,
      },
      position: {
        x: 0,
        y: 0,
        facing: EAST,
      },
    },
    units: [
      {
        ...WhiteWalker,
        position: {
          x: 4,
          y: 0,
          facing: WEST,
        },
      },
    ],
  },
};

module.exports = {
  name: 'Game of Thrones',
  description:
    'There is only one war that matters: the Great War. And it is here.',
  levels: [Level1, Level2],
};

Viel besser! Lese weiter, um zu lernen deinen Turm zu testen und zu veröffentlichen, sodass auch andere Spieler ihn spielen können!

← Einheiten definierenTesten →
WarriorJS Docs
Docs
PlayerMaker
Community
SpectrumTwitterFollow WarriorJS on Twitter
More
DonateGitHubStar