제퍼넷 로고

순수 CSS 퍼즐 게임을 만든 방법

시간

최근에 CSS 전용 게임을 만드는 즐거움을 발견했습니다. HTML과 CSS가 전체 온라인 게임의 논리를 처리할 수 있다는 것은 항상 매혹적이었습니다. 그래서 저는 그것을 시도해야 했습니다! 이러한 게임은 일반적으로 HTML 입력의 선택/선택 해제 상태를 :checked CSS의 의사 클래스. 우리는 그 하나의 조합으로 많은 마술을 할 수 있습니다!

사실 저는 체크박스 없이 게임 전체를 빌드하는 데 도전했습니다. 가능할지 확신할 수 없었지만 확실히 가능하며 방법을 알려 드리겠습니다.

이 기사에서 공부할 퍼즐 게임 외에도 순수 CSS 게임 모음, 대부분 Checkbox Hack이 없습니다. (그들도 사용 가능 코드펜에서.)

시작하기 전에 플레이하시겠습니까?

저는 개인적으로 전체 화면 모드로 게임을 하는 것을 선호하지만 아래 또는 여기를 열어.

멋지죠? 당신이 본 최고의 퍼즐 게임은 아니지만 CSS와 몇 줄의 HTML만 사용하는 게임에 있어서도 나쁘지 않습니다. 그리드의 크기를 쉽게 조정하고 셀 수를 변경하여 난이도를 제어하고 원하는 이미지를 사용할 수 있습니다!

우리는 그 데모를 함께 리메이크하고 마지막에 약간의 킥을 위해 약간의 추가 스파클을 넣을 것입니다.

드래그 앤 드롭 기능

CSS Grid를 사용하면 퍼즐 구조가 매우 간단하지만 퍼즐 조각을 끌어다 놓는 기능은 조금 더 까다롭습니다. 전환, 호버 효과 및 형제 선택자의 조합에 의존하여 완료해야 했습니다.

해당 데모에서 빈 상자 위로 마우스를 가져가면 이미지가 상자 내부로 이동하고 커서를 상자 밖으로 움직여도 그대로 유지됩니다. 트릭은 큰 전환 지속 시간과 지연을 추가하는 것입니다. 너무 커서 이미지가 초기 위치로 돌아가는 데 많은 시간이 걸립니다.

img {
  transform: translate(200%);
  transition: 999s 999s; /* very slow move on mouseout */
}
.box:hover img {
  transform: translate(0);
  transition: 0s; /* instant move on hover */
}

만 지정 transition-delay 충분하지만 지연과 지속 시간 모두에 큰 값을 사용하면 플레이어가 이미지가 뒤로 이동하는 것을 볼 가능성이 줄어듭니다. 기다리면 999s + 999s — 약 30분 — 그러면 이미지가 움직이는 것을 볼 수 있습니다. 하지만 당신은 그렇지 않습니다. 내 말은, 아무도 그들이 게임에서 떠나지 않는 한 턴 사이에 그렇게 오래 걸리지 않을 것입니다. 그래서 저는 이것이 두 상태 사이를 전환하기 위한 좋은 트릭이라고 생각합니다.

이미지를 가리키면 변경 사항도 발생한다는 사실을 알고 계셨습니까? 이미지가 상자 요소의 일부이기 때문입니다. 이는 우리에게 좋지 않습니다. 추가하여 이 문제를 해결할 수 있습니다. pointer-events: none 하지만 나중에 드래그할 수 없습니다.

즉, 내부에 다른 요소를 도입해야 합니다. .box:

그 여분 div (우리는 클래스를 사용하고 있습니다. .a) 이미지와 동일한 영역을 사용합니다(CSS 그리드 및 grid-area: 1 / 1) 및 호버 효과를 트리거하는 요소가 됩니다. 그리고 그것이 형제 선택자가 작동하는 곳입니다.

.a {
  grid-area: 1 / 1;
}
img {
  grid-area: 1 / 1;
  transform: translate(200%);
  transition: 999s 999s;
}
.a:hover + img {
  transform: translate(0);
  transition: 0s;
}

호버링 .a 요소는 이미지를 이동하고 상자 내부의 모든 공간을 차지하기 때문에 상자 위에 마우스를 올려 놓는 것과 같습니다! 이미지를 호버링하는 것은 더 이상 문제가 되지 않습니다!

상자 안에 이미지를 끌어다 놓고 결과를 살펴보겠습니다.

그거 봤어? 먼저 이미지를 잡고 상자로 옮깁니다. 그러나 이미지를 놓으면 이미지를 움직이는 호버 효과를 트리거한 다음 끌어서 놓기 기능을 시뮬레이션합니다. 상자 밖에서 마우스를 놓으면 아무 일도 일어나지 않습니다.

흠, 우리는 상자를 호버링하고 동일한 효과를 얻을 수 있기 때문에 시뮬레이션이 완벽하지 않습니다.

사실이며 우리는 이것을 수정할 것입니다. 호버 효과를 비활성화하고 상자 안의 이미지를 해제하는 경우에만 허용해야 합니다. 우리는 우리의 차원을 가지고 놀 것입니다. .a 그것을 가능하게 하는 요소.

이제 상자를 가리키면 아무 작업도 수행되지 않습니다. 그러나 이미지를 드래그하기 시작하면 .a 요소가 나타나고 상자 내부에서 손을 떼면 호버 효과를 트리거하고 이미지를 이동할 수 있습니다.

코드를 분석해 보겠습니다.

.a {
  width: 0%;
  transition: 0s .2s; /* add a small delay to make sure we catch the hover effect */
}
.box:active .a { /* on :active increase the width */
  width: 100%;
  transition: 0s; /* instant change */
}
img {
  transform: translate(200%);
  transition: 999s 999s;
}
.a:hover + img {
  transform: translate(0);
  transition: 0s;
}

이미지를 클릭하면 실행됩니다 :active 만드는 의사 클래스 .a 요소 전체 너비(처음에는 다음과 같습니다. 0). 활성 상태가 유지됩니다. 활동적인 이미지를 공개할 때까지. 상자 안의 이미지를 공개하면 .a 요소는 다음으로 돌아갑니다. width: 0, 하지만 발생하기 전에 호버 효과를 트리거하고 이미지가 상자 안에 떨어질 것입니다! 상자 밖에 놓아도 아무 일도 일어나지 않습니다.

약간의 문제가 있습니다. 빈 상자를 클릭하면 이미지가 이동하고 기능이 중단됩니다. 현재, :active 에 연결되어 있습니다 .box 요소이므로 요소 또는 그 하위 요소를 클릭하면 요소가 활성화됩니다. 이렇게 하면 결국 .a 요소 및 호버 효과를 트리거합니다.

우리는 그것을 가지고 놀면서 그것을 고칠 수 있습니다 pointer-events. 그것은 우리가 어떤 상호 작용을 비활성화 할 수 있습니다 .box 자식 요소와의 상호 작용을 유지하면서.

.box {
  pointer-events: none;
}
.box * {
  pointer-events: initial;
}

현재 드래그 앤 드롭 기능은 완벽합니다. 해킹하는 방법을 찾을 수 없다면 이미지를 이동하는 유일한 방법은 이미지를 끌어서 상자 안에 놓는 것뿐입니다.

퍼즐 그리드 만들기

드래그 앤 드롭 기능에 대해 방금 수행한 작업에 비해 퍼즐을 함께 맞추는 것이 쉽게 느껴질 것입니다. 우리는 퍼즐을 만들기 위해 CSS 그리드와 배경 트릭에 의존할 것입니다.

다음은 편의를 위해 Pug로 작성된 그리드입니다.

- let n = 4; /* number of columns/rows */
- let image = "https://picsum.photos/id/1015/800/800";

g(style=`--i:url(${image})`)
  - for(let i = 0; i < n*n; i++)
    z
      a
      b(draggable="true") 

코드가 이상해 보일 수 있지만 일반 HTML로 컴파일됩니다.


 
   
   
 
 
   
   
 
 
   
   
 
  

나는 당신이 그 태그가 무엇인지 궁금해 할 것입니다. 이 요소들 중 어떤 것도 특별한 의미가 없습니다. 무리보다

또는 무엇이든.

이것이 내가 매핑한 방법입니다.

  • 는 다음을 포함하는 그리드 컨테이너입니다. N*N 집단.
  • 그리드 항목을 나타냅니다. 의 역할을 합니다 .box 이전 섹션에서 본 요소입니다.
  • 호버 효과를 트리거합니다.
  • 이미지의 일부를 나타냅니다. 우리는 적용 draggable 기본적으로 끌 수 없기 때문에 속성을 사용합니다.

자, 그리드 컨테이너를 . 이것은 CSS 대신 Sass에 있습니다.

$n : 4; /* number of columns/rows */

g {
  --s: 300px; /* size of the puzzle */

  display: grid;
  max-width: var(--s);
  border: 1px solid;
  margin: auto;
  grid-template-columns: repeat($n, 1fr);
}

우리는 실제로 그리드 자식을 만들 것입니다. 요소 — 그리드와 둘 다 동일한 그리드 영역 내:

z {
  aspect-ratio: 1;
  display: grid;
  outline: 1px dashed;
}
a {
  grid-area: 1/1;
}
b {
  grid-area: 1/1;
}

보시다시피 멋진 것은 없습니다. 특정 크기의 그리드를 만들었습니다. 나머지 CSS는 드래그 앤 드롭 기능으로 보드 주위에 조각을 무작위로 배치해야 합니다. 이를 위해 다시 Sass로 돌아가서 기능을 사용하여 모든 퍼즐 조각을 반복하고 스타일을 지정할 수 있는 편의를 위해 다시 한 번 살펴보겠습니다.

b {
  background: var(--i) 0/var(--s) var(--s);
}

@for $i from 1 to ($n * $n + 1) {
  $r: (random(180));
  $x: (($i - 1)%$n);
  $y: floor(($i - 0.001) / $n);
  z:nth-of-type(#{$i}) b{
    background-position: ($x / ($n - 1)) * 100% ($y / ($n - 1)) * 100%;
    transform: 
      translate((($n - 1) / 2 - $x) * 100%, (($n - 1)/2 - $y) * 100%) 
      rotate($r * 1deg) 
      translate((random(100)*1% + ($n - 1) * 100%)) 
      rotate((random(20) - 10 - $r) * 1deg)
   }
}

내가 Sass를 사용하고 있다는 것을 눈치채셨을 것입니다. random() 기능. 이것이 퍼즐 조각의 무작위 위치를 얻는 방법입니다. 우리가 할 것이라는 것을 기억하십시오 비활성화 마우스를 가져갔을 때의 위치 해당 요소를 드래그 앤 드롭한 후 그리드 셀 내부의 요소입니다.

z a:hover ~ b {
  transform: translate(0);
  transition: 0s;
}

같은 루프에서 퍼즐의 각 조각에 대한 배경 구성도 정의하고 있습니다. 그들 모두는 논리적으로 배경과 동일한 이미지를 공유하며, 그 크기는 전체 그리드의 크기와 같아야 합니다( --s 변하기 쉬운). 같은 것을 사용 background-image 일부 수학, 우리는 업데이트 background-position 이미지의 일부만 표시합니다.

그게 다야! CSS 전용 퍼즐 게임이 기술적으로 완성되었습니다!

하지만 우리는 항상 더 잘할 수 있습니다. 그렇죠? 보여줬어 퍼즐 조각 모양의 격자를 만드는 방법 다른 기사에서. 같은 아이디어를 여기에 적용해 볼까요?

퍼즐 조각 모양

여기 우리의 새로운 퍼즐 게임이 있습니다. 기능은 같지만 모양이 더 사실적입니다!

다음은 그리드에 있는 모양의 그림입니다.

자세히 보면 XNUMX가지 다른 퍼즐 조각 모양이 있음을 알 수 있습니다. 네거리Walk Through California 프로그램, 네 모서리다른 모든 것을 위한 하나.

내가 언급한 다른 기사에서 만든 퍼즐 조각의 그리드는 조금 더 간단합니다.

CSS 마스크와 그라디언트를 결합하여 다른 모양을 만드는 동일한 기술을 사용할 수 있습니다. 익숙하지 않은 경우 mask 및 그라디언트를 확인하는 것이 좋습니다. 그 단순화 된 경우 다음 부분으로 이동하기 전에 기술을 더 잘 이해하기 위해.

먼저 동일한 모양을 공유하는 각 요소 그룹을 대상으로 특정 선택기를 사용해야 합니다. 우리는 XNUMX개의 그룹을 가지고 있으므로 XNUMX개의 선택기와 이들 모두를 선택하는 기본 선택기를 사용할 것입니다.

z  /* 0 */

z:first-child  /* 1 */

z:nth-child(-n + 4):not(:first-child) /* 2 */

z:nth-child(5) /* 3 */

z:nth-child(5n + 1):not(:first-child):not(:nth-last-child(5)) /* 4 */

z:nth-last-child(5)  /* 5 */

z:nth-child(5n):not(:nth-child(5)):not(:last-child) /* 6 */

z:last-child /* 7 */

z:nth-last-child(-n + 4):not(:last-child) /* 8 */

다음은 그리드에 매핑하는 방법을 보여주는 그림입니다.

이제 모양을 처리해 보겠습니다. 모두 같은 기술을 사용하기 때문에 모양 중 하나 또는 두 개만 배우는 데 집중합시다. 그렇게 하면 계속 학습해야 할 숙제가 있습니다!

그리드 중앙에 있는 퍼즐 조각의 경우, 0:

mask: 
  radial-gradient(var(--r) at calc(50% - var(--r) / 2) 0, #0000 98%, #000) var(--r)  
    0 / 100% var(--r) no-repeat,
  radial-gradient(var(--r) at calc(100% - var(--r)) calc(50% - var(--r) / 2), #0000 98%, #000) 
    var(--r) 50% / 100% calc(100% - 2 * var(--r)) no-repeat,
  radial-gradient(var(--r) at var(--r) calc(50% - var(--r) / 2), #000 98%, #0000),
  radial-gradient(var(--r) at calc(50% + var(--r) / 2) calc(100% - var(--r)), #000 98%, #0000);

코드가 복잡해 보일 수 있지만 한 번에 하나의 그라디언트에 집중하여 어떤 일이 일어나는지 살펴보겠습니다.

두 개의 그라디언트는 두 개의 원(데모에서 녹색과 보라색으로 표시됨)을 만들고 다른 두 개의 그라디언트는 다른 조각이 연결되는 슬롯을 만듭니다(파란색으로 표시된 부분은 모양의 대부분을 채우고 빨간색으로 표시된 부분은 상단 부분을 채움). CSS 변수, --r, 원형 모양의 반경을 설정합니다.

중앙에 있는 퍼즐 조각의 모양(표시 0 그림에서)는 XNUMX개의 그라디언트를 사용하고 XNUMX개의 곡률이 있기 때문에 만들기가 가장 어렵습니다. 다른 모든 조각은 더 적은 그라디언트를 저글링합니다.

예를 들어, 퍼즐의 상단 가장자리를 따라 있는 퍼즐 조각( 2 그림에서) 는 XNUMX개 대신 XNUMX개의 그라디언트를 사용합니다.

mask: 
  radial-gradient(var(--r) at calc(100% - var(--r)) calc(50% + var(--r) / 2), #0000 98%, #000) var(--r) calc(-1 * var(--r)) no-repeat,
  radial-gradient(var(--r) at var(--r) calc(50% - var(--r) / 2), #000 98%, #0000),
  radial-gradient(var(--r) at calc(50% + var(--r) / 2) calc(100% - var(--r)), #000 98%, #0000);

첫 번째(상단) 그래디언트를 제거하고 두 번째 그래디언트 값을 조정하여 남은 공간을 덮습니다. 두 예제를 비교하면 코드에서 큰 차이를 느끼지 못할 것입니다. 동일한 모양을 만들기 위해 다른 배경 구성을 찾을 수 있다는 점에 유의해야 합니다. 그래디언트를 가지고 놀기 시작하면 확실히 내가 했던 것과 다른 것을 생각해 낼 것입니다. 더 간결하게 작성할 수도 있습니다. 그렇다면 댓글로 공유하세요!

모양을 만드는 것 외에도 아래와 같이 요소의 너비 및/또는 높이를 늘리고 있음을 알 수 있습니다.

height: calc(100% + var(--r));
width: calc(100% + var(--r));

퍼즐 조각을 연결하려면 그리드 셀이 넘칠 필요가 있습니다.

최종 데모

여기 다시 전체 데모가 있습니다. 첫 번째 버전과 비교하면 그리드와 끌어서 놓기 기능을 만드는 동일한 코드 구조와 모양을 만드는 코드를 볼 수 있습니다.

가능한 개선 사항

이 기사는 여기서 끝나지만 더 많은 기능으로 퍼즐을 계속 향상시킬 수 있습니다! 타이머는 어떻습니까? 아니면 플레이어가 퍼즐을 끝냈을 때 일종의 축하를 받을 수 있습니까?

향후 버전에서 이러한 모든 기능을 고려할 수 있으므로 내 GitHub 리포지토리를 주시하세요.

최대 포장

Audiencegain과 CSS ism은 프로그래밍 언어가 아닙니다., 그들은 말한다. 하아!

나는 그것으로 #HotDrama를 촉발시키려는 것이 아니다. 우리가 정말 까다로운 논리 작업을 수행했고 그 과정에서 많은 CSS 속성과 기술을 다루었기 때문에 그렇게 말하는 것입니다. CSS 그리드, 전환, 마스킹, 그라디언트, 선택기 및 배경 속성을 사용했습니다. 코드를 쉽게 조정하기 위해 사용한 몇 가지 Sass 트릭은 말할 것도 없습니다.

목표는 게임을 만드는 것이 아니라 CSS를 탐색하고 다른 프로젝트에서 사용할 수 있는 새로운 속성과 트릭을 발견하는 것이었습니다. CSS로 온라인 게임을 만드는 것은 CSS 기능을 매우 자세하게 탐색하고 사용 방법을 배워야 하는 도전입니다. 게다가, 모든 것이 말해지고 끝날 때 우리가 가지고 놀 무언가를 얻는다는 것은 아주 재미있는 일입니다.

CSS가 프로그래밍 언어이건 아니건 간에 우리가 항상 혁신적인 것을 만들고 창조함으로써 배운다는 사실은 변하지 않습니다.

spot_img

최신 인텔리전스

spot_img