퍼즐로 건너뛰기
어느 날 어린 시절의 작은 퍼즐 장난감에 대한 기억이 떠올랐습니다. 슬라이더 퍼즐은 15개의 정사각형 타일이 4 x 4 배열의 셀로 프레임에 배치되어 하나의 여유 공간을 남기는 것이었습니다. 각 타일과 프레임의 가장자리에 있는 일련의 능선과 홈을 통해 타일이 프레임에 타일을 고정하는 동안 서로 미끄러져 지나갈 수 있습니다. 주어진 시간에 여유 공간에 인접한 모든 타일은 해당 공간으로 이동할 수 있으며, 그렇지 않으면 타일이 이동할 수 없습니다. 타일을 여유 공간으로 이동하면 타일이 있던 자리에 새로운 여유 공간이 남고 다른 타일이 해당 새 공간으로 이동할 수 있습니다. 아이디어는 이러한 방식으로 타일을 반복적으로 밀어 타일을 미리 정해진 순서로 배열하는 것입니다.
분명히 이것은 "15 퍼즐"이라고 불리며 1870년대부터 존재해 왔습니다. 웹을 검색하면 다양한 프로그래밍 언어로 작성된 여러 가지 레크리에이션이 반환되며 실제로 https://dev.to/artydev/let-us-code-a-sliding-puzzle-9n을 포함하여 여기 dev.to에 여러 기사가 있습니다. , 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에서 상태를 변경하고 유지하는 방법은 많지 않지만 가장 일반적인 것은 '체크박스 해킹'이며 이 구현에서는 이를 많이 활용합니다. 체크박스 해킹에 익숙하지 않은 분들을 위해 설명하자면,
따라서 각 타일에는 각각 4개의 라디오 버튼이 있는 한 쌍의 라디오 버튼 그룹이 있습니다. 이러한 그룹 중 하나는 X축의 타일 위치를 유지하고 다른 그룹은 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개의 레이블 요소도 포함됩니다. 각 레이블은 서로 겹쳐지는 절대 위치에 있으며 각 레이블은 타일을 완전히 채웁니다. 레이블은 투명하며 처음에는 모든 레이블에 포인터 이벤트:없음을 설정하여 클릭 및 탭에 응답하지 않도록 설정됩니다.
다음 단계는 CSS 선택기가 빈 셀의 위치를 식별하는 것입니다. 이는 제거에 의해 수행되며 X, Y 좌표가 15개 타일 중 라디오 버튼 그룹 쌍으로 표시되지 않는 셀입니다.
예를 들어 다음과 일치하는 경우:
.frame:not(:has(.tile .X0:checked~.Y0:checked)) { .... }
그러면 빈 셀이 현재 왼쪽 상단 셀에 있어야 합니다. 16개의 셀 각각에 대해 이 과정을 반복하면 그 중 정확히 하나만 일치합니다.
이 작업이 완료되면 빈 셀에 인접한 셀을 식별할 수 있습니다. 빈 셀이 모서리에 있으면 해당 셀로 이동할 수 있는 타일은 정확히 두 개입니다. 그렇지 않고 빈 셀이 프레임 측면 중 하나에 있으면 셀로 이동할 수 있는 타일은 세 개입니다. 그렇지 않으면 빈 셀입니다. 셀은 4개의 중간 셀 중 하나여야 하며, 해당 셀로 이동할 수 있는 4개의 타일이 있습니다. 각 타일에 대해 타일의 8개 라벨 중 정확히 하나가 타일을 빈 셀로 이동하는 데 필요한 올바른 라디오 버튼을 활성화합니다. 해당 레이블은 포인터 이벤트 값을 다시 자동으로 설정하여 활성화됩니다. 예를 들어:
/* 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 */
그리고 10개의 게임 중 어떤 게임을 플레이할지 선택할 수 있는 단일 라디오 버튼 세트가 있습니다.
게임을 플레이하려면 빈 셀로 슬라이드하려는 타일을 클릭하거나 탭하세요.
또한 HTML 및 CSS 작동 방식을 이해하는 데 도움이 될 수 있는 타일 문자와 라디오 버튼을 표시하는 "베어본" 모드를 제공했습니다.
자, 완성된 퍼즐 게임은 이렇습니다. 피드백이 있으면 알려주시기 바랍니다.
부인 성명: 제공된 모든 리소스는 부분적으로 인터넷에서 가져온 것입니다. 귀하의 저작권이나 기타 권리 및 이익이 침해된 경우 자세한 이유를 설명하고 저작권 또는 권리 및 이익에 대한 증거를 제공한 후 이메일([email protected])로 보내주십시오. 최대한 빨리 처리해 드리겠습니다.
Copyright© 2022 湘ICP备2022001581号-3