Уважаемые пользователи Голос!
Сайт доступен в режиме «чтение» до сентября 2020 года. Операции с токенами Golos, Cyber можно проводить, используя альтернативные клиенты или через эксплорер Cyberway. Подробности здесь: https://golos.io/@goloscore/operacii-s-tokenami-golos-cyber-1594822432061
С уважением, команда “Голос”
GOLOS
RU
EN
UA
rassen
7 лет назад

Стать программистом. Практика JavaScript для новичков. Занятие 16. ФИНАЛ.

Доброго времени суток, друзья!

В нашем прошлом занятии мы с Вами закрыли список задач по Питомцу. Теперь наш Мураш отлично имитирует самостоятельность в выборе того или иного действия, но нас это устраивает. В конце концов написать настоящий Skynet используя JavaScript у нас может бы и вышло, но времени это бы заняло значительно больше. Кроме того за Вами должок по оптимизации методов startPlay() и startSleep(), stopPlay() и stopSleep(). У Вас уже достаточно знаний, чтобы справиться с это несложной задачей.

По сути для завершения нашего проекта нам осталось сделать несколько шагов. Давайте начнём!

Стать программистом. Практика JavaScript для новичков. Занятие 16.

Смотрите, теперь у нас есть функциональность для работы счетчиков, уровень которых пользователь поддерживает с помощью четырёх кнопок в правом верхнем углу и у нас есть функциональность, которая отвечает за поведение нашего Питомца. Чего у нас нет, так это того, чтобы обе эти функциональности запускали при загрузке окна. Давайте ее добавим.

Сделали мы это просто, в нашем объекте {Booth} в файле booth.js у нас есть метод startGame(). Там уже присутствовали два метода для запуска наших счетчиков, мы же просто добавили туда вызов основного метода для нашего Муравья. То есть для того чтобы наша игра началась, нам просто надо вызвать где-то это метод. Я предлагаю особо не заморачиваться и вызвать его прямо в нашем index.html. Вот таким образом:

И теперь при загрузке нашего index.html или обновлении окна у нас сразу же будет начинаться игра.

Как видим, всё пришло в движение. Отлично! Как говаривали в классике ужасов: «It’s a life!». Далее, логично предположить что, раз у нас есть метод startGame() то должен быть и метод для её прекращения. Потому что сейчас у нас дело обстоит так:

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

Как мы видим это организовать тоже не сложно. У нас есть ссылка на интервал для выбора действия и мы просто передаём её параметром в наше метод stopAllActions() используя метод stopInterval(). То есть получается что, когда один из счетчиков закончился, нам надо вызвать метод stopAllActions() для остановки муравья. Давайте реализуем это.

В объекте {Booth} мы создали метод gameOver(), где вызвали остановку нашего Питомца, и сам метод перенесли в место где, останавливаются все счетчики (Оранжевая стрелка). Давайте теперь проверим, остановится ли муравей, если один из счетчиков упадет до нуля:

Мы видим, все останавливаются. Это хорошо. Но Пользователя желательно предупредить о прекращении игры более явным способом. Для этого я тоже уже подготовил стили и всё, что нам потребуется – это добавить к html-выборке нашего «Домика» класс _ it-is-game-over_. Давайте сделаем это:

Мы добавили в метод gameOver() работу с давно нам знакомым методом setAttribute()
И вот наш результат:

Актуальные варианты кода

(Pet) ant.js

<hr />
var Pet = function(x, y) {
    this.selector = document.getElementById('pet');
    this.x = x || 0;
    this.y = y || 0;
    this.walkInterval = null;
    this.movementInterval = null;
    this.makeActionInterval = null;
}

Pet.prototype =  {
    /* Задаем начальную позицию питомца в домике */
    setPosition: function() {
        var x = this.x;
        var y = this.y;
        var petWidth = this.selector.offsetWidth;
        var petHeight = this.selector.offsetHeight;
        var bottomEnd = Booth.getHeight() - petHeight;
        var rightEnd = Booth.getWidth() - petWidth;
        /* проверрим на верхнюю и левую границы домика */
        if( x < 0 ) {
            this.x = x = 0;
        }
        if( y < 0 ) {
            this.y = y = 0;
        }
        /* проверрим на правую и нижнюю границы домика */
        if( x > rightEnd) {
            this.x = x = rightEnd;
        }
        if( y > bottomEnd) {
            this.y = y = bottomEnd;
        }

        this.selector.style.top = y + 'px';
        this.selector.style.left = x + 'px';
    },
    /* передвижение питомца */
    startWalk: function(direction) {
        var self = this;
        var timeForWalk = 50;
        var petWidth = this.selector.offsetWidth;
        var petHeight = this.selector.offsetHeight;
        var leftOrUp = function(styleName) {
            var current = parseInt(self.selector.style[styleName]) || 0;
                if(current != 0) {
                    self.selector.style[styleName] = (current - 1) + 'px';
                }
        };
        var rightOrBottom = function(styleName, border) {
                var current = parseInt(self.selector.style[styleName]) || 0;
                if(current < border) {
                    self.selector.style[styleName] = (current + 1) + 'px';
                }
        };
        var currentIntervalFunction = null;

        if(direction == 'left') {
            currentIntervalFunction = function() {
                leftOrUp('left');
            }
        }

        if(direction == 'right') {
            currentIntervalFunction = function() {
                var border = Booth.getWidth() - petWidth;
                rightOrBottom('left', border);
            }
        }

        if(direction == 'up') {
            currentIntervalFunction = function() {
                leftOrUp('top');
            }
        }

        if(direction == 'down') {
            currentIntervalFunction = function() {
                var border = Booth.getHeight() - petHeight;
                rightOrBottom('top', border);
            }
        }

        this.selector.setAttribute('class', direction);

        this.walkInterval = setInterval(currentIntervalFunction, timeForWalk);

    },
    /* остановка интервала питомца */
    stopInterval: function(intervalLink) {
        clearInterval(intervalLink);
    },
    /* начинает движение */
    startMovement: function() {
        var self = this;
        var timForMovementInOneDirection = 2000;

        this.movementInterval = setInterval(function() {
            var newDirection = self.getDirection()

            self.stopInterval(self.walkInterval);

            self.startWalk(newDirection);

        }, timForMovementInOneDirection);


        self.startWalk(this.getDirection());

        Booth.informer.setText('Гуляет...');

    },
    /* Выбор направления движения */
    getDirection: function() {
        var directionArray = ['left', 'right', 'up', 'down'];
        var currentDirection = Brain.makeChoice(directionArray);

        return currentDirection;
    },
    /*Остановить все дейсвтия питомца */
    stopAllActions: function() {
        this.stopInterval(this.movementInterval);
        this.stopInterval(this.walkInterval);
        this.stopInterval(this.makeActionInterval);
        this.stopPlay();
        this.stopSleep();
    },
    /* Начать играть с мячом */
    startPlay: function() {
        this.selector.setAttribute('class', 'playing');
        Booth.informer.setText('Играет...');
    },
    /* Перестать играть с мячом*/
    stopPlay: function() {
        this.selector.removeAttribute('class');
    },
    /* Начать играть с мячом */
    startSleep: function() {
        this.selector.setAttribute('class', 'sleep');
        Booth.informer.setText('Спит...');
    },
    /* Перестать играть с мячом*/
    stopSleep: function() {
        this.selector.removeAttribute('class');
    },
    /* Выбор действия */
    makeAction: function() {
        var self = this;
        var actions = ['sleep', 'walk', 'play'];
        var timeForChangeAction = 5000;

        this.makeActionInterval = setInterval(function() {
            var intervalAction = Brain.makeChoice(actions);

            /* Останавливаем все действия */
            self.stopAllActions();

            /* Начинаем случайно выбранное действие */
            if(intervalAction == 'walk') {
                self.startMovement();
            }

            if(intervalAction == 'sleep') {
                self.startSleep();
            }

            if(intervalAction == 'play') {
                self.startPlay();
            }

        }, timeForChangeAction);

        /* Для того чтобы не ждать начала интервала */
        this.startMovement();
        
    }
}

/* Создаем муравья, используя функцию-родитель */

var ant = new Pet(0, 0);

{Booth} booth.js


var Booth = {
    selector: document.getElementById('booth'),
    getHeight: function() {
        return this.selector.offsetHeight;
    },
    getWidth: function() {
        return this.selector.offsetWidth;
    },
    informer: {
        selector: document.getElementById('info'),
        setText: function(text) {
            this.selector.innerText = text;
        }
    },
    timer1: {
        selector: document.getElementById('fatigue'),
        isOrange: false,
        isRed: false,
        interval: null,
        width: 100
    },
    timer2: {
        selector: document.getElementById('satiety'),
        isOrange: false,
        isRed: false,
        interval: null,
        width: 100
    },
    timer3: {
        selector: document.getElementById('mood'),
        isOrange: false,
        isRed: false,
        interval: null,
        width: 100
    },
    /* добавляем события к выбранным кнопкам */
    buttons: document.getElementsByClassName('monitor__btn'),
    addButtonsEvents: function() {
        var context = this; // равен объекту Booth

        for(var i = 0; i < this.buttons.length; i+=1) {
            this.buttons[i].addEventListener('click', function() {
                var action = this.getAttribute('data-state');
                if(action == 'fatigue') {
                    context.refreshProgressBar(context.timer1);
                }
                if(action == 'satiety') {
                    context.refreshProgressBar(context.timer2);
                }
                if(action == 'mood') {
                    context.refreshProgressBar(context.timer3);                     
                }   
            });
        }
    },
    /* Запускаем счетчики парметров */
    runProgressBar: function(timer, seconds) {
        var self = this; // равен объекту Booth
        var milliseconds = seconds*1000;
        timer.interval = setInterval(function() {
            if(timer.width != 0) {
                timer.width -= 1;
                timer.selector.style.width = timer.width + '%';

                /* смена цвета счетчика*/
                if(timer.isOrange == false && timer.width <= 50) {
                    timer.isOrange = true;
                    timer.selector.setAttribute('class', 'monitor-bar__progress attention');
                }

                if(timer.isRed == false && timer.width <= 25) {
                    timer.isRed = true;
                    timer.selector.setAttribute('class', 'monitor-bar__progress alarm');
                }

            } else {
                /* Останавливаем все счетчики */
                clearInterval(self.timer1.interval);
                clearInterval(self.timer2.interval);
                clearInterval(self.timer3.interval);
                self.gameOver();
            }
        }, milliseconds);
    },
    /* пополняем счетчик */
    refreshProgressBar: function(timer) {
        timer.width = 100;
        timer.selector.setAttribute('class', 'monitor-bar__progress');
    },
    /* Запускаем наши счетчики */
    startTimers: function() {
        this.runProgressBar(this.timer1, 0.3);
        this.runProgressBar(this.timer2, 0.5);
        this.runProgressBar(this.timer3, 0.7);
    },
    /* Запускаем игру */
    startGame: function() {
        this.addButtonsEvents();
        this.startTimers();
        ant.makeAction();
    },
    /* Останавливаем игру */
    gameOver: function() {
        this.selector.setAttribute('class', 'booth it-is-game-over');
        ant.stopAllActions();
    }
}

Ну вот и всё. Безусловно наш код еще можно улучшать, оптимизировать, дополнять разными плюшками, что к примеру частично сделано в моём прототипе. Если вы внимательно на него взглянете что заметите что счетчики характеристик в нем уменьшаются каждый раз по-разному при новой загрузке окна. Или что при нажатии на кнопку пополнения счетчика, Муравей выполняет соответствующее действие. Но всё это уже нюансы. Главное, что мы начали наш проект и довели его до логического конца. Надеюсь такая практика была вам полезной.

Благодарю за внимание и апвоты.

Ссылки на предыдущие занятия:

Практика JavaScript для новичков. Занятие 1,
Практика JavaScript для новичков. Занятие 2,
Практика JavaScript для новичков. Занятие 3,
Практика JavaScript для новичков. Занятие 4,
Практика JavaScript для новичков. Занятие 5,
Практика JavaScript для новичков. Занятие 6,
Практика JavaScript для новичков. Занятие 7,
Практика JavaScript для новичков. Занятие 8,
Практика JavaScript для новичков. Занятие 9,
Практика JavaScript для новичков. Занятие 10,
Практика JavaScript для новичков. Занятие 11,
Практика JavaScript для новичков. Занятие 12,
Практика JavaScript для новичков. Занятие 13,
Практика JavaScript для новичков. Занятие 14,
Практика JavaScript для новичков. Занятие 15,

Ссылки на предыдущий курс:

Урок 1 - Окружение.,
Урок 2 - Некоторые особенности синтаксиса.,
Урок 3 - Переменные.,
Урок 4 - Типы переменных, как основа для их взаимодействия.,
Урок 5 - Операции с переменными одного типа.,
Урок 6 - Операции с переменными одного типа. Часть II.,
Урок 7 - Взаимодействие переменных с разными типами.,
Урок 8 - Взаимодействие переменных разного типа. часть II.,
Урок 9 - Взаимодействие переменных разного типа. Часть III.,
Урок 10 - Другие возможные взаимодействия между переменными.,
Урок 11 - Другие возможные взаимодействия между переменными. Часть II.,
Урок 12 - Другие возможные взаимодействия между переменными. Операторы присваивания.,
Урок 13 - Другие возможные взаимодействия между переменными. Операторы сравнения.,
Урок 14 - Сложные переменные. Array и Object.,
Урок 15 - Условные операторы.,
Урок 16 - Циклы.,
Урок 17 - Циклы. Часть II.,
Урок 18 - Функции.,
Урок 19 - Функции. Часть II.,
Урок 20 - Профилирование. Функции, часть III.,
Урок 21 - Функции, Часть IV. Аргументы.,
Урок 22 - Objects (Объекты).,
Урок 23 - Встроенные функции и объекты.,
Урок 24 - Встроенные функции и Объекты, Часть II. Глобальные функции и переменные.,
Урок 25 - Встроенные функции и Объекты, Часть III. Document Object Model.,
Урок 26 - Встроенные функции и Объекты, Часть III. Document Object Model.
Урок 27 - Встроенные объекты. Объект Style, Events, Часть II.
Урок 28 - Встроенная переменная this. Глобальная и локальная области видимости.
Урок 29 - Объектно-ориентированное Программирование. Введение.
Урок 30 - Объектно-ориентированное Программирование. Часть II. Полиморфизм.
Урок 31 - OОП. Наследование, Часть I. Оператор new.
Урок 32 - ООП. Наследование, Часть II. PROTOTYPE.
Урок 33 - ООП. Часть II. Полиморфизм.
Урок 34 - ООП. Часть III. Инкапсуляция.

23
61.328 GOLOS
На Golos с December 2016
Комментарии (6)
Сортировать по:
Сначала старые