Статьи

Использование CSS Grid Layout и Blend 5 для создания игры

Я хотел бы поделиться с вами загадочным внутренним секретом, который долгое время хранился в Microsoft. Это реальная история, лежащая в основе концепции CSS Grid Layout, представленной Microsoft для IE10 и приложений Магазина Windows.

Большинство из вас, вероятно, думают, что эта спецификация была разработана, чтобы дать разработчикам лучший механизм верстки для их сайтов и приложений. Но первоначальная мотивация была совершенно иной. Самая первая цель состояла в том, чтобы создать игру, похожую на тетрис, простым способом!

Я уверен, что вы еще не убеждены. Вот почему я собираюсь доказать это вам, используя смесь 5 в качестве компаньона. Хорошо пойдем!

Предварительные условия: чтобы следовать этому руководству, сначала необходимо:

  1. Загрузите / купите и установите Windows 8 RTM на своем компьютере: http://msdn.microsoft.com/en-US/windows/apps/br229516.aspx
  2. Загрузите и установите бесплатную версию Visual Studio 2012 Express RTM для Windows 8: http://msdn.microsoft.com/en-US/windows/apps/br229516.aspx, которая включает в себя Expression Blend 5 для Visual Studio, или используйте более высокие версии ,

Шаг 1: откройте секрет CSS Grid Layout благодаря Blend 5

Запустите Expression Blend 5 и создайте новый проект HTML (Windows Store) типа Blank App. Назовите это « TheRealCSSGridStory »:

образ

Заменить:

  < p > Контент идет сюда </ p > 
 

С:

  < div class = "mainGrid"> 
  </ div > 
 

Давайте создадим сетку, содержащую 10 столбцов и 20 строк, независимо от разрешения экрана, используя дробные единицы. Для этого добавьте это правило CSS:

  .mainGrid {
     дисплей : -ms-grid ;
     ширина : 100% ;
     высота : 100% ;
     -ms-grid-колонки : (1fr) [10] ;
     -ms-grid- row : (1fr) [20] ;
 } 

Выберите в Live DOM элемент <div> mainGrid, и вы должны получить это:

образ

Давайте нарисуем форму внутри этой красивой сетки. Добавьте этот блок HTML внутри основной сетки:

  < div class = "shape1"> 
  </ div > 
 

И вставьте этот CSS связанный с ним:

  .shape1 {
     -ms-grid-column : 4 ;
     -ms-grid-row : 3 ;
     -ms-grid-column-span : 3 ;
     -ms-grid-row-span : 2 ;
     цвет фона : красный ;
 } 

Теперь вы должны увидеть это в смеси 5:

образ

Круто, но ничто еще не похоже на игровую часть тетриса. Давайте работать над этим. Добавьте эти два DIV внутри shape1:

  < div class = "line1shape1"> </ div > 
  < div class = "line2shape1"> </ div > 
 

и замените предыдущее правило .shape1 на этот блок CSS:

  .shape1 {
     -ms-grid-column : 4 ;
     -ms-grid-row : 3 ;
     -ms-grid-column-span : 3 ;
     -ms-grid-row-span : 2 ;
     дисплей : -ms-grid ;
     -ms-grid-колонки : 1fr 1fr 1fr ;
     -ms-grid-rows : 1fr 1fr ;
     ширина : 100% ;
     высота : 100% ;
 }
 .line1shape1 {
     -ms-grid-column-span : 2 ;
     цвет фона : красный ;

 }

 .line2shape1 {
     -ms-grid-column : 2 ;
     -ms-grid-row : 2 ;
     -ms-grid-column-span : 2 ;
     цвет фона : красный ;
 } 

В настоящее время shape1 занимает три столбца и два ряда. Затем я создам новую сетку внутри этой области, определяемой тремя столбцами и двумя строками, чтобы ячейки имели одинаковый размер с ячейками основной сетки, каким бы ни было разрешение.

После этого я создам две линии, чтобы имитировать Z-образную форму игры Tetris. Теперь у вас должен быть такой результат:

z-форма в тетрисе

Более того, поиграйте с различными видами, доступными на вкладке «Устройство», и вы увидите, что наша игра уже реализует адаптивный дизайн ! Это чертовски круто, не правда ли?

Вот, например, выходные данные для привязанного вида и портретного вида:


z-форма в альбомной ориентации

Давайте теперь решим еще одну проблему.

Сетка Тетрис игровая состоит из квадратов. Наш текущий отзывчивый дизайн растягивается на 100%. Создание приложения Windows 8 для Магазина Windows в большинстве случаев будет соответствовать широкоэкранным мониторам (в настоящее время планшеты имеют разрешение 1366 × 768 или 1920 × 1080, а большинство настольных ПК имеют соотношение 16/9). Давайте тогда предположим, что нацеливание на широкоэкранное соотношение охватывает почти все случаи. Чтобы вычислить правильную ширину отклика, вам нужно сделать: 9/16 * 10/20 (отношение основной игровой сетки), что равно: 28,125%.

Добавьте это правило для целевой сетки в полноэкранном ландшафтном режиме:

  @media screen и (-ms-view-state: fullscreen-landscape) {
     .mainGrid {
         ширина : 28,125% ;
         }
 } 

Давайте теперь центрируем игровую сетку, используя… CSS Grid Layout снова! (И теперь вы должны начать верить, что он действительно предназначен для тетриса!)

Переключите элемент body на –ms-grid, состоящий из одного столбца и одной строки:

  тело {
     дисплей : -ms-grid ;
     -ms-grid-колонки : 1fr ;
     -ms-grid-rows : 1fr ;
     ширина : 100% ;
     высота : 100% ;
 } 

Теперь просто добавьте этот атрибут в CSS, связанный с основной сеткой:

  -ms-grid-column-align : центр ; 

И сетка теперь центрирована:

На этом этапе вы, вероятно, уже в шоке. « Как я мог пропустить этот невероятный секрет? «Вы задаетесь вопросом для себя.

Вдохни.

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

Шаг 2: перемещение или вращение формы

Моей первой идеей было попытаться избежать JS, используя как можно больше CSS. Затем я сначала попытался использовать CSS3 Animations для перемещения и анимации фигуры в различных строках / столбцах. Но плохая новость заключается в том, что вы не можете изменить значения –ms-grid-column или –ms-grid-row с помощью анимации CSS3. Тогда это будет работа некоторого кода JavaScript.

Затем я начал думать о том, как я буду вращать форму. CSS Transforms, казалось, идеально приспособлены для этого. Давайте проверим это, выполнив несколько экспериментов. Blend 5 действительно хорош для этого, так как вы можете непосредственно увидеть результат ваших изменений вживую.

Добавьте поворот на 90 градусов на shape1 , добавив этот класс в его элемент DIV:

  .shape1rotated {
     преобразование : вращение (90 градусов) ;
 } 

Я уверен, что вы не ожидали этого:

Rotated shape

Проблема: он неправильно выровнен по игровой сетке. Чтобы выровнять нашу форму по сетке, нам нужны небольшие корректировки:

  .shape1rotated {
     трансформация происхождения : 33% 50% ;
     transform : повернуть (90 градусов) translateX (-33%) ;
 } 

И теперь у нас есть та же ротация, что и в игре типа тетрис. Вот два скриншота до / после поворота:

Z-образная форма перед вращением
Z-образная форма после вращения

Мы можем даже пойти дальше, используя набор переходов для shape1 через это:

  переход : все 1s разгрузка ; 

И теперь удаление / добавление класса .shape1rotated в DIV shape1 запустит анимацию плавного вращения.

Проверьте результат в Blend 5 благодаря этому короткому видео:

Скачать видео: MP4 , WebM , HTML5 видеоплеер от VideoJS

На данном этапе мы могли бы подумать, что этот подход является хорошим для построения нашей игры. Но, к сожалению, это еще не так. Вот почему Попробуйте переместить фигуру, просто изменив ее свойство –ms-grid-column . Смесь 5 будет отражать изменения напрямую. Когда не повернуто, форма может быть перемещена до 8-го столбца:

Z-форма переместилась в 8-ю колонку

Все идет нормально. Но когда вы вращаете его, добавляя класс .shape1rotated в DIV:

Z-образная форма повернута до 8-го столбца

Вы видите, что по-прежнему есть 1 ряд справа для перемещения фигуры. Если вы думаете, что нам просто нужно переместить его в 9-й ряд, вы ошибаетесь! Действительно, вот что мы получим в 9-м ряду:

Z-форма сжимается при перемещении в 9-й ряд

Вы, вероятно, забыли, что в данный момент мы перемещаем элемент DIV, отображающий сетку с тремя столбцами и двумя строками, точно совпадающими с игровой сеткой. При его перемещении у нас действительно возникает ощущение, что это блок-часть главной сетки, которую мы перемещаем. Но чтобы этот трюк сработал, нам нужно по крайней мере три доступных столбца для содержания нашего элемента shape. Если он содержится в двух столбцах (при установке в 9-й столбец) или менее, он будет «сжат», как на скриншоте.

Есть два способа решить это.

1 — Прекратите использовать CSS Transforms и нарисуйте повернутую фигуру, используя другое определение сетки. Например, используя три элемента внутри фигуры вместо двух. Но использование такого подхода не даст нам иметь хорошие CSS-анимации.
2 — Переопределена основная сетка для работы с 12 столбцами вместо 10, и мы будем использовать только столбцы с 2 по 11 (своего рода область отсечения, если хотите). Это решит нашу проблему «переполнения».

Давайте реализуем второе решение.

Переопределите основную сетку, используя это:

  .mainGrid {
     дисплей : -ms-grid ;
     -ms-grid-columns : (1fr) [12] ;
     -ms-grid- row : (1fr) [20] ;
     -ms-grid-column-align : центр ;    
     ширина : 100% ;
     высота : 100% ;
 } 

Чтобы также иметь правильное соотношение, необходимо обновить связанный медиазапрос:

  @media screen и (-ms-view-state: fullscreen-landscape) {
     .mainGrid {
         ширина : 33,75% ;
         }
 } 

33,75% = 9/16 * 12/20

Давайте также добавим «виртуальную сетку», чтобы разграничить пространство, в котором мы сможем перемещать фигуры. Внутри основной сетки DIV вставьте эту:

  < div class = "virtualGrid"> 
  </ div > 
 

Связанный с этим блоком CSS:

  .virtualGrid {
     -ms-grid-column : 2 ;
     -ms-grid-column-span : 10 ;
     -ms-grid-row-span : 20 ;
     стиль границы справа : пунктирная ;
     стиль границы слева : пунктирная ;
     цвет фона : # 505A5A ;
 } 

Это поможет разграничить игровую зону с серым фоном и пунктирными границами.

Теперь, если я перемещаю фигуру Z в столбце 9, строке 2, вот результат:

Z-образная форма в столбце 9

Если я вращаю его с помощью CSS Transforms, я могу правильно переместить его в столбец 10:

Повернутая z-образная форма перемещена правильно в столбец 9

Бонус — обработка портретного режима:

Если вы хотите поддержать портретный режим (что еще лучше для игры в сетку Tetris), добавьте это определение CSS Media Query:

  @media screen и (-ms-view-state: fullscreen-Portrait) {
         .mainGrid {
         ширина : 106,66% ;
         }
 } 

Так как коэффициент необходимо рассчитать как = 16/9 * 12/20 = 106,66%.

Сетка тетрис в ландшафте

Шаг 3: добавление некоторого кода для обработки части игровой логики

Теперь, когда мы решили графическую часть игры, используя только некоторый чистый код CSS и HTML, нам нужна помощь JavaScript для перемещения / вращения фигуры в игровой области. Мы собираемся повторно реализовать логику CSS через объект JS, который будет определяться благодаря WinJS.Class .

Откройте « TheRealCSSGridStory » в Visual Studio 2012.

Создайте файл TetrisShapeZ.js в каталоге JS и скопируйте / вставьте этот код:

  ( function () {
     «использовать строгое» ;

     var ShapeZ = WinJS.Class.define (
     /// Конструктор - columnIndex не является обязательным.  Если указано, определяет столбец, в котором начинается форма 
          function (columnIndex) {
             // Мы создаем эквивалент этого блока HTML: 
              // <div class = "shape1"> 
              // <div class = "line1shape1"> </ div> 
              // <div class = "line2shape1"> </ div> 
              // </ div> 
              this ._shape1 = document.createElement ( "div" );
             var line1 = document.createElement ( "div" );
             var line2 = document.createElement ( "div" );
             this ._shape1.className = "shape1" ;
             line1.className = "line1shape1" ;
             line2.className = "line2shape1" ;
             this ._shape1.appendChild (line1);
             this ._shape1.appendChild (line2);
             // Логическое значение, чтобы указать, находится ли фигура в режиме ориентации по умолчанию или нет 
              // True означает, что не повернуто, false означает, что повернуто 
              this ._defaultOrientation = true ;
             // Установка позиции столбца в основной сетке 
              if (columnIndex) {
                 this ._currentColPos = columnIndex;
                 this ._shape1.style.msGridColumn = this ._currentColPos;
             }
             еще {
                 this ._currentColPos = 1;
             }
             // Мы всегда начинаем со строки 1 
              this ._currentLinePos = 1;
             // логическое значение, чтобы знать, можно ли перемещать / вращать фигуру или нет 
              // Если true, это означает, что мы достигли последней возможной строки 
              this ._fixed = false ;
         },
         {
             /// Укажите, с каким HTML-элементом, отображаемым в CSS-сетке, вы хотели бы работать 
              /// ширина - количество столбцов сетки, а высота - количество строк. 
              insertIntoGrid: function (element, width, height) {
                 element.appendChild ( this ._shape1);
                 this ._gridWidth = width;
                 this ._gridHeight = высота;
                 // Это левый и нижний максимальный предел для этой фигуры 
                  // когда отображается в режиме ориентации по умолчанию 
                  this ._maxLeft = ширина - 3;
                 this ._maxBottom = высота - 1;
             },
             /// Повернуть Z-образную форму на 90 градусов против / по часовой стрелке, используя CSS Transforms 
              /// просто удаляя / добавляя класс shape1rotated 
              rotate: function () {
                 if (! this ._fixed && this ._defaultOrientation) {
                     // поворот на 90 градусов по часовой стрелке, это также вызовет переход CSS 
                      WinJS.Utilities.addClass ( this ._shape1, "shape1rotated" );
                     this ._defaultOrientation = false ;
                     // левый предел теперь +1 против ориентации по умолчанию 
                      this ._maxLeft = this ._gridWidth - 2;
                 }
                 еще {
                     if (! this ._fixed && this ._currentColPos < this ._maxLeft) {
                         // удаление shape1rotated автоматически сбросит форму 
                          // к своей исходной матрице и снова CSS Transition выполнит  
                          // анимация для вас 
                          WinJS.Utilities.removeClass ( this ._shape1, "shape1rotated" );
                         this ._defaultOrientation = true ;
                         this ._maxLeft = this ._gridWidth - 3;
                     }
                 }
             },
             // Внутренняя функция, вызываемая public moveLeft / moveRight 
              _moveHorizontally: функция (направление) {
                 if (! this ._fixed && ( this ._currentColPos < this ._maxLeft || direction === -1) && 
                 ( this ._currentColPos> 2 || direction === 1)) {
                     this ._currentColPos = this ._currentColPos + direction;
                     this ._shape1.style.msGridColumn = this ._currentColPos;
                 }
             },
             /// Переместить фигуру в ближайший левый столбец 
              /// Проверить, достиг ли ты левого предела или нет 
              moveLeft: function () {
                 this ._moveHorizontally (-1);
             },
             /// Переместить фигуру в ближайший правый столбец 
              /// Проверьте, достигли ли вы правильного предела или нет 
              moveRight: function () {
                 this ._moveHorizontally (1);
             },
             /// Переместить форму вниз по прямой ниже линии 
              /// Проверка, достигли ли вы нижнего предела или нет 
              moveDown: function () {
                 если (! this ._fixed) {
                     this ._currentLinePos = this ._currentLinePos + 1;
                     this ._shape1.style.msGridRow = this ._currentLinePos;
                     if ( this ._currentLinePos === this ._maxBottom) {
                         this ._fixed = true ;
                     }
                 }
             }
         }
     );

     WinJS.Namespace.define ( "CSSTetris" , {ShapeZ: ShapeZ});
 } ()); 

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

Добавьте ссылку на этот файл скрипта в default.html и оставьте только этот блок HTML внутри тела:

  < div class = "mainGrid"> 
      < div class = "virtualGrid"> 
      </ div > 
  </ div > 
 

Перейти в default.js .

Крутой частью хорошо документированного кода является то, что теперь у нас есть интересные детали IntelliSense, например, для конструктора :

Intellisense для конструктора ShapeZ (columnIndex)

или функция поворота :

Intellisense для функции поворота

Чтобы правильно использовать этот код, добавьте этот блок JS сразу после вызова processAll :

  document.addEventListener ( "keydown" , OnKeyDown, false );
 mainGrid = document.getElementsByClassName ( "mainGrid" ) [0];
 myShape = новый CSSTetris.ShapeZ (4);
 myShape.insertIntoGrid (mainGrid, 12, 20);
 в этом(); 

И добавьте эти две функции:

  функция init () {
     setInterval ( function () {
         myShape.moveDown ();
     }, 1000);
 }

 function OnKeyDown (event) {
     switch (event.keyCode) {
         case KEYCODE_X:
             myShape.rotate ();
             перерыв ;
         case KEYCODE_LEFT:
             myShape.moveLeft ();
             перерыв ;
         case KEYCODE_RIGHT:
             myShape.moveRight ();
             перерыв ;
         case KEYCODE_DOWN:
             myShape.moveDown ();
             перерыв ;
     }
 } 

И мы сделали! Теперь у нас есть очень простая игра, использующая CSS Grid Layout в сочетании с CSS Transforms & Animations для графической части и несколько строк кода JS, чтобы начать основы основанной на тетрисе игры.

Вот короткое видео, демонстрирующее конечный результат:

Скачать видео: MP4 , WebM , HTML5 видеоплеер от VideoJS

Вы можете загрузить окончательное решение Visual Studio, соответствующее трем шагам этого руководства, здесь: http://david.blob.core.windows.net/win8/TheRealCSSGridStory.zip

Итак, вы теперь уверены, что CSS Grid Layout был создан для того, чтобы упростить создание игр типа тетрис?


Эта статья является частью технической серии HTML5 от команды Internet Explorer. Испытайте концепции этой статьи с 3 месяцами бесплатного кросс-браузерного тестирования BrowserStack @ http://modern.IE .


Первоначально эта статья появилась в блоге Дэвида Русса MSDN Coding4Fun 12 февраля 2013 года .