إنشاء مكوِّن قائمة للعبة ثلاثية الأبعاد

هي نظرة عامة أساسية حول كيفية إنشاء قائمة ألعاب ثلاثية الأبعاد سريعة الاستجابة وتكيّفية ويمكن الوصول إليها.

في هذه المشاركة، أود أن أشارككم أفكارًا حول طريقة لإنشاء مكون قائمة لعبة ثلاثية الأبعاد. ندعوك لبدء العرض التوضيحي.

عرض توضيحي

إليك نسخة من هذه المشاركة على YouTube إذا كنت تفضّل ذلك:

نظرة عامة

غالبًا ما تقدم ألعاب الفيديو للمستخدمين قائمة صور متحركة وإبداعية وغير عادية وفي مساحة ثلاثية الأبعاد. وهو شائع في ألعاب الواقع المعزّز/الواقع الافتراضي الجديدة لجعل القائمة تبدو وكأنها تطفو في الفضاء. اليوم سنعيد إنشاء أساسيات هذا التأثير ولكننا مع لمسة إضافية من نظام الألوان التكيفي ووسائل الراحة للمستخدمين الذين يفضلون الحركة المنخفضة.

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.

CANNOT TRANSLATE
قائمة نقطية ذات مظهر عام جدًا مع أزرار عادية كعناصر.

CSS

ينقسم تصميم قائمة الأزرار إلى الخطوات عالية المستوى التالية:

  1. إعداد الخصائص المخصصة.
  2. تخطيط flexbox
  3. زر مخصّص مع عناصر زائفة زخرفية
  4. وضع العناصر في مساحة ثلاثية الأبعاد

نظرة عامة على الخصائص المخصّصة

تساعد السمات المخصّصة على تمييز القيم من خلال تقديم معنى الأسماء لقيم ذات شكل عشوائي، مع تجنّب تكرار الرمز البرمجي ومشاركة البيانات القيم بين الأطفال.

في ما يلي طلبات البحث عن الوسائط المحفوظة كمتغيّرات 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);
  }
}
عرض توضيحي لتغيير في الخلفية بين الإعدادات المفضّلة للألوان الفاتحة والداكنة

تفعيل المنظور الثلاثي الأبعاد

لكي توجد العناصر في المساحة ثلاثية الأبعاد لصفحة الويب، فإن إطار العرض ذو من منظور ينبغي تهيئة. اخترتُ أن أضع وجهة نظر العنصر body. واستخدمت وحدات إطار العرض لإنشاء النمط الذي أعجبني.

body {
  perspective: 40vw;
}

هذا هو نوع منظور التأثير الذي يمكن أن تحدثه.

تصميم قائمة أزرار "<ul>"

هذا العنصر مسؤول عن التنسيق الكلي لقائمة الأزرار وكذلك لكونها بطاقة عائمة تفاعلية وثلاثية الأبعاد. إليك طريقة لتحقيق ذلك.

تصميم مجموعة الأزرار

يمكن لـ Flexbox إدارة تخطيط الحاوية. تغيير الاتجاه التلقائي للمرونة من الصفوف إلى الأعمدة التي تحتوي على flex-direction والتأكد من أن كل عنصر بحجم محتوياته من خلال التغيير من stretch إلى start في align-items.

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

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

بعد ذلك، عليك إنشاء الحاوية كسياق مساحة ثلاثية الأبعاد وإعداد 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 على التحويلات. هذا النمط عندما يتفاعل الماوس مع البطاقة، مما يسهل للانتقال إلى تغييرات الدوران. الرسوم المتحركة هي رسم متحرك يعمل باستمرار يوضح المساحة ثلاثية الأبعاد التي توجد بها البطاقة، حتى إذا لم يستطع الماوس لا يتفاعل مع المكون.

@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;
}

لقطة شاشة للقائمة التي تم تدويرها في مساحة ثلاثية الأبعاد لعرض المنظور
لم يعد يحتوي كل عنصر قائمة على رمز نقطي.

تصميم عناصر <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;
}

لقطة شاشة لقائمة الأزرار بمنظور ثلاثي الأبعاد، هذه المرة باستخدام
الأزرار.

العناصر الزائفة في الزر

حدود الزر ليست حدودًا تقليدية، بل هي في موضعها المطلق والعناصر الزائفة ذات الحدود.

لقطة شاشة للوحة &quot;عناصر أدوات مطوّري البرامج في Chrome&quot; مع زر
::before و ::after.

هذه العناصر ضرورية لعرض المنظور ثلاثي الأبعاد الذي تم التأسيس. سوف يتم إبعاد أحد هذه العناصر الزائفة عن الزر، ويتم تقريب أحدهما أكثر من المستخدم يكون التأثير أكثر وضوحًا في الزر العلوي والسفلي.

.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);
    }
  }
}

أنماط التحويل الثلاثي الأبعاد

تم ضبط القيمة الأقل من transform-style على preserve-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));
  }
}

أنماط الصور المتحركة الشرطية

فإذا كان المستخدم يوافق على الحركة، يشير الزر إلى المتصفح بأن يجب أن تكون خاصية التحويل جاهزة للتغيير وتم تعيين انتقال إلى السمتان transform وbackground-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. يظهر العنصران العلوي والسفلي التأثير بطريقة رقيقة ولطيفة.

تحسينات صغيرة باستخدام JavaScript

يمكن استخدام الواجهة من خلال لوحات المفاتيح وقارئات الشاشة ولوحات التحكم بالألعاب وأجهزة اللمس بالماوس بالفعل، ولكن يمكننا إضافة بعض اللمسات الخفيفة من JavaScript لتخفيف السيناريوهات.

مفاتيح الأسهم الداعمة

يعد مفتاح Tab طريقة جيدة للتنقل في القائمة ولكن كنت أتوقع الحصول على إرشادات لوحة أو أذرع تحكم لتحريك التركيز على لوحة الألعاب. تشير رسالة الأشكال البيانية roving-ux غالبًا ما تُستخدم لواجهة المستخدم الرسومية ستتعامل واجهات التحدي مع مفاتيح الأسهم لنا. يخبر الكود أدناه لالتقاط التركيز داخل .threeD-button-set وإعادة توجيه التركيز إلى العناصر الثانوية للأزرار.

import {rovingIndex} from 'roving-ux'

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

تفاعل تأثير اختلاف الماوس

يهدف تتبع الماوس وإمالته إلى محاكاة الواقع المعزّز والواقع الافتراضي واجهات ألعاب الفيديو، حيث يكون لديك مؤشر افتراضي بدلاً من الماوس. قد يكون من الممتع عندما تكون العناصر على دراية تامة بالمؤشر.

نظرًا لأن هذه ميزة إضافية صغيرة، سنضع التفاعل خلف استعلام تفضيل حركة المستخدم. وكجزء من عملية الإعداد أيضًا، يمكنك تخزين قائمة الأزرار في الذاكرة باستخدام querySelector وتخزين حدود العنصر في ذاكرة التخزين المؤقت menuRect استخدِم هذه الحدود لتحديد إزاحة التدوير المطبَّقة على البطاقة. بناءً على موضع الماوس.

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

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

بعد ذلك، نحتاج إلى دالة تقبل موضعَي الماوس x وy وتعود قيمة يمكننا استخدامها لتدوير البطاقة. تستخدم الدالة التالية الماوس لتحديد أي جانب من الصندوق بداخله ومقدار المساحة. تشير رسالة الأشكال البيانية يتم إرجاع دلتا من الدالة.

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> تحتوي على نمط !important لـ writing-mode في المستخدم ورقة أنماط العميل. وهذا يعني أن رمز HTML لقائمة اللعبة يجب تغييره لاستيعاب التصميم المطلوب. يؤدي تغيير قائمة الأزرار إلى قائمة من الروابط إلى تفعيل السمات التي تتيح تغيير اتجاه القائمة، لأنّ عناصر <a> لا تحتوي على متصفّح تم تقديم نمط !important.

الخاتمة

الآن بعد أن تعرّفت على كيفية إجراء ذلك، كيف يمكنك‽ 🙂 هل يمكنك إضافة مقياس التسارع؟ التفاعل مع القائمة، بحيث يؤدي تجانب هاتفك إلى تدوير القائمة؟ هل يمكننا تحسين تجربة عدم الحركة؟

يمكننا تنويع أساليبنا وتعلُّم جميع طرق إنشاء المحتوى على الويب. أنشئ عرضًا توضيحيًا وأضيف روابط تغريدة إليّ. انتقِل إلى قسم الريمكسات في المنتدى أدناه.

ريمكسات من إنشاء المنتدى

ما من محتوى جديد حتى الآن.