Если вы читали мой предыдущий пост об определении объектов в JavaScipt с помощью замыканий, я подумал, что рабочий пример может помочь. Это основано на коде, который я написал вместе со своим сыном, чтобы помочь ему понять программирование и сделать его интересным. Он решил создать простое приключение из командной строки в стиле 80-х, в котором вам нужно выбраться из лабиринта, находя предметы и сражаясь с монстрами.

Во-первых, мы определяем объект игрока. У игрока есть уровень опыта, сумка для хранения предметов и оружие. Изначально оружие - это их рука - игроку лучше не наезжать ни на что опасное! Мы также определяем несколько видов оружия и их силу.

const character = function(who, attrib) {
    attrib = attrib || {};
    const _name = who;
    const dv = (value,def ) 
           => (typeof value === "undefined")?def:value;
    let _hp = dv( attrib.hp, 10 );
    let _level = dv( attrib.level, 1 );
    const _bag = [];
    let _weapon =  dv( attrib.weapon, "hand");

    const weapons = {
        "hand": 1,
        "Iron Sword" : 2,
        "Diamond Sword" : 5,
        "Hammer" : 2
    }

    function name() {
        return _name;
    }
    function hit() {
        _hp -= 1;
    }
    function dead() {
        return _hp === 0
    }
    function stash( item ) {
        if( weapons[item])
        {
            console.log( "You found the " + item );
            setWeapon( item )
        }
        else {
            console.log("You found the " + item 
                + " and placed it in your bag");
            _bag.push( item );
        }
    }
    function has( item ) {
        return _bag.includes( item );
    }
    function getWeapon() {
        return _weapon;
    }
    function getWeaponStat() {
        return weapons[_weapon]
    }
    function setWeapon( item ) {
        if (weapons[_weapon] < weapons[item]) {
            console.log("You use the " + item);
            _weapon = item;
        }
    }
    function level() {
        return _level;
    }
    function levelUp() {
        _level += 1;
    }
    return { name, stash, has, getWeapon, getWeaponStat, 
             hit, dead, level, levelUp }
}

Мы также реализовали несколько вспомогательных методов; Мы можем спросить игрока: «Ты мертв?», «На каком ты уровне?», Мы можем «спрятать» предмет и нанести некоторый урон, вызвав удар. Если спрятанный предмет оказался оружием, мы проверяем, не «лучше» ли оно, чем наше старое, и заменяем его. Есть еще несколько помощников, к которым мы вернемся позже.

Если бы я писал здесь производственный код, я бы также написал набор тестовых примеров, чтобы доказать, что логика работает правильно и, что немаловажно, что код обрабатывает некачественный ввод.

Поскольку мы не хотим, чтобы у всех персонажей были одинаковые атрибуты, мы зададим их через конструктор. Для этого передадим структуру. Вы заметите, что я определил небольшую вспомогательную анонимную функцию (лямбда), чтобы проверить, есть ли в структуре attrib переопределения. Это то, что делает верхняя часть этого кода. Я также по умолчанию использую случай с нулевым атрибутом.

const character = function(who, attrib) {
    attrib = attrib || {};
    const _name = who;
    const dv = (value,def ) => 
          (typeof value === "undefined")?def:value;
    let _hp = dv( attrib.hp, 10 );

Теперь мы можем создать несколько персонажей.

const person = character( “You” );
const npc = character( “Grump Ork”, { hp : 5, weapon : “Hammer” } );

Предположим, вам не нравится «Сварливый орк» или, возможно, они нападают на вас. Нам нужен распорядок боя.

Создаем небольшую процедуру, имитирующую бросок кубика, d12 + модификатор

// dieroll simulates a die roll, d12 + a modifier
function dieroll( level )
{
    const rand = ( num ) => Math.floor( Math.random() * num )
    return rand( 12 ) + rand( level );
}

Затем мы определяем функцию, которая для двух персонажей имитирует драку между ними.

function fight( char1, char2 ) {
    while (true) {
        const c1roll = dieroll(char1.level()) + char1.getWeaponStat();
        const c2roll = dieroll(char2.level()) + char2.getWeaponStat();

        if (c1roll < c2roll) {
            char1.hit();
            console.log( char2.name() 
                   + " strikes the " + char1.name());
        } else if ( c1roll > c2roll ) {
            char2.hit()
            console.log( char1.name() 
                   + " strikes the " + char2.name());
        } else {
            console.log( " again " );
        }

        if (char1.dead()) {
            console.log( char1.name() 
                   + " is dead, killed by the " + char2.name());
            return true;
        }
        if (char2.dead()) {
            console.log( char2.name() 
                   + " is dead, killed by the " + char1.name());
            return false;
        }
    }
}

Последний шаг - создать пару персонажей и заставить их сражаться.

const you = character( “Player” );
const npc = character( “Grump Ork”, { hp : 5, weapon : “Hammer” } );
fight( you, npc );

Поместите весь этот код в один скрипт и запустите под Node.js.

Grump Ork strikes the Player
Player strikes the Grump Ork
Player strikes the Grump Ork
Player strikes the Grump Ork
Player strikes the Grump Ork
Grump Ork strikes the Player
Grump Ork strikes the Player
Player strikes the Grump Ork
Grump Ork is dead, killed by the Player

Если вы хотите быть уверены, что у вас больше шансов на победу, дайте себе лучшее оружие.

you.stash( “Iron Sword”);
fight( you, npc );

И снова беги; вы все равно можете проиграть.

You found the Iron Sword
Player strikes the Grump Ork
Grump Ork strikes the Player
Player strikes the Grump Ork
again
Player strikes the Grump Ork
Player strikes the Grump Ork
Grump Ork strikes the Player
Grump Ork strikes the Player
Player strikes the Grump Ork
Grump Ork is dead, killed by the Player

На этом пока все; в следующей части мы добавим лабиринт и начнем выстраивать остальные игровые взаимодействия.

Больше контента на plainenglish.io

Для знакомства с используемым стилем