Maison >interface Web >tutoriel CSS >Jeu de slider \'Puzzle\' en HTML et CSS
Passer au puzzle
L'autre jour, un souvenir m'est venu à l'esprit d'un petit puzzle de mon enfance, un puzzle coulissant dans lequel 15 tuiles carrées sont placées dans un cadre dans un arrangement de cellules 4 x 4 laissant un espace libre. Un ensemble de crêtes et de rainures sur les bords de chaque carreau et du cadre permet aux carreaux de glisser les uns sur les autres tout en les maintenant dans le cadre. À tout moment, n'importe quelle tuile adjacente à l'espace libre peut se déplacer dans cet espace, sinon les tuiles ne peuvent pas bouger. Déplacer une tuile dans l'espace libre laisse alors un nouvel espace libre d'où vient la tuile et une autre tuile peut alors se déplacer dans ce nouvel espace. L'idée est de faire glisser plusieurs fois les carreaux de cette manière pour les disposer dans un ordre prédéterminé.
Apparemment, cela s'appelle un « 15 Puzzle » et existe depuis les années 1870. La recherche sur le Web renvoie un certain nombre de récréations écrites dans une variété de langages de programmation et il existe en effet plusieurs articles ici sur dev.to, notamment https://dev.to/artydev/let-us-code-a-sliding-puzzle-9n. , https://dev.to/xzanderzone/making-a-slider-puzzle-in-java-script-83m et https://dev.to/claurcia/slide-puzzle-5c55 le tout en JavaScript et https :/ /dev.to/mfbmina/building-a-sliding-puzzle-with-go-3bnj dans Go. Il est également présenté comme un bon défi de démarrage pour ceux qui apprennent JavaScript.
Ce qui a piqué mon intérêt, c'est l'idée qu'il devrait être recréable sur le Web en utilisant aucun langage de programmation ! Autrement dit, une implémentation utilisant uniquement du HTML et du CSS purs. Je le présente donc ci-dessous. Le seul compromis que j'ai dû faire était que les 10 jeux fournis avaient des positions de départ fixes et mélangées.
Pour cela, l'ordre prédéterminé est de montrer une image complétée.
Le principe de base de cette implémentation est que chaque tuile conserve un enregistrement d'état indiquant où elle se trouve dans le cadre. Il n'existe pas beaucoup de façons de modifier et de conserver l'état en HTML et CSS, mais la plus courante est le "piratage de case à cocher", et cette implémentation en fait un usage intensif. Pour tous ceux qui ne connaissent pas le hack des cases à cocher, lorsqu'un
Donc, chaque vignette comporte une paire de groupes de boutons radio, chacun comportant quatre boutons radio. L'un de ces groupes conserve la position de la tuile sur l'axe X et l'autre sa position sur l'axe Y. (Ou respectivement position horizontale et position verticale, si vous préférez.) Les quinze tuiles reçoivent chacune initialement une combinaison différente de coordonnées X et Y via leurs boutons radio afin que chacune occupe une cellule différente dans le cadre.
Les vignettes sont initialement placées dans la cellule supérieure gauche du cadre, puis déplacées dans le cadre via CSS mesurant l'état des boutons radio en leur appliquant une transformation de traduction :
/* "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 */
La vignette contient alors également huit éléments de label, correspondant aux huit boutons radio. Chaque étiquette est positionnée de manière absolue, se superposant les unes aux autres et chacune remplit complètement la tuile. Les étiquettes sont transparentes et sont initialement configurées pour ne pas répondre aux clics et aux pressions en définissant pointer-events:none sur chacune d'entre elles.
L'étape suivante consiste pour les sélecteurs CSS à identifier l'emplacement de la cellule vide. Cela se fait par élimination, c'est la cellule dont les coordonnées X,Y ne sont représentées par la paire de groupes de boutons radio d'aucune des quinze tuiles.
Par exemple, si cela correspond :
.frame:not(:has(.tile .X0:checked~.Y0:checked)) { .... }
alors la cellule vide doit actuellement être dans la cellule du coin supérieur gauche. Répétez cette opération pour chacune des seize cellules et exactement une d'entre elles correspondra.
Une fois cela fait, les cellules adjacentes à la cellule vide peuvent être identifiées. Si la cellule vide est dans un coin, alors il y a exactement deux tuiles qui peuvent entrer dans cette cellule, sinon, si la cellule vide est contre un des côtés du cadre, il y a trois tuiles qui peuvent entrer dans la cellule, sinon la cellule vide est dans un coin. La cellule doit être l’une des quatre cellules du milieu et quatre tuiles peuvent s’y déplacer. Pour chacune de ces vignettes, exactement l'un des huit libellés des vignettes activera le bon bouton radio nécessaire pour déplacer la vignette vers la cellule vide. Cette étiquette est activée en redéfinissant la valeur de ses événements de pointeur sur auto. Donc à titre d'exemples :
/* 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; } }
The last step of the game is to identify when the puzzle is solved. This is simply a case of checking that the 15 tiles all have their expected X and Y axis radio buttons set to their "solved" position.
/* 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; }
The rest is cosmetic. The sliding is done with a simple transition of the transform described above
.tile { transition: 0.5s transform; @media (prefers-reduced-motion) { transition: none; } }
and each tile shows a portion of the game's image using background-size and 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 */
and there's a single set of radio buttons to choose which of the ten games to play.
To play the game, simply click or tap on the tile you want to slide to the empty cell.
I've also provided a "barebones" mode to show the tile letters and radio buttons which might help with the understanding of how the HTML and CSS works.
So here's the completed puzzle game. Please let me know any feedback you have.
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!