パズルへスキップ
先日、子供の頃の小さなパズルおもちゃの思い出が頭に浮かびました。それは、15 個の正方形のタイルが 4 x 4 のセル配置でフレーム内に 1 つの空きスペースを残して配置されるスライダー パズルです。各タイルとフレームの端にある一連の隆起と溝により、タイルをフレーム内に保持しながらタイルが互いにスライドして通過できます。いつでも、空きスペースに隣接するタイルはそのスペースに移動できますが、それ以外の場合、タイルは移動できません。タイルを空きスペースに移動すると、タイルの元の新しい空きスペースが残り、別のタイルがその新しいスペースに移動できるようになります。この方法でタイルを繰り返しスライドさせて、あらかじめ決められた順序にタイルを配置するというアイデアです。
これは「15 パズル」と呼ばれるもので、1870 年代から存在しているようです。 Web を検索すると、さまざまなプログラミング言語で書かれた多数のレクリエーションが表示されます。実際、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:/ Go の /dev.to/mfbmina/building-a-sliding-puzzle-with-go-3bnj。これは、JavaScript を学習する人にとって良い入門課題としても提示されています。
しかし、私の興味をそそられたのは、プログラミング言語をまったく使用せずに Web 上で再作成できるべきだという考えでした。つまり、純粋な HTML と CSS だけを使用した実装です。そこで以下に紹介します。私がしなければならなかった 1 つの妥協点は、提供されている 10 ゲームがシャッフル前の開始位置を固定しているということでした。
このために、あらかじめ決められた順序は、完成した写真を表示することです。
この実装の基本原理は、各タイルがフレーム内のどこにあるかの状態記録を保持することです。 HTML や CSS で状態を変更したり保持したりする方法はそれほど多くありませんが、最も一般的なのは「チェックボックス ハック」であり、この実装ではそれを多用しています。チェックボックス ハックに詳しくない人のために説明すると、
したがって、各タイルには、それぞれ 4 つのラジオ ボタンを持つ 2 つのラジオ ボタン グループがあります。これらのグループの 1 つは X 軸でのタイルの位置を保持し、もう 1 つは Y 軸での位置を保持します。 (または、必要に応じて、それぞれ水平位置と垂直位置を指定します。) 15 個のタイルには、それぞれがフレーム内の異なるセルを占めるように、最初にラジオ ボタンを介して 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 */
タイルには、8 つのラジオ ボタンに対応する 8 つのラベル要素も含まれます。各ラベルは絶対に互いに重なって配置され、それぞれがタイルを完全に埋め尽くします。ラベルは透明で、最初はすべてのラベルに pointer-events:none を設定することで、クリックやタップに反応しないように設定されています。
次のステップは、CSS セレクターが空のセルがどこにあるかを識別することです。これは消去によって行われます。これは、X、Y 座標が 15 個のタイルのいずれのラジオ ボタン グループ ペアによっても表されていないセルです。
たとえば、これが一致する場合:
.frame:not(:has(.tile .X0:checked~.Y0:checked)) { .... }
その場合、空のセルは現在左上隅のセルにある必要があります。 16 個のセルごとにこれを繰り返すと、そのうちの 1 つだけが一致します。
そうすると、空きセルに隣接するセルが特定できます。空のセルが隅にある場合、そのセルに移動できるタイルはちょうど 2 つあります。そうでない場合、空のセルがフレームのいずれかの辺にある場合、セルに移動できるタイルは 3 つあり、そうでない場合は、空のセルに移動できます。セルは中央の 4 つのセルの 1 つである必要があり、そこに移動できるタイルは 4 つあります。これらのタイルのそれぞれについて、タイルの 8 つのラベルのうち 1 つだけで、タイルを空のセルに移動するために必要な正しいラジオ ボタンがアクティブになります。このラベルは、pointer-events の値を 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; } }
そして各タイルには、background-size と background-position を使用してゲームの画像の一部が表示されます
.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 */
また、10 種類のゲームのうちどれをプレイするかを選択するラジオ ボタンのセットが 1 つあります。
ゲームをプレイするには、空のセルにスライドさせたいタイルをクリックまたはタップするだけです。
HTML と CSS がどのように機能するかを理解するのに役立つタイル文字とラジオ ボタンを表示する「ベアボーン」モードも提供しました。
完成したパズルゲームがこちらです。ご意見がございましたらお聞かせください。
免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3