3D 게임 메뉴 구성요소 빌드

액세스가 가능하고 반응형의 적응형 3D 게임 메뉴를 빌드하는 방법에 관한 기본 개요입니다.

이 게시물에서는 3D 게임 메뉴 구성 요소를 빌드하는 방법에 대한 생각을 공유하고자 합니다. 이 demo

<ph type="x-smartling-placeholder">
</ph> <ph type="x-smartling-placeholder">
</ph> 데모

동영상을 선호한다면 이 게시물의 YouTube 버전을 참고하세요.

개요

비디오 게임은 사용자에게 창의적이고 특이한 메뉴, 애니메이션, 3D 공간에서도 활용할 수 있습니다. 새로운 AR/VR 게임에서는 메뉴가 마치 우주에 떠다니죠. 오늘은 이 효과의 본질을 다시 만들 것이지만 적응형 색 구성표와 사용자를 위한 숙박 시설까지 더해졌기 때문에 움직임이 적은 것을 선호합니다.

HTML

게임 메뉴는 버튼 목록입니다. 이를 HTML로 표현하는 가장 좋은 방법은 다음과 같습니다.

<ul class="threeD-button-set">
  <li><button>New Game</button></li>
  <li><button>Continue</button></li>
  <li><button>Online</button></li>
  <li><button>Settings</button></li>
  <li><button>Quit</button></li>
</ul>

버튼 목록은 스크린 리더 기술에 잘 알려져 있으며 는 JavaScript나 CSS 없이도 작동합니다.

a
글머리기호 목록으로 보기에는 일반 버튼이 항목처럼 표시되어 있습니다.

CSS

버튼 목록의 스타일 지정은 다음과 같은 상위 단계로 분류됩니다.

  1. 맞춤 속성 설정
  2. Flexbox 레이아웃
  3. 장식용 유사 요소가 포함된 맞춤 버튼
  4. 요소를 3D 공간에 배치

맞춤 속성 개요

커스텀 속성은 의미 있는 속성을 지정하여 값을 명확하게 구분하는 데 도움이 됩니다. 임의의 값으로 바꾸는 것을 허용하므로, 반복되는 코드와 공유를 피할 수 있습니다. 가치를 얻을 수 있다는 것입니다.

다음은 CSS 변수로 저장된 미디어 쿼리(맞춤 설정이라고도 함)입니다. 미디어라고 합니다. 이들은 전역적이며 는 코드를 간결하고 읽기 쉽게 유지하기 위해 다양한 선택기에서 사용됩니다. 이 게임 메뉴 구성요소에서 모션 사용 환경설정, 시스템 색상 스키마, 및 색상 범위 기능을 디스플레이.

@custom-media --motionOK (prefers-reduced-motion: no-preference);
@custom-media --dark (prefers-color-scheme: dark);
@custom-media --HDcolor (dynamic-range: high);

다음 사용자 지정 속성은 색 구성표를 관리하고 마우스 버튼을 누른 상태에서 마우스 오버를 통해 게임 메뉴를 대화형으로 만들기 위한 위치 값 커스텀 이름 지정 속성은 값 또는 값의 결과에 대한 친숙한 이름입니다.

.threeD-button-set {
  --y:;
  --x:;
  --distance: 1px;
  --theme: hsl(180 100% 50%);
  --theme-bg: hsl(180 100% 50% / 25%);
  --theme-bg-hover: hsl(180 100% 50% / 40%);
  --theme-text: white;
  --theme-shadow: hsl(180 100% 10% / 25%);

  --_max-rotateY: 10deg;
  --_max-rotateX: 15deg;
  --_btn-bg: var(--theme-bg);
  --_btn-bg-hover: var(--theme-bg-hover);
  --_btn-text: var(--theme-text);
  --_btn-text-shadow: var(--theme-shadow);
  --_bounce-ease: cubic-bezier(.5, 1.75, .75, 1.25);

  @media (--dark) {
    --theme: hsl(255 53% 50%);
    --theme-bg: hsl(255 53% 71% / 25%);
    --theme-bg-hover: hsl(255 53% 50% / 40%);
    --theme-shadow: hsl(255 53% 10% / 25%);
  }

  @media (--HDcolor) {
    @supports (color: color(display-p3 0 0 0)) {
      --theme: color(display-p3 .4 0 .9);
    }
  }
}

밝은 테마 및 어두운 테마 배경 원뿔 배경

밝은 테마는 생동감 있는 cyan~deeppink 원뿔 효과를 사용합니다. 그라데이션 어두운 테마에는 어둡고 은은한 원뿔 그라데이션이 적용됩니다. 무엇을 자세히 알아보려면 원뿔 그라데이션으로 적용할 수 있습니다. conic.style을 참고하세요.

html {
  background: conic-gradient(at -10% 50%, deeppink, cyan);

  @media (--dark) {
    background: conic-gradient(at -10% 50%, #212529, 50%, #495057, #212529);
  }
}
드림 <ph type="x-smartling-placeholder">
</ph>
밝은 색상 환경설정과 어두운 색상 환경설정 간에 변경되는 배경 데모

3D 관점 사용 설정

요소가 웹페이지의 3D 공간에 존재하려면 관점 초기화해야 합니다 body 요소에 원근을 넣기로 선택했습니다. 표시 영역 단위를 사용하여 원하는 스타일을 만들었습니다.

body {
  perspective: 40vw;
}

이것은 관점이 미칠 수 있는 영향의 유형입니다.

<ul> 버튼 목록 스타일 지정

이 요소는 전체 버튼 목록 매크로 레이아웃뿐만 아니라 양방향 3D 플로팅 카드입니다. 이를 실현할 수 있는 방법을 소개합니다

버튼 그룹 레이아웃

Flexbox는 컨테이너 레이아웃을 관리할 수 있습니다. Flex의 기본 방향 변경 flex-direction를 사용하여 행에서 열로 변환하고 각 항목의 크기가 align-items의 콘텐츠를 stretch에서 start로 변경하여 콘텐츠를 변경할 수 있습니다.

.threeD-button-set {
  /* remove <ul> margins */
  margin: 0;

  /* vertical rag-right layout */
  display: flex;
  flex-direction: column;
  align-items: flex-start;
  gap: 2.5vh;
}

다음으로 컨테이너를 3D 공간 컨텍스트로 설정하고 CSS clamp()를 설정합니다. 함수를 사용하여 카드가 읽을 수 있는 회전 지점 이상으로 회전하지 않도록 합니다. 알림 클램프의 중간값이 맞춤 속성이라는 것을 알 수 있습니다. 이러한 --x--y 마우스 입력 시 JavaScript에서 설정 어떻게 해야 하는지에 대해 이야기해 보겠습니다

.threeD-button-set {
  

  /* create 3D space context */
  transform-style: preserve-3d;

  /* clamped menu rotation to not be too extreme */
  transform:
    rotateY(
      clamp(
        calc(var(--_max-rotateY) * -1),
        var(--y),
        var(--_max-rotateY)
      )
    )
    rotateX(
      clamp(
        calc(var(--_max-rotateX) * -1),
        var(--x),
        var(--_max-rotateX)
      )
    )
  ;
}

다음으로, 방문하는 사용자의 움직임이 괜찮으면 브라우저에 힌트를 이 항목의 변환은 이동하면서 will-change 또한 변환에 transition를 설정하여 보간 유형을 사용 설정합니다. 이 마우스가 카드와 상호작용하면 애니메이션이 원활하게 적용할 수 있습니다. 애니메이션은 지속적으로 실행되는 애니메이션입니다. 3D 공간을 나타내는 3D 이미지를 반환합니다. 구성요소와 상호작용하지 않을 때 발생합니다.

@media (--motionOK) {
  .threeD-button-set {
    /* browser hint so it can be prepared and optimized */
    will-change: transform;

    /* transition transform style changes and run an infinite animation */
    transition: transform .1s ease;
    animation: rotate-y 5s ease-in-out infinite;
  }
}

rotate-y 애니메이션은 50%에 중간 키프레임만 설정합니다. 브라우저에서 0%100%를 요소의 기본 스타일로 기본 설정합니다. 이 은 번갈아 가며 같은 지점에서 시작하고 끝나야 하는 애니메이션의 약칭입니다. 있습니다. 이는 무한 번갈아 반복되는 애니메이션을 설명하는 좋은 방법입니다.

@keyframes rotate-y {
  50% {
    transform: rotateY(15deg) rotateX(-6deg);
  }
}

<li> 요소 스타일 지정

각 목록 항목 (<li>)에는 버튼과 테두리 요소가 포함되어 있습니다. 이 display 스타일이 변경되어 항목에 ::marker position 스타일 relative로 설정되므로 다음 버튼 의사 요소가 버튼이 사용되는 전체 영역 내에서 자동 광고 소재를 실행합니다.

.threeD-button-set > li {
  /* change display type from list-item */
  display: inline-flex;

  /* create context for button pseudos */
  position: relative;

  /* create 3D space context */
  transform-style: preserve-3d;
}

원근을 보여주기 위해 3D 공간에서 회전된 목록의 스크린샷
각 목록 항목에 더 이상 글머리기호가 없습니다

<button> 요소 스타일 지정

상태 및 상호작용 유형이 많기 때문에 버튼의 스타일을 지정하는 것은 어려울 수 있습니다. 고려해야 합니다 이러한 버튼은 균형 잡혀있기 때문에 빠르게 복잡해집니다. 애니메이션 및 상호작용으로 구성됩니다.

초기 <button> 스타일

다음은 다른 상태를 지원하는 기본 스타일입니다.

.threeD-button-set button {
  /* strip out default button styles */
  appearance: none;
  outline: none;
  border: none;

  /* bring in brand styles via props */
  background-color: var(--_btn-bg);
  color: var(--_btn-text);
  text-shadow: 0 1px 1px var(--_btn-text-shadow);

  /* large text rounded corner and padded*/
  font-size: 5vmin;
  font-family: Audiowide;
  padding-block: .75ch;
  padding-inline: 2ch;
  border-radius: 5px 20px;
}

이번에는 스타일이 지정된 3D 투시 버튼 목록의 스크린샷
버튼을 클릭합니다.

버튼 의사 요소

버튼의 테두리는 일반적인 테두리가 아니라 절대 위치입니다. pseudo-elements가 있습니다.

버튼이 표시된 Chrome Devtools Elements 패널의 스크린샷
::before 및 ::after 요소

이러한 요소는 3D로 제작된 3D 원근법을 보여주는 데 있습니다. 이러한 유사 요소 중 하나가 버튼에서 다른 곳으로 밀려나고 하나는 사용자에게 더 가까이 당겨집니다 그 효과는 다음 항목에서 가장 두드러집니다. 상단 및 하단 버튼

.threeD-button button {
  

  &::after,
  &::before {
    /* create empty element */
    content: '';
    opacity: .8;

    /* cover the parent (button) */
    position: absolute;
    inset: 0;

    /* style the element for border accents */
    border: 1px solid var(--theme);
    border-radius: 5px 20px;
  }

  /* exceptions for one of the pseudo elements */
  /* this will be pushed back (3x) and have a thicker border */
  &::before {
    border-width: 3px;

    /* in dark mode, it glows! */
    @media (--dark) {
      box-shadow:
        0 0 25px var(--theme),
        inset 0 0 25px var(--theme);
    }
  }
}

3D 변환 스타일

아래 transform-stylepreserve-3d로 설정되어 하위 요소가 간격을 둘 수 있습니다. z 축에 자신을 위치시킵니다. transform--distance로 설정됩니다. 맞춤 속성(마우스를 올려 놓았을 때 증가됨) 포커스가 필요합니다.

.threeD-button-set button {
  

  transform: translateZ(var(--distance));
  transform-style: preserve-3d;

  &::after {
    /* pull forward in Z space with a 3x multiplier */
    transform: translateZ(calc(var(--distance) / 3));
  }

  &::before {
    /* push back in Z space with a 3x multiplier */
    transform: translateZ(calc(var(--distance) / 3 * -1));
  }
}

조건부 애니메이션 스타일

사용자가 모션에 괜찮은 경우 버튼은 브라우저에 변환 속성이 변경될 준비가 되어 있어야 하고 전환이 transformbackground-color 속성. 인코더-디코더 아키텍처를 은은하게 흔들리는 효과가 있는 것 같았습니다.

.threeD-button-set button {
  

  @media (--motionOK) {
    will-change: transform;
    transition:
      transform .2s ease,
      background-color .5s ease
    ;

    &::before,
    &::after {
      transition: transform .1s ease-out;
    }

    &::after    { transition-duration: .5s }
    &::before { transition-duration: .3s }
  }
}

마우스 오버 및 포커스 상호작용 스타일

상호작용 애니메이션의 목표는 이미지를 구성하는 레이어를 넓히는 것입니다. 평평하게 표시되는 버튼 이렇게 하려면 --distance 변수를 설정합니다. 처음에는 1px로 변경합니다. 다음 코드 예에 표시된 선택 도구는 버튼이 표시된 기기가 버튼에 마우스를 가져가거나 포커스가 있는지 확인 활성화되고 있지 않습니다. 이 경우에는 CSS를 적용하여 있습니다.

  • 마우스 오버 배경 색상을 적용합니다.
  • 거리를 넓힙니다 .
  • 바운스 이징 효과를 추가합니다.
  • 의사 요소 전환을 시차를 두고 진행합니다.
를 통해 개인정보처리방침을 정의할 수 있습니다.
.threeD-button-set button {
  

  &:is(:hover, :focus-visible):not(:active) {
    /* subtle distance plus bg color change on hover/focus */
    --distance: 15px;
    background-color: var(--_btn-bg-hover);

    /* if motion is OK, setup transitions and increase distance */
    @media (--motionOK) {
      --distance: 3vmax;

      transition-timing-function: var(--_bounce-ease);
      transition-duration: .4s;

      &::after  { transition-duration: .5s }
      &::before { transition-duration: .3s }
    }
  }
}

reduced 모션 환경설정의 3D 관점은 여전히 매우 깔끔했습니다. 상단 및 하단 요소는 효과를 섬세하게 보여줍니다.

JavaScript를 통한 일부 기능 개선

이 인터페이스는 키보드, 스크린 리더, 게임패드, 터치 및 키보드 등 간단한 자바스크립트 터치를 추가하여 두 가지 작업을 쉽게 할 수 있습니다. 시나리오에 관한 것입니다

지원 화살표 키

Tab 키는 메뉴를 탐색하는 데 좋은 방법이지만 게임패드에서 포커스를 이동합니다. 이 GUI에 자주 사용되는 oving-ux 라이브러리 챌린지 인터페이스는 화살표 키를 자동으로 처리합니다. 아래 코드는 .threeD-button-set 내에서 포커스를 트랩하고 버튼 하위 요소를 사용할 수 있습니다.

import {rovingIndex} from 'roving-ux'

rovingIndex({
  element: document.querySelector('.threeD-button-set'),
  target: 'button',
})

마우스 시차 상호작용

마우스를 추적한 후 메뉴를 기울이면 AR 및 VR을 모방합니다. 마우스 대신 가상 포인터가 있을 수 있는 비디오 게임 인터페이스입니다. 요소가 포인터를 하이퍼 인지하는 것은 재미있을 수 있습니다.

이것은 작은 추가 기능이므로 사용자의 모션 환경설정입니다. 또한 설정 과정에서 버튼 목록을 저장합니다. querySelector를 사용하여 구성요소를 메모리에 추가하고 요소의 경계를 menuRect입니다. 이 경계를 사용하여 카드에 적용되는 회전 오프셋을 결정하세요. 기반으로 합니다.

const menu = document.querySelector('.threeD-button-set')
const menuRect = menu.getBoundingClientRect()

const { matches:motionOK } = window.matchMedia(
  '(prefers-reduced-motion: no-preference)'
)

다음으로 마우스 xy 위치를 허용하고 반환하는 함수가 필요합니다. 카드를 회전하는 데 사용할 수 있는 값입니다. 다음 함수는 마우스를 사용해 위치를 사용하여 상자의 어느 면이 들어 있고 얼마인지 구분할 수 있습니다. 이 delta가 반환됩니다.

const getAngles = (clientX, clientY) => {
  const { x, y, width, height } = menuRect

  const dx = clientX - (x + 0.5 * width)
  const dy = clientY - (y + 0.5 * height)

  return {dx,dy}
}

마지막으로 마우스가 움직이는 것을 확인하고 위치를 getAngles() 함수에 전달합니다. 델타 값을 맞춤 속성 스타일로 사용합니다. 덧셈을 하기 위해 20으로 나눈 값입니다. 델타를 낮추고 경사를 줄이게 하려면 더 좋은 방법이 있을 수 있습니다. 만약 --x--y 속성을 처음부터 clamp() 함수를 사용하면 셀 간격이 넓을 때 카드를 읽을 수 없는 위치에 놓습니다.

if (motionOK) {
  window.addEventListener('mousemove', ({target, clientX, clientY}) => {
    const {dx,dy} = getAngles(clientX, clientY)

    menu.attributeStyleMap.set('--x', `${dy / 20}deg`)
    menu.attributeStyleMap.set('--y', `${dx / 20}deg`)
  })
}

번역 및 경로

다른 쓰기 모드에서 게임 메뉴를 테스트할 때 한 가지 실수가 있었고 있습니다.

<button> 요소에 사용자의 writing-mode에 대한 !important 스타일이 있음 에이전트 스타일 시트입니다. 이는 게임 메뉴 HTML을 변경해야 했습니다. 선택할 수 있습니다. 버튼 목록을 링크 목록으로 변경하면 메뉴 방향을 변경하기 위한 속성(<a> 요소에 브라우저가 없음) 제공된 !important 스타일

결론

이제 제가 어떻게 했는지 알게 되었으니 어떻게 해야 할까요?‽ ph 가속도계를 추가할 수 있나요? 휴대전화에서 타일로 메뉴를 회전시키면 개선할 수 있는가 어떻게 해야 할까요?

접근방식을 다각화하고 웹에서 빌드하는 방법을 모두 알아보겠습니다. 데모를 만들고 링크를 트윗하여 추가하면 됩니다. 아래 커뮤니티 리믹스 섹션을 공유해 주세요

커뮤니티 리믹스

표시할 내용이 아직 없습니다.