একটি প্রতিক্রিয়াশীল, অভিযোজিত এবং অ্যাক্সেসযোগ্য 3D গেম মেনু কীভাবে তৈরি করা যায় তার একটি মৌলিক সারসংক্ষেপ।
এই পোস্টে আমি একটি 3D গেম মেনু কম্পোনেন্ট তৈরি করার উপায় সম্পর্কে আমার চিন্তাভাবনা শেয়ার করতে চাই। ডেমোটি চেষ্টা করে দেখুন।
যদি আপনি ভিডিও পছন্দ করেন, তাহলে এই পোস্টের একটি ইউটিউব সংস্করণ এখানে দেওয়া হল:
সংক্ষিপ্ত বিবরণ
ভিডিও গেমগুলি প্রায়শই ব্যবহারকারীদের জন্য একটি সৃজনশীল এবং অস্বাভাবিক মেনু উপস্থাপন করে, অ্যানিমেটেড এবং 3D স্পেসে। নতুন AR/VR গেমগুলিতে মেনুটিকে মহাকাশে ভাসমান দেখানোর জন্য এটি জনপ্রিয়। আজ আমরা এই ইফেক্টের প্রয়োজনীয় জিনিসগুলি পুনরায় তৈরি করব তবে একটি অভিযোজিত রঙের স্কিমের অতিরিক্ত স্বাদ এবং কম গতি পছন্দকারী ব্যবহারকারীদের জন্য থাকার ব্যবস্থা সহ।
এইচটিএমএল
একটি গেম মেনু হল বোতামের একটি তালিকা। 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>
বোতামগুলির একটি তালিকা স্ক্রিন রিডার প্রযুক্তির সাথে ভালোভাবে পরিচিত হবে এবং জাভাস্ক্রিপ্ট বা CSS ছাড়াই কাজ করবে।

সিএসএস
বোতাম তালিকার স্টাইলিং নিম্নলিখিত উচ্চ স্তরের ধাপগুলিতে বিভক্ত:
- কাস্টম বৈশিষ্ট্য সেট আপ করা হচ্ছে।
- একটি ফ্লেক্সবক্স লেআউট।
- সাজসজ্জার ছদ্ম-উপাদান সহ একটি কাস্টম বোতাম।
- 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);
}
}
3D দৃষ্টিকোণ সক্ষম করা হচ্ছে
একটি ওয়েব পৃষ্ঠার 3D স্পেসে উপাদানগুলি বিদ্যমান থাকার জন্য, দৃষ্টিকোণ সহ একটি ভিউপোর্ট শুরু করা প্রয়োজন। আমি body এলিমেন্টে দৃষ্টিকোণ স্থাপন করা বেছে নিয়েছি এবং আমার পছন্দের স্টাইল তৈরি করতে ভিউপোর্ট ইউনিট ব্যবহার করেছি।
body {
perspective: 40vw;
}
এই ধরণের প্রভাব দৃষ্টিভঙ্গির হতে পারে।
<ul> বোতাম তালিকা স্টাইল করা
এই উপাদানটি সামগ্রিক বোতাম তালিকার ম্যাক্রো লেআউটের জন্য দায়ী এবং একই সাথে একটি ইন্টারেক্টিভ এবং 3D ভাসমান কার্ডও বটে। এটি অর্জনের একটি উপায় এখানে দেওয়া হল।
বোতাম গ্রুপ লেআউট
ফ্লেক্সবক্স কন্টেইনার লেআউট পরিচালনা করতে পারে। 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() ফাংশন সেট আপ করুন যাতে কার্ডটি সুস্পষ্ট ঘূর্ণনের বাইরে ঘোরানো না হয়। লক্ষ্য করুন যে clamp-এর মধ্যম মানটি একটি কাস্টম সম্পত্তি, এই --x এবং --y মানগুলি পরে মাউস ইন্টারঅ্যাকশনের সময় জাভাস্ক্রিপ্ট থেকে সেট করা হবে।
.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 স্থানটি প্রদর্শন করে, এমনকি যদি একটি মাউস উপাদানটির সাথে ইন্টারঅ্যাক্ট করতে না পারে বা নাও করতে পারে।
@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;
}

বোতামের ছদ্ম-উপাদান
বোতামের সীমানাগুলি ঐতিহ্যবাহী সীমানা নয়, এগুলি সীমানা সহ পরম অবস্থানের ছদ্ম-উপাদান।

এই উপাদানগুলি প্রতিষ্ঠিত 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-style preserve-3d তে সেট করা হয়েছে যাতে শিশুরা z অক্ষের উপর নিজেদের স্থান করে নিতে পারে। transform --distance কাস্টম প্রপার্টিতে সেট করা হয়েছে, যা hover এবং focus- এ বাড়ানো হবে।
.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 গতির পছন্দের জন্য 3D দৃষ্টিকোণটি এখনও সত্যিই সুন্দর ছিল। উপরের এবং নীচের উপাদানগুলি একটি সুন্দর সূক্ষ্ম উপায়ে প্রভাবটি দেখায়।
জাভাস্ক্রিপ্টের সাহায্যে ছোট ছোট উন্নতি
ইন্টারফেসটি ইতিমধ্যেই কীবোর্ড, স্ক্রিন রিডার, গেমপ্যাড, টাচ এবং একটি মাউস থেকে ব্যবহারযোগ্য, তবে কয়েকটি পরিস্থিতি সহজ করার জন্য আমরা জাভাস্ক্রিপ্টের কিছু হালকা ছোঁয়া যোগ করতে পারি।
সাপোর্টিং তীরচিহ্নগুলি
ট্যাব কী মেনুতে নেভিগেট করার জন্য একটি চমৎকার উপায়, তবে আমি আশা করব দিকনির্দেশক প্যাড বা জয়স্টিকগুলি গেমপ্যাডে ফোকাস স্থানান্তর করবে। GUI চ্যালেঞ্জ ইন্টারফেসের জন্য প্রায়শই ব্যবহৃত roving-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)'
)
এরপর, আমাদের এমন একটি ফাংশনের প্রয়োজন যা মাউসের 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> এলিমেন্টগুলিতে ইউজার এজেন্ট স্টাইলশিটে writing-mode জন্য একটি !important স্টাইল থাকে। এর অর্থ হল পছন্দসই ডিজাইনের জন্য গেম মেনু HTML পরিবর্তন করতে হবে। বোতাম তালিকাকে লিঙ্কের তালিকায় পরিবর্তন করলে লজিক্যাল প্রোপার্টি মেনুর দিক পরিবর্তন করতে সক্ষম হয়, কারণ <a> এলিমেন্টগুলিতে ব্রাউজার সরবরাহ করা !important স্টাইল থাকে না।
উপসংহার
এখন তুমি জানো আমি এটা কিভাবে করেছি, তুমি কিভাবে করবে 🙂 তুমি কি মেনুতে অ্যাক্সিলোমিটার ইন্টারঅ্যাকশন যোগ করতে পারো, যাতে তোমার ফোন টাইল করলে মেনুটি ঘোরানো যায়? আমরা কি নো মোশন অভিজ্ঞতা উন্নত করতে পারি?
আসুন আমরা আমাদের পদ্ধতিগুলিকে বৈচিত্র্যময় করি এবং ওয়েবে তৈরি করার সমস্ত উপায় শিখি। একটি ডেমো তৈরি করুন, আমাকে লিঙ্কগুলি টুইট করুন , এবং আমি এটি নীচের কমিউনিটি রিমিক্স বিভাগে যুক্ত করব!
কমিউনিটি রিমিক্স
এখানে এখনও দেখার মতো কিছুই নেই!