Перейти к загадке
На днях мне в голову пришло воспоминание о маленькой игрушке-головоломке из моего детства, головоломке-слайдере, в которой 15 квадратных плиток помещены в рамку в порядке расположения ячеек 4 х 4, оставляя одно свободное место. Набор выступов и канавок по краям каждой плитки и рамы позволяет плиткам скользить друг по другу, удерживая плитки в рамке. В любой момент времени любая плитка, примыкающая к свободному пространству, может переместиться в это пространство, в противном случае перемещение плиток невозможно. При перемещении плитки в свободное пространство остается новое свободное пространство, откуда пришла плитка, и другая плитка может затем переместиться в это новое пространство. Идея состоит в том, чтобы путем многократного сдвига плиток расположить их в некотором заранее определенном порядке.
Очевидно, это называется «Пазл 15» и существует с 1870-х годов. Поиск в Интернете выдает множество воссозданий, написанных на разных языках программирования, и действительно, на dev.to есть несколько статей, включая https://dev.to/artydev/let-us-code-a-sliding-puzzle-9n. , https://dev.to/xzanderzone/making-a-slider-puzzle-in-java-script-83m и https://dev.to/claurcia/slide-puzzle-5c55 — все на JavaScript и https:/ /dev.to/mfbmina/building-a-sliding-puzzle-with-go-3bnj в Go. Он также представлен как хорошее начальное задание для тех, кто изучает JavaScript.
Что меня заинтересовало, так это идея о том, что его можно воссоздать в Интернете, вообще не используя язык программирования! То есть реализация, использующая только чистый HTML и CSS. Поэтому я представляю это ниже. Единственный компромисс, на который мне пришлось пойти, заключался в том, что в 10 предоставленных играх были фиксированные, предварительно перетасованные стартовые позиции.
Для этого задан заранее порядок показа законченного изображения.
Основной принцип этой реализации заключается в том, что каждый фрагмент сохраняет запись о том, где он находится в кадре. В HTML и CSS не так много способов изменить и сохранить состояние, но наиболее распространенным является «взлом флажка», и в этой реализации он активно используется. Для тех, кто не знаком с хаком с флажками, при щелчке или касании элемента
Таким образом, каждая плитка имеет пару групп переключателей, каждая из которых содержит четыре переключателя. Одна из этих групп сохраняет положение плитки по оси X, а другая — по оси Y. (Или горизонтальное и вертикальное положение соответственно, если хотите.) Каждому из пятнадцати плиток изначально присваивается разная комбинация координат X и Y с помощью переключателей, так что каждая из них занимает отдельную ячейку в кадре.
Плитки изначально размещаются в верхней левой ячейке фрейма, а затем перемещаются внутри фрейма с помощью CSS, измеряя состояние переключателей, применяя к ним преобразование перевода:
/* "X" refers to the X-axis cell positions, "Y" to the Y-axis cell positions. * 0, 1, 2, 3 refers to the position on that axis, * 0 = left and top, 3 = right and bottom respectively. */ .tile:has(.X0:checked~.Y0:checked) { transform: translate(0%, 0%); } .tile:has(.X0:checked~.Y1:checked) { transform: translate(0%, 100%); } .tile:has(.X0:checked~.Y2:checked) { transform: translate(0%, 200%); } .tile:has(.X0:checked~.Y3:checked) { transform: translate(0%, 300%); } .tile:has(.X1:checked~.Y0:checked) { transform: translate(100%, 0%); } /* and so on for the remainder of the sixteen combinations */
Плитка также содержит восемь элементов метки, соответствующих восьми переключателям. Каждая метка абсолютно позиционируется, накладываясь друг на друга, и каждая полностью заполняет плитку. Метки прозрачны и изначально настроены так, чтобы не реагировать на щелчки и касания, путем установки для всех из них pointer-events:none.
Следующий шаг — селекторы CSS должны определить, где находится пустая ячейка. Это делается методом исключения: это ячейка, координаты X,Y которой не представлены парой групп переключателей ни на одной из пятнадцати плиток.
Например, если это соответствует:
.frame:not(:has(.tile .X0:checked~.Y0:checked)) { .... }
тогда пустая ячейка должна находиться в верхнем левом углу ячейки. Повторите это для каждой из шестнадцати ячеек, и ровно одна из них будет совпадать.
Как только это будет сделано, можно будет идентифицировать ячейки, соседние с пустой ячейкой. Если пустая ячейка находится в углу, то есть ровно две плитки, которые могут переместиться в эту ячейку, в противном случае, если пустая ячейка находится напротив одной из сторон кадра, есть три плитки, которые могут переместиться в ячейку, в противном случае пустая ячейка ячейка должна быть одной из четырех средних ячеек, и есть четыре плитки, которые могут переместиться в нее. Для каждой из этих плиток ровно одна из восьми меток плитки активирует правильный переключатель, необходимый для перемещения плитки в пустую ячейку. Эта метка включается путем установки значения ее указателя-событий обратно в значение auto. Итак, примеры:
/* Top, left corner */ .frame:not(:has(.tile .X0:checked ~ .Y0:checked)) { :is( .tile:has(.X0:checked ~ .Y1:checked) label.Y0, .tile:has(.X1:checked ~ .Y0:checked) label.X0 ) { pointer-events: auto; } } /* right most cell of row two */ .frame:not(:has(.tile .X1:checked ~ .Y3:checked)) { :is( .tile:has(.X1:checked ~ .Y2:checked) label.Y3, .tile:has(.X0:checked ~ .Y3:checked) label.X1, .tile:has(.X2:checked ~ .Y3:checked) label.X1 ) { pointer-events: auto; } } /* second cell from left on row three */ .frame:not(:has(.tile .X2:checked ~ .Y1:checked)) { :is( .tile:has(.X2:checked ~ .Y0:checked) label.Y1, .tile:has(.X2:checked ~ .Y2:checked) label.Y1, .tile:has(.X1:checked ~ .Y1:checked) label.X2, .tile:has(.X3:checked ~ .Y1:checked) label.X2 ) { pointer-events: auto; } }
Последний шаг игры — определить, когда головоломка решена. Это просто случай проверки того, что для всех 15 плиток ожидаемые переключатели осей X и Y установлены в «решенное» положение.
/* Each tile is assigned a letter "a" to "o". * The puzzle is solved when the tiles are in alphabetical order * reading left to right and top to bottom */ .frame:has(.a .X0:checked ~ .Y0:checked):has(.b .X1:checked ~ .Y0:checked):has( .c .X2:checked ~ .Y0:checked ):has(.d .X3:checked ~ .Y0:checked):has(.e .X0:checked ~ .Y1:checked):has( .f .X1:checked ~ .Y1:checked ):has(.g .X2:checked ~ .Y1:checked):has(.h .X3:checked ~ .Y1:checked):has( .i .X0:checked ~ .Y2:checked ):has(.j .X1:checked ~ .Y2:checked):has(.k .X2:checked ~ .Y2:checked):has( .l .X3:checked ~ .Y2:checked ):has(.m .X0:checked ~ .Y3:checked):has(.n .X1:checked ~ .Y3:checked):has( .o .X2:checked ~ .Y3:checked ) ~ .options .success { display: block; }
Остальное — косметика. Скольжение осуществляется с помощью простого перехода описанного выше преобразования
.tile { transition: 0.5s transform; @media (prefers-reduced-motion) { transition: none; } }
и каждая плитка показывает часть изображения игры с использованием размера фона и положения фона
.tile { background-size: 400%; } #board1 .tile { background-image: url("https://alohci.net/image/dev.to/slidergame/mullermarc-k7bQqdUf954-unsplash.webp"); } .a { background-position: 0% 0%; } .b { background-position: 33.333% 0%; } .c { background-position: 66.667% 0%; } .d { background-position: 100% 0%; } .e { background-position: 0% 33.333%; } /* and so on for the remaining tiles */
и есть один набор переключателей, позволяющий выбрать, в какую из десяти игр играть.
Чтобы начать игру, просто нажмите или коснитесь плитки, которую хотите переместить в пустую ячейку.
Я также предоставил «базовый» режим для отображения букв плитки и переключателей, который может помочь понять, как работают HTML и CSS.
Итак, вот законченная игра-головоломка. Пожалуйста, дайте мне знать, если у вас есть отзывы.
Отказ от ответственности: Все предоставленные ресурсы частично взяты из Интернета. В случае нарушения ваших авторских прав или других прав и интересов, пожалуйста, объясните подробные причины и предоставьте доказательства авторских прав или прав и интересов, а затем отправьте их по электронной почте: [email protected]. Мы сделаем это за вас как можно скорее.
Copyright© 2022 湘ICP备2022001581号-3