Создание игры «Слова из Слова»

в 12:50, , рубрики: game, javascript, головоломки, разработка игр

Добрый день! Хочу представить Вашему вниманию проект-игру «Слова из Слова». Относительно недавно я стал изучать web-программирование и, так как лучший учитель — это практика, решил написать свой вариант довольно-таки известной игры «Слова из Слова». Основная цель — использование чистого Javascript без подключения дополнительных библиотек.

image
Вид игрового поля

Описание игры

Задача игрока – из букв представленного на экране слова составлять другие. Составленное слово должно быть нарицательным именем существительным в единственном числе, уменьшительно-ласкательные формы, а также сокращения не принимаются. Минимальная длина – 3 буквы. За каждое отгаданное слово начисляются очки в зависимости от его длины (базовая ставка за каждую букву, умножаемая на коэффициент). Базовая ставка равняется десяти очкам. Коэффициент рассчитывается следующим образом:

  • три буквы – 1;
  • от четырех до пяти букв – 1.25;
  • от шести до семи букв – 1.5;
  • от восьми до девяти букв – 1.75;
  • более девяти букв – 2.

На каждом уровне игрок может заработать дополнительные очки, выполняя определенные условия:

  • отгадать 40 проц. возможных слов на уровне (1 000 очков);
  • отгадать три слова, начинающихся на ту же букву, что и слово уровня (500 очков);
  • отгадать все возможные слова на уровне (50 000 очков).

Отгаданные игроком слова отображаются на игровом поле в алфавитном порядки, сгруппированные по количеству букв в слове. Игрок может посмотреть значение каждого, нажав на него. Результаты охраняются каждый раз после верно отгаданного слова.

Использованные техники и приемы

В ходе работы над приложением использовались элементы подхода MVC (model, view, controller). В отдельные компоненты также вынесено управление звуком, обработка результатов игры и общие методы для всего приложения.

Общая структура приложения

GAME = {
    "utils":{}, // общие инструменты
    "sounds":{}, // обработка звуков
    "view":{}, // представление
    "controller":{}, // обработка поведения
    "model":{}, // основные данные
    "results":{} // обработка результатов
}
GAME.init(place) // инициализация приложения
GAME.namespace(ns_string) // создание пространств имен

В процессе разработки ощутил все преимущества использования замыканий и немедленно вызываемых функций. Так, их использование избавило от постоянного поиска элементов на странице посредством getElementById и т.п.

Пример использования замыканий
controller.play = (function () {
            // блокировка множественного нажатия
            var cancelClick = false;

            return function (letter) {
                if (cancelClick) return;

                cancelClick = true;

                setTimeout(function () {
                    cancelClick = false;
                }, 200)
                
                //код функции
             })()

Этапы выполнения приложения

В процессе инициализации приложения создаются все необходимые html-элементы, формируются объекты-списки для упрощения доступа к ним.

Содержимое html до инициализации

<body>
    <div id="gamefield"></div>
    <div id="help">
        <h2>Правила</h2>
        <div class='textGuide'>
            <p>Необходимо составлять слова из показанного на экране слова. Слово должно быть нарицательным именем существительным в единственном числе. Уменьшительно-ласкательные формы, а также сокращения не принимаются. Минимальная длина слова - 3 буквы.</p>
        </div>
        <h2>Управление</h2>
        <div class='textGuide'>
            <p>Чтобы выбрать букву, кликните мышкой. Повторный клик по последней выбранной букве снимает выделение.</p>
            <p>Клавиша Esc отменяет ввод всего слова.</p>
            <p>Клавиша Backspace (←) отменяет ввод последней буквы.</p>
        </div>
        <h2>Игровые бонусы</h2>
        <div class="textGuide">
            <p>Первая звезда - отгадать 40% возможных слов на уровне. Бонус: 1 000 очков.</p>
            <p>Вторая звезда - отгадать три слова, начинающихся на ту же букву, что и слово уровня. Бонус: 500 очков.</p>
            <p>Третья звезда - отгадать все возможные слова на уровне. Бонус: 50 000 очков.</p>
        </div>
        <h2>Подсказки</h2>
        <div>
            <img src="images/icons/tips/definition.png">
            <p>Показать определение неотгаданного слова. Стоимость подсказки: 100 очков</p>
        </div>
        <div>
            <img src="images/icons/tips/word.png">
            <p>Показать неотгаданное слово. Стоимость подсказки: 500 очков.</p>
        </div>
        <h2>Элементы интерфейса</h2>
        <div>
            <img src="images/icons/buttons_small/soundON.png">
            <p>Управление звуком.</p>
        </div>
        <div>
            <img src="images/icons/buttons_small/menuButton.png">
            <p>Вызов игрового меню.</p>
        </div>
        <div>
            <progress max="10" value="3"></progress>
            <p>Прогресс на уровне.</p>
        </div>
    </div>
</body>

Содержимое html после инициализации

<body>
    <div id="gamefield" style="position: relative;">
    <div>
       <div class="gameInfo">
        <!-- Область информации о текущей сессии игры -->
            <h1>Слова из слова</h1>
            <div class="userName">Игрок: <span>123</span></div>
            <div class="currentLevel">Уровень: <span>1</span></div>
            <div class="menuLevel">
             <!-- Переходы по уровням-->
                 <div class="menuLabel">Карта уровней ⇩</div>
                 <div class="levelMap" style="display: none;">
                     <a class="reached levelButton">1</a>
                     <a class="levelButton">2</a>
                     <a class="levelButton">3</a>
                     <a class="levelButton">4</a>
                 </div>
           </div>
           <div class="score">Очки: <span>0</span></div>
           <progress max="31" value="0" title="Отгадано 0 из 31 слов"></progress>
           <div class="tips">
               <h2>Подсказки:</h2>
               <img id="wordDefinition" title="Показать определение неотгаданного слова." alt="Показать определение неотгаданного слова." src="images/icons/tips/definition_gray.png">
               <img id="holeWord" title="Показать неотгаданное слово целиком." alt="Показать неотгаданное слово целиком." src="images/icons/tips/word_gray.png"></div>
            </div>
         <!-- Игровая область-->
          <div class="gameField">
          <div class="missions">
              <img src="images/icons/missions/incomplete.png" alt="Первая звезда" title="Отгадайте больше 40% слов">
              <img src="images/icons/missions/incomplete.png" alt="Вторая звезда" title="Отгадайте 3 слова на букву "р"">
              <img src="images/icons/missions/incomplete.png" alt="Третья звезда" title="Отгадайте 100% слов">
          </div>
          <div class="buttonGroup">
              <img src="images/icons/buttons_small/soundON.png" alt="Выключить звук" title="Выключить звук">
              <img src="images/icons/buttons_small/menuButton.png" alt="Меню" title="Игровое меню">
              <img src="images/icons/buttons_small/help.png" title="Помощь" alt="Помощь">
         </div>
         <!-- Отображение вводимого игроком слова -->
         <div class="userWord"></div>
         <div class="levelWord">
          <!-- Буквы основного слова -->
              <div class="letter" data-order="0">р</div>
              <div class="letter" data-order="0">о</div>
              <div class="letter" data-order="0">д</div>
              <div class="letter" data-order="0">и</div>
              <div class="letter" data-order="0">н</div>
              <div class="letter" data-order="0">а</div></div>
           <!-- контейнер для найденных слов -->
              <div class="foundWords"></div>
        </div>
      </div>
   </div>
</body>

Все информация о прохождении игроком уровня сохраняется в объекте GAME.model.level

Хранение информации о прохождении

level = {
     "1":{
       "wordForLevel":"родина",
       "foundWords":["род","анод","аир"],
       "missions": {
             "progress":3,
             "firstStar":true,
             "secondStar":true,
             "thirdStar":true
             }
         }
      }

Для того, чтобы как-то сохранять прогресс и не задействовать при этом серверные скрипты и базы данных, был выбран способ сохранения в localStorage браузера. Кроме того, реализовал «таблицу рекордов» для игроков, которые используют это приложение в одном и том же браузере

Метод сохранения

/**
     * Сохранение результатов.
     * @method GAME.controller.storeResults
     * @param {string} name
     * Имя игрока.
     */
    controller.storeResults = function (name) {
        var results = {
            level: GAME.utils.createClone(model.level),
            score: model.score
        }
        results = JSON.stringify(results);
        window.localStorage.setItem(name, results);
    }

Таким образом, представляю Вам на обсуждения мой проект. Буду рад выслушать конструктивную критику и предложения как в комментариях, так и в личном общении. Если интересуют подробности, с удовольствием расскажу о процессе написания подробнее.

Ссылка на репозиторий GitHub

Автор: Ghivan

Источник

* - обязательные к заполнению поля


https://ajax.googleapis.com/ajax/libs/jquery/3.4.1/jquery.min.js