Обычно я буду следовать первому руководству, применяя передовые методы кодирования, полученные в The Iron Yard. Я пишу это как процедуру, которой вы можете следовать, с минимумом болтовни.

Мой эталонный проект: https://github.com/davidasteed/babylonjs-exploration

Зачем мы это делаем?

На шестой неделе учебного курса по программированию The Iron Yard (фантастические двенадцать недель непрерывного обучения под критическим взглядом очень опытного ветерана индустрии) мне было поручено написать технический блог. Так почему бы не узнать немного об игровом API, который я планирую использовать в своем финальном проекте? В качестве дополнительного плюса ВЫ можете создать свой собственный репозиторий и следовать ему.

Не паникуйте

Я совершенно новый разработчик JavaScript, посещающий учебный курс по программированию… это достаточно простые вещи, которыми мы будем заниматься. Приветствуем новичков и случайных кодеров!

Объезды впереди

Поскольку мы не узнаем много о том, как использовать BabylonJS, просто скопировав и вставив операторы учебника в index.html и просмотрев результат в локальном браузере, я буду значительно отклоняться от шагов учебника. Подробно объясню почему.

Важный! Мы будем следить за более обновленным исходным руководством!

Мы будем использовать: http://doc.babylonjs.com/

Мы не будем использовать: https://doc.babylonjs.com/tutorials/creating_a_basic_scene

Я также отмечу, где я делаю другие изменения во время нашего путешествия и почему.

Текущие лучшие практики

Я буду интерпретировать руководство, чтобы создать правильно структурированное приложение JavaScript, используя синтаксис ES6 и рекомендуемые шаблоны программирования.

Необходимые предпосылки

  • Интернет-доступ к веб-сайту фреймворка: http://babylonjs.com/
  • Текстовый редактор (я использую Atom: https://atom.io/)
  • Современный веб-браузер с последней версией. Лучшим руководством по совместимости является поддержка WebGL вашим браузером: http://caniuse.com/#search=webgl
  • Гит установлен. github.com содержит больше информации и руководств.
  • Веб-сервер с командной строкой, такой как (https://www.npmjs.com/package/http-server)

Рекомендуемые предварительные условия

  • Знать, как создать репозиторий git и создать/просмотреть html-страницу. (для git: https://help.github.com/categories/bootcamp/) Конкретно для нашей задачи: перейти в каталог репозитория, создать базовую html-страницу в текстовом редакторе, открыть командную строку и запустить http- сервер и просмотреть эту страницу (обычно http://127.0.0.1:8080/) в веб-браузере.

Дополнительные вещи

  • Мини-лекция Себе: Не копируй и не вставляй бездумно. Введите каждый комментарий и оператор кода и подумайте, что они делают. Новых разработчиков учат избегать простых, но потенциально очень трудоемких ошибок и путаницы. Я даже не буду копировать/вставлять комментарии. Вместо этого я напишу краткое заявление, объясняющее мое собственное понимание того, что на самом деле делает этот оператор кода.
  • Зачем загружать все функции в неминифицированном виде? Я хочу в конце концов увидеть, на что способна библиотека. Я хочу иметь возможность легко сканировать основной код, чтобы получить общее представление о том, как работает библиотека. Например, если я хочу выполнить код, чтобы увидеть, что происходит в инспекторе в веб-браузере. Конечно, я бы вернулся к уменьшенной версии библиотеки до фактического развертывания.
  • Зачем создавать локальный репозиторий git, а не «облачное кодирование»? Мы можем отправлять наши задания для буткемпа только в правильно отформатированном репозитории. ИМХО, симулятор облачного кода скрывает большую часть реального процесса, используемого для создания и управления производственными сборками.

Создать репозиторий

  • Сначала создайте репо на github.com. Затем откройте окно командной строки и перейдите в каталог, который вы создали для локального репозитория.
  • Затем создайте локальный репозиторий следующим образом:
echo "# babylonjs-exploration" >> README.md
git init
git add README.md
git commit -m "first commit"
git remote add origin <insert your git url here>
git push -u origin master

Настроить файловую систему

Создайте следующие папки в корневой папке репозитория:

  • источник
  • источник/js
  • источник/CSS

Создать пустые файлы проекта

Создайте следующие пустые файлы:

  • источник/index.html
  • источник/css/style.css
  • источник/js/sceneCreate.js
  • src/js/sceneExecute.js

Напишите немного HTML5

Напишите index.html, чтобы он выглядел следующим образом, и сохраните его.

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Babylon - Getting Started</title>
    <link rel="stylesheet" href="css/style.css">
  </head>
  <body>
    <canvas id="renderCanvas"></canvas>
    <script src="js/babylon.custom.unminified.js"></script>
    <script src="js/sceneCreate.js"></script>
    <script src="js/sceneExecute.js"></script>
  </body>
</html>

Напишите немного CSS

Как вы можете видеть выше, есть тег ‹link› на src/css/style.css. Давайте напишем этот файл CSS и сохраним его. Вот мой src/css/style.css для справки:

html, body {
  overflow: hidden;
  height: 100%;
  margin: 0;
  padding: 0;
}
#renderCanvas {
  width: 100%;
  height: 100%;
  touch-action: none;
}

Примечание. Я опустил ненужную «ширину: 100%» в правиле «html, body {}», потому что элемент HTML по умолчанию принимает ширину своего родителя.

Скачать BabylonJS

  • Соберите и загрузите библиотеку BabylonJS (или фреймворк, как говорят все крутые ребята) с http://babylonjs.com/versionBuilder/. Я выбрал все варианты, v2.5 и неминифицированный. Имя файла — babylon.custom.unminified.js, и я сохранил его в новой папке на своем компьютере с именем babylon.js_v2.5_full для использования в будущих проектах кода.
  • Скопируйте указанный выше файл в src/js вашего проекта.
  • Обратите внимание, что medium.com мог исказить отступы, если строки были вырезаны/вставлены в ваш проект. Конечно, пожалуйста, простите меня за намек на то, что вы планируете вырезать/вставлять при написании кода :) Я мог бы предложить просмотреть файлы кода в моем проекте github, а не пытаться читать/копировать их на этом сайте.

Напишите немного JavaScript

Мы будем использовать руководство по BabylonJS, которое можно найти здесь: (http://doc.babylonjs.com/)

  • Обратите внимание на учебник: мы используем версию «JavaScript», а не «TypeScript». Это управляется кнопками в середине верхней части страницы руководства, прямо под заголовком «Начало работы».
  • Напишите следующие файлы JavaScript. Не стесняйтесь обращаться к руководству, чтобы увидеть различия (о которых я объясню в разделах, следующих за этим):

сценаКреате.js

Напишите следующий код в src/js/sceneCreate.js и сохраните файл:

(function() {
  'use strict';
  // link to, or create, namespace
  window.sceneNS = window.sceneNS || {};
  // scene creation function
  window.sceneNS.sceneCreate =
    /**
     * Create a Scene instance and return it
     * @param  {Canvas} canvas [canvas element which will display the new Scene]
     * @param  {Engine} engine [Engine class instance used to create the Scene]
     * @return {Scene}         [newly created Scene instance]
     */
    function sceneCreate(canvas, engine) {
      // convenience alias for BABYLON namespace
      let BABYLON = window.BABYLON;
      // create scene object
      let scene = new BABYLON.Scene(engine);
      // create a FreeCamera, and set position to x:0, x:5, z:-10
      let camera = new BABYLON.FreeCamera('camera1', new BABYLON.Vector3(0, 5, -10), scene);
      // point the camera at the scene origin
      camera.setTarget(BABYLON.Vector3.Zero());
      // attach the camera to the canvas
      camera.attachControl(canvas, false);
      // create a basic light, and aim it straight up
      let light = new BABYLON.HemisphericLight(
        'light1', new BABYLON.Vector3(0, 1, 0), scene);
      // Create a "sphere" using built-in shape:
      // Constructor parameters: name, width, depth, subdivisions, scene
      let sphere = BABYLON.Mesh.CreateSphere('sphere', 16, 2, scene);
      // relocate sphere +y by a value of half of its height
      sphere.position.y = 1;
      // create a built-in "ground" shape
      // Constructor parameters: name, width, depth, subdivisions, scene
      var ground = BABYLON.Mesh.CreateGround('ground1', 6, 6, 2, scene);
      // return the scene object
      return scene;
    };
}());

сценаExecute.js

Напишите следующий код в src/js/sceneExecute.js и сохраните файл:

(function() {
  'use strict';
  // link to, or create, namespace
  window.sceneNS = window.sceneNS || {};
  // wait until the web page is fully loaded
  // before running this code block
  window.addEventListener('DOMContentLoaded', function(){
    
    // query the DOM and save a reference to the canvas html element
    let canvas = document.getElementById('renderCanvas');
    // load the Babylon 3D engine
    let engine = new window.BABYLON.Engine(canvas, true);
    // create a Scene instance
    let scene = window.sceneNS.sceneCreate(canvas, engine);
    // register a render loop that repeatedly
    // renders the scene onto the canvas element
    engine.runRenderLoop(function() {
      scene.render();
    });
    // instantiate a handler for canvas/window resize events
    window.addEventListener('resize', function() {
      engine.resize();
    });
  });
}());

Запустить его!

  • Убедитесь, что все файлы проекта с операторами кода сохранены.
  • Убедитесь, что веб-сервер работает (я запускаю свой с терминала, а) перейдите в репозиторий проекта и б) запустите: http-server src
  • Откройте веб-браузер (возможно, ваша страница находится по адресу http://127.0.0.1:8080) и изумленно взгляните на новую сцену BabylonJS.

Отличия в моей сборке

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

IIFE блоки

На самом деле давайте начнем с самого верха всех файлов .js в проекте. Вы заметили этот код, который оборачивает каждый файл .js в проекте?

(function() {
  'use strict';
  
}());

Это IIFE, что означает Instantly Instantiated Function Expression. Этот блок IFFE эффективно изолирует доступ ко всему вложенному коду до тех пор, пока он не понадобится остальной части программы. Это важная практика программирования в JavaScript. Мы хотим попытаться предотвратить любые «коллизии кода», когда программист случайно записывает функцию или переменную с тем же именем, что и в каком-то внешнем коде.

Блоки IIFE взаимодействуют с несколькими компонентами программирования:

  • Объект окна, к которому подключено все в браузере, включает в себя все, к чему может прикоснуться наш код JavaScript.
  • Объект окна имеет глобальную область видимости. Ничто в любом IIFE не видно, если оно не содержится в «пространстве имен», присоединенном к объекту окна.
  • Пространство имен — логический домен, который отслеживает имена объектов, включая функции из любой библиотеки/фреймворка или локального файла JavaScript.
  • Я создал собственное пространство имен под названием «sceneNS», к которому привязываю свои функции. Затем я могу вызывать эти функции в других файлах. На самом деле оба файла js имеют одно и то же пространство имен.
  • В BabylonJS есть по крайней мере одно пространство имен, включенное в структуру: BABYLON. Мы получаем доступ к этому пространству имен через: window.BABYLON.

Как блок IIFE влияет, например, на sceneExec.js? Позволь мне объяснить:

Поскольку мой код JavaScript в sceneExec.js находится внутри IIFE, он изолирован от объекта «окно» (глобальная область видимости), и поэтому мы не можем вызывать какие-либо внешние функции, если не ссылаемся на объект окна и пространство имен. Пока код выполняется в IIFE, мне потребуется префикс window.‹namespace›. для любых внешних функций.

На самом деле, sceneExec.js даже не может видеть ни одну из функций из библиотеки BabylonJS, даже несмотря на то, что мы включили ее в тег ‹script› в index.html! Вот как я «раскрыл» части библиотеки для sceneExec.js:

// load the Babylon 3D engine
    let engine = new window.BABYLON.Engine(canvas, true);

window.BABLYLON — это пространство имен, включенное в js/babylon.custom.unminified.js. Строка выше создает новый экземпляр класса Engine и присваивает его переменной с именем «engine».

Папка и файлы

Хорошей практикой программирования является размещение всего исходного кода в дереве папок «src». Это позволяет легко поддерживать сборку.

  • Веб-серверы начинаются с index.html в качестве базовой страницы, поэтому я поместил index.html в src.
  • Файлы CSS в /src/css
  • Файлы JavaScript в /src/js (включая файл библиотеки BabylonJS)

Теги сценария

Соберите все элементы ‹script› в самом низу HTML-файла. Почти во всех случаях использования мы хотим, чтобы JavaScript выполнялся для объекта окна, в котором загружено 100% всего HTML и CSS.

Порядок элементов ‹script› имеет решающее значение. В нашем проекте мы хотим, чтобы а) сначала загружалась библиотека BabylonJS, затем б) вызывался js-файл, содержащий нашу функцию, и в) js-файл, который будет вызывать библиотечные функции, а также нашу собственную функцию:

  <script src="js/babylon.custom.unminified.js"></script>
  <script src="js/sceneCreate.js"></script>
  <script src="js/sceneExecute.js"></script>

Пусть, но никогда не вар

Инструктор Iron Yard строго запрещает использование ключевого слова «var». «var» включает поведение «переменного подъема». Поднятие переменных — это уникальная (и часто проблематичная для программистов) концепция, которая, по крайней мере, продвигает вновь определенную переменную в начало текущего блока кода. Это противоречит поведению большинства языков программирования (и очень сбивает с толку студента-программиста на C/C++, такого как я). Действительно ли я хочу, чтобы переменная была актуальной до ее объявления? Неа. Вместо этого я использую «let» для определения переменных, чтобы получить согласованную и ожидаемую область действия для этой переменной.

Используйте строгий

Этот блок IIFE также включал оператор «use strict». Любой браузер должен запускать наш JavaScript в строгом соответствии со стандартом языка, без отклонений. Мы стараемся всегда добиваться ожидаемого выполнения программы.

Докблок

Блок документов предоставит четкую документацию для функций, которые мы пишем, и является передовой практикой. Вот пример из sceneCreate.js:

    /**
     * Create a Scene class instance and return it
     * @param  {Canvas} canvas [canvas element which will display the new Scene]
     * @param  {Engine} engine [Engine class instance used to create the Scene]
     * @return {Scene}         [newly created Scene instance]
     */
    function sceneCreate(canvas, engine) {...}

Общие правила создания докблока таковы:

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

Обратите внимание, что в следующей строке кода нет документа в sceneCreate.js:

window.addEventListener('DOMContentLoaded', function(){...}

Это потому, что а) мы не написали addEventListener()… это основной JavaScript и б) наша анонимная функция обработчика событий() просто вызывает другие функции.

Правильный отступ

Ключ к тому, чтобы сделать ваш код легким для чтения и поддержки. Бонус: делает вашего босса счастливым. Независимо от того, выбираем ли мы отступ в 2 или 5 пробелов, мы хотим быть абсолютно последовательными. Обратите внимание, здесь в уроке мы видим пример почти правильного отступа. Можете ли вы обнаружить ошибку отступа? (Давайте не будем обращать внимание на опечатку в комментарии… конечно, во время написания этого руководства они не имели в виду, что v2.3 была «последней» версией?).

<!DOCTYPE html>
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html" charset="utf-8"/>
    <title>Babylon - Getting Started</title>
    <!-- link to the last version of babylon -->
    <script src="babylon.2.3.debug.js"></script>
</head>
<body>
    <canvas id="renderCanvas"></canvas>
</body>
</html>

‹html› является родительским элементом как для ‹head›, так и для ‹body›. Поэтому они должны располагаться следующим образом. Поскольку я использую отступы в 2 пробела во всем своем проекте, я придерживаюсь последовательной практики:

<!DOCTYPE html>
<html>
  <head>
    <meta charset="utf-8">
    <title>Babylon - Getting Started</title>
    <link rel="stylesheet" href="css/style.css">
  </head>
  <body>
    <canvas id="renderCanvas"></canvas>
    <script src="js/babylon.custom.unminified.js"></script>
    <script src="js/sceneCreate.js"></script>
    <script src="js/sceneExecute.js"></script>
  </body>
</html>

Приятной особенностью редактора Atom является то, что вы можете выбрать весь документ, затем перейти в раскрывающееся меню «Правка/Строки» и выбрать «Автоматический отступ». Это хорошо работает с версией редактора Atom по умолчанию, за исключением докблоков, где звездочки нужно будет скорректировать после автоматического отступа.

За пределами нашей компетенции

Я заметил две некритические ошибки, связанные с операторами учебника, которые я пока не исследовал, но отмечу для дальнейшего использования. Когда я запустил jshint для своих файлов JavaScript (для обнаружения линтинга/ошибки), он сказал:

/babylonjs-exploration (master)$ jshint src/js/scene*.js
src/js/sceneCreate.js: line 33, col 11, 'light' is defined but never used.
src/js/sceneCreate.js: line 45, col 11, 'ground' is defined but never used.
2 errors

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

Вывод

Спасибо за помощь в этом прогоне руководства по BabylonJS. Желаем удачи в ваших приключениях по программированию!