Добрый день! Хочу представить Вашему вниманию проект-игру «Слова из Слова». Относительно недавно я стал изучать 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
UPD! Поиграть можно здесь
Поделиться с друзьями
-->

Комментарии (31)


  1. platon23
    22.08.2016 16:33

    Такую игру бы на смартфоны, был бы отличный таймкиллер.


    1. Viacheslav01
      22.08.2016 18:31

      Вытерто за неактуальностью


    1. lizarge
      22.08.2016 20:47

      Участвовал в разработке https://itunes.apple.com/app/that-name-game/id966220098?mt=8 игры в города, там есть где то и русская версия, не сочтите за рекламу, уже работаю в другой компании да и игра коммерчески успешна не была, и не факт что хорошо работает под ios9/10.


    1. Agorov
      23.08.2016 00:37

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



  1. V2008n
    22.08.2016 16:42

    Так есть уже. Вовсю играю.


    1. Ghivan
      22.08.2016 17:21

      Собственно игра на смартфоне и побудила меня выбрать этот жанр для тренировки


  1. mihmig
    22.08.2016 16:44

    Неплохо было бы прикрутить внешний ресурс со словами…


    1. Ghivan
      22.08.2016 17:20

      Пока набираюсь знаний. Еще есть желание сделать онлайн-вариант для двух игроков (на один ход 60 сек)


  1. tehnolog
    22.08.2016 17:46

    А можно ссылку на готовую игру?


    1. Ghivan
      22.08.2016 18:43

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


      1. tehnolog
        22.08.2016 19:07

        Спасибо. Уже играю. В слове акробат не распознает слово табор.


        1. Ghivan
          22.08.2016 19:34

          Уже поправил. Спасибо


          1. kursorik
            23.08.2016 00:37

            Попробовал, довольно интересный проект. Хочу отметить лишь что дизайн несколько «старомоден», в HTML5 смотрелось-бы лучше (но это лишь мое мнение, имхо), из минусов, не определяет некоторые слова (Рина (жен. имя), Один (сканд. бог), Рон (муж. имя) и некоторые другие), хочу пожелать удачи в развитии и совершенствовании навыков.


            1. Ghivan
              23.08.2016 00:39

              Ну, дизайн не моя сильная сторона, хотя некоторая «старомодность» и была задумана. А насчет имен собственных, они не принимаются по правилам игры.


              1. kursorik
                23.08.2016 01:07

                Хорошо, ну например слово «Дон» является титулом, однако скрипт этого увы не знает. Но знак вопроса в верхнем правом углу, смотрится слишком грубо, так как лучше было бы использовать шрифтовые иконки FA либо векторные SVG.


                1. Ghivan
                  23.08.2016 08:11

                  Тут с Вами согласен, нужно будет переделать


      1. BarrelRoll
        22.08.2016 19:56

        Выложили бы хоть на heroku


        1. Ghivan
          23.08.2016 00:11

          Собственно, сделал так, как ниже упомянул slaFFik. Вот!


          1. BarrelRoll
            23.08.2016 00:42

            Супер! Игра понравилась, спасибо!


      1. slaFFik
        23.08.2016 00:10

        Выше сказали про heroku, но можно заюзать Github Pages — не нужен хостинг, новый аккаунт и прочего — все уже есть. Просто пуш в новую ветку, включить в админке репозитория — и все.


  1. ziv
    23.08.2016 08:07

    В Chrome на Андроиде выделение букв не снимается — то есть, нельзя исправить слово.


    1. Ghivan
      23.08.2016 08:10

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


      1. ziv
        23.08.2016 08:32

        Да, прошу прощения, в обратном порядке выделение действительно снимается. Но почему строго в обратном порядке? Это не очевидно и не очень удобно.
        Кроме того, некоторые слова не распознаются, например, торба. Может быть, использовать какой-нибудь доступный словарь для проверки слов?


  1. saluev
    23.08.2016 10:39

    Никому не кажется, что для статьи про геймдев на Хабре здесь маловато технических деталей? (Нет, код не считается!) Выглядит как «я сделяль», без какой бы то ни было попытки обогатить читателей новыми знаниями.


    1. Ghivan
      23.08.2016 12:01

      Это не только первый опыт написания проекта, но еще и первый опыт написания статей на подобные ресурсы. Потому буду рад услышать конструктивные замечания по поводу улучшения данной статьи.


      1. saluev
        23.08.2016 13:14

        Ну, например, расскажите про проблемы, с которыми вы столкнулись в процессе написания игры, как искали/придумывали решения и как решили.


  1. monowar
    23.08.2016 11:56

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


    1. Ghivan
      23.08.2016 12:03

      Словарь создавался мной вручную, потому есть определенные пробелы. Планирую подключать внешние ресурсы.


      1. monowar
        23.08.2016 12:10

        И забыл сказать, что в целом игра очень понравилась! Не забрасывать этот проект.


  1. dcc0
    25.08.2016 12:41

    Классная игра.