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

в прошлом году

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

В нашем прошлом занятии мы с Вами решили две задачи. Первая касалась учитывания границ «Домика» нашим питомцем во время движения. Вторая затронула процесс оптимизации. Почему я так подробно на нем остановился? Я хотел показать Вам процесс разработки и оптимизации кода, для того чтобы вы имели представления о том, с чем Вам предстоит столкнутся, если Вы решите связать свою судьбу с программированием. В дальнейшем мы еще ни раз будем оптимизировать первоначальные версии нашей функциональности.

Давайте двигаться дальше.

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

На текущий момент у на есть метод startWalk() для начала движения нашего Питомца и метод stopWalk() для прекращения нашего движения. Однако для того, чтобы наш муравей начал движение нам надо вызвать метод startWalk() с нужным нам параметром в консоли браузера. Зам=тем, если мы хотим, чтобы питомец начал двигаться в другом направлении нам, так же в консоли надо вызвать метод stopWalk и заново startWalk() уже с другим параметром direction. Давайте сегодня попробуем сделать так, чтобы наш мураве делал все эти действия без непосредственного вызова этих методов в консоли.
Для этого, для начала нам требуется определится с логикой того, как это будет происходить. Смотрите, у нас есть четыре направления, куда наш муравей может двигаться это left, right, up и down. В консоли мы сами выбирали какое из этих направлений указать в данный момент. Но для реализации нашей задачи, нам нужно сделать так, чтобы наш Муравей сам выбирал куда ему двигаться. Ясное дело, что создавать искусственный интеллект на JavaScript’e мы не станем, но создать подобие выбора мы всё-таки можем. Для этого мы прибегнем к случайному выбору одного из возможных направлений. Для случайного выбора (его еще называют рандомного) в JavaScript’e есть метод random() у встроенного объекта {Math}. Этот метод при каждом вызове, генерирует произвольную цифру в промежутке между 0 и 1. Давайте посмотрим наглядно на его работу.

Обратите внимание, каждый раз при вызове этого метода у нас генерируется новая циферка. Сейчас это длинное дробной число. Но мы можем его округлить с помощью метода round() всё того же объекта {Math}. Давайте это проделаем.

Смотрите как интересно. Теперь у нас при каждом вызове случайно генерируется либо единица, либо ноль. Метод ** round()** округляет число в соответствии с математическим округлением до полвины и более половины. Что это значит? Это значит что метод random() генерирует большое дробное число наподобие такого 0.4321371042153497 а уже метод round() смотрит, больше ли это число чем половина от единицы (0.5). Мы видим, что это не так, так как 0.4 меньше чем 0.5 значит метод round() округлит это число к меньшему, то есть к нулю. Проверим:

Действительно округлил к нулю. Соответственно если бы у нас было число больше 0.5 например 0.5321371042153497, то метод round() уже вернул бы единицу. Удостоверимся:

Все так. Надеюсь логика работы этих методом ясна. Как мы можем воспользоваться этими методами для наших нужд. Дело в том, что как я уже упоминал в самом начала, нам известно, что у нас всего четыре направления для движения. Это означает что нам надо случайно выбирать значение от одного до четырех. Верно? Давайте попробуем для начала умножить число сгенерированное методом random() на 4. И посмотрим что из этого выйдет:

B и что мы видим? У нас по-прежнему получаются длинные дробные числа. Но обратите внимание, что все они генерируются в нужных нам пределах – от единицы до нуля! Давайте теперь попробуем их круглить с помощью метода random():

И о чудо! Теперь мы получаем целые числа в нужном нам пределе. Как теперь мы можем использовать это открытие? Очень просто – из прошлого курса мы знаем, что у массивов (Array) каждый элемент имеет свой индекс. Давайте попробуем создать массив с нашими направлениями движения, а вместо индекса засунем наш рандомизатор от 0 до 4.

Смотрите, мы создали метод, который назвали getDirection(). Не спешите пока переносить его к себе в код. Внутри этого метода мы создали массив с нашими возможными направлениями. Также мы создали переменную index в которую при каждом вызове нашего метода будет сохранятся рандомное число от 0 до 4. И на всякий случай мы вывели то число в консоль. Давайте проверим как работает наш метод:

Видите? Всё шло хорошо, нам возвращалось случайное значение для направления и тут хлоп! Вернулся индекс 4 и значение для направления undefined. Почему так? Я думаю Вы уже догадались. Из прошлого курса, когда мы разбирали работу с массивами мы упоминали, что индексы в массиве начинаются не с единицы, а с нуля. Другими словами, в массиве из четырех элементов только индексы 0, 1, 2 и 3 вернут значения, а вот уже под индексом 4 никакого элемента нет. Поэтому мы и получаем undefined. Значит нам надо исключить четверку из возможных индексов нашего рандомизатора. Как проще всего это сделать? Проще всего отнять от получаемого нами числа единицу, правда? Примерно так:

Таким образом, если рандомизатор вернет нам 4 от нее отнимется 1 и индекс станет равным 3. Если вернется 3 то индекс будет 2 и так далее. Замечательно. Но постойте! Что будет если рандомизатор вернет нам ноль? Ведь 0 – 1 будет равен -1, а элемента с индексом -1 у нас тоже нет. Что делать? А ничего не остаётся кроме как исключить в рандомизаторе возможность генерировать 0. Как это сделать? Дело в том, что в объекте {Math} есть еще один метод для округления. Он называется ceil(). Отличие этого метода от метода round() заключается в том, что он всегда округляет в большую (ударение на «о») сторону. То есть если мы будем использовать этот метод вместо метода round() то, чтобы не генерировал random() у нас никогда не получится нуля. Давайте заменим методы в нашем getDirection()

Отлично. Посмотрим, как теперь он будет работать в консоли:

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

Итак, мы создали новый метод startMovement(). Который по сути делает следующее. Он запускает интервал (оранжевая рамка), который каждые 2 секунды (переменная timForMovementInOneDirection) генерирует новое направление для движения (переменная newDirection)б останавливает предыдущее значение (зеленая стрелка) и запускает движение с уже новым направлением еще раз. Помимо этого на строке 105 мы сразу делаем вызов к началу движения, потому что интервал первый интервал запустится только через 2 секунды, и чтобы наш муравей с самого начала не стоял это необходимо было сделать. Давайте посмотрим на результат своих трудов:

Наш муравей ожил. И теперь как в том мультике – «Куда хочу, туда лечу!». Правда пока он не поворачивается в нужном нам направлении, но это мы исправим с следующем занятии.

Актуальный на сегодня код:

var Pet = function(x, y) {
    this.selector = document.getElementById('pet');
    this.x = x || 0;
    this.y = y || 0;
    this.walkInterval = 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.walkInterval = setInterval(currentIntervalFunction, timeForWalk);

    },
    /* остановка питомца */
    stopWalk: function() {
        var self = this;

        clearInterval(self.walkInterval);
    },
    /* начинает движение */
    startMovement: function() {
        var self = this;
        var timForMovementInOneDirection = 2000;

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

            self.stopWalk();

            self.startWalk(newDirection);

        }, timForMovementInOneDirection);


        self.startWalk(this.getDirection());

    },
    /* Выбор направления движения */
    getDirection: function() {
        var directionArray = ['left', 'right', 'up', 'down'];
        var index = Math.ceil(Math.random()*4) - 1;

        return directionArray[index];
    }
}

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

var ant = new Pet(0, 0);

Ну а на сегодня всё. Продолжение следует…

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

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

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

Урок 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. Инкапсуляция.

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

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

Награда за количество опубликованных постов

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

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

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

69
  ·  в прошлом году

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

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

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

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

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

71
  ·  в прошлом году

Ваш пост поддержали следующие Инвесторы Сообщества "Добрый кит":
kavalsky, svetlanaaa, volv, svinsent, gryph0n, orezaku, exan, vika-teplo, juke, myhardmoney
Поэтому я тоже проголосовал за него!
Узнать подробности о сообществе можно тут:
Разрешите представиться - Кит Добрый
Правила
Инструкция по внесению Инвестиционного взноса
Вы тоже можете стать Инвестором и поддержать проект!!!


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