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

11 месяцев назад

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

В нашем прошлом занятии мы с Вами закрыли список задач по Питомцу. Теперь наш Мураш отлично имитирует самостоятельность в выборе того или иного действия, но нас это устраивает. В конце концов написать настоящий 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. Инкапсуляция.

Авторы получают вознаграждение, когда пользователи голосуют за их посты.
Голосующие читатели также получают вознаграждение за свой голос.
Порядок сортировки:  Популярное

Ваш пост поддержали следующие Инвесторы Сообщества "Добрый кит":
t3ran13, antino, damm, dabudi, genyakuc, volv, natasmr, svinsent, gryph0n, arystarch, exan, bobrik, vika-teplo, anomalywolf, myhardmoney, del137, generationg, gradovskih, mixtura
Поэтому я тоже проголосовал за него!
Узнать подробности о сообществе можно тут:
Разрешите представиться - Кит Добрый
Правила
Инструкция по внесению Инвестиционного взноса
Вы тоже можете стать Инвестором и поддержать проект!!!


Если Вы хотите отказаться от поддержки Доброго Кита, то ответьте на этот комментарий командой "!нехочу"

@rassen Поздравляю! Вы добились некоторого прогресса на Голосе и были награждены следующими новыми бейджами:

Награда за количество голосов

Вы можете нажать на любой бейдж, чтобы увидеть свою страницу на Доске Почета.
Чтобы увидеть больше информации о Доске Почета, нажмите здесь

Если вы больше не хотите получать уведомления, ответьте на этот комментарий словом стоп

Голосуя за это уведомление, вы помогаете всем пользователям Голоса. Узнайте, как здесь.

@rassen Поздравляю! Вы добились некоторого прогресса на Голосе и были награждены следующими новыми бейджами:

Награда за количество голосов

Вы можете нажать на любой бейдж, чтобы увидеть свою страницу на Доске Почета.
Чтобы увидеть больше информации о Доске Почета, нажмите здесь

Если вы больше не хотите получать уведомления, ответьте на этот комментарий словом стоп

Голосуя за это уведомление, вы помогаете всем пользователям Голоса. Узнайте, как здесь.

Доброго времени суток. У меня такой вопрос:
Вот есть пример сайта http://coin-win.com
В фрейме указаны 3 кнопки: coin-win.com, news и Bitcoin Wordl.

Как реализовать кнопки news и Bitcoin Wordl? В плане нужны ресурсы, где можно понять, как сделать самому, при том свое.
Я думаю, что это больше относится к JavaScript, так как в html не нашёл этого. Можете помочь?

Заранее спасибо)

·

Доброго..

Это не кнопки, это просто ссылки. И это не JavaScript, это html. Код для них выглядит следующим оразом:

Для news:

<a href="http://coin-win.com/news">News</a>

Для Bitcoin World:

<a href="http://coin-win.com/bitcoin-world">Bitcoin World</a>

Для реализации похожих ссылок вам надо и спользовать следующий код:

<a href="сюда ввести адрес на который будет вести ссылка">сюда ввести имя сслыки</a>
·
·

Косяк с моей стороны. Не доглядел. Спасибо)