कैसे मैंने एक शुद्ध सीएसएस पहेली गेम प्लेटोब्लॉकचैन डेटा इंटेलिजेंस बनाया। लंबवत खोज। ऐ.

मैंने एक शुद्ध सीएसएस पहेली गेम कैसे बनाया

मैंने हाल ही में CSS-only गेम बनाने का आनंद खोजा है। यह हमेशा आकर्षक होता है कि कैसे HTML और CSS पूरे ऑनलाइन गेम के तर्क को संभालने में सक्षम हैं, इसलिए मुझे इसे आजमाना पड़ा! ऐसे गेम आमतौर पर ol' Checkbox Hack पर निर्भर होते हैं, जहां हम HTML इनपुट की चेक/अनचेक स्थिति को :checked सीएसएस में छद्म वर्ग। हम उस एक संयोजन से बहुत सारा जादू कर सकते हैं!

वास्तव में, मैंने खुद को चेकबॉक्स के बिना एक संपूर्ण गेम बनाने की चुनौती दी। मुझे यकीन नहीं था कि यह संभव होगा, लेकिन यह निश्चित रूप से है, और मैं आपको दिखाने जा रहा हूं कि कैसे।

पहेली खेल के अलावा हम इस लेख में अध्ययन करेंगे, मैंने बनाया है शुद्ध CSS खेलों का संग्रह, उनमें से ज्यादातर चेकबॉक्स हैक के बिना। (वे भी उपलब्ध हैं कोडपेन पर.)

शुरू करने से पहले खेलना चाहते हैं?

मैं व्यक्तिगत रूप से गेम को पूर्ण स्क्रीन मोड में खेलना पसंद करता हूं, लेकिन आप इसे नीचे खेल सकते हैं या इसे यहाँ खोलो.

बिल्कुल सटीक? मुझे पता है, यह अब तक का सबसे अच्छा पहेली गेम नहीं है, लेकिन यह किसी ऐसी चीज़ के लिए भी बुरा नहीं है जो केवल CSS और HTML की कुछ पंक्तियों का उपयोग करती है। आप आसानी से ग्रिड के आकार को समायोजित कर सकते हैं, कठिनाई स्तर को नियंत्रित करने के लिए कक्षों की संख्या बदल सकते हैं, और जो भी छवि आप चाहते हैं उसका उपयोग कर सकते हैं!

हम उस डेमो को एक साथ रीमेक करने जा रहे हैं, फिर कुछ किक के लिए अंत में इसमें थोड़ी अतिरिक्त चमक डालें।

खींचें और छोड़ें कार्यक्षमता

जबकि सीएसएस ग्रिड के साथ पहेली की संरचना काफी सीधी है, पहेली के टुकड़ों को खींचने और छोड़ने की क्षमता थोड़ी पेचीदा है। मुझे इसे पूरा करने के लिए संक्रमण, होवर प्रभाव, और भाई चयनकर्ताओं के संयोजन पर निर्भर रहना पड़ा।

यदि आप उस डेमो में खाली बॉक्स पर होवर करते हैं, तो छवि उसके अंदर चली जाती है और कर्सर को बॉक्स से बाहर ले जाने पर भी वहीं रहती है। चाल एक बड़ी संक्रमण अवधि और देरी को जोड़ने की है - इतनी बड़ी कि छवि को अपनी प्रारंभिक स्थिति में लौटने में बहुत समय लगता है।

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) छवि के समान क्षेत्र लेगा (सीएसएस ग्रिड के लिए धन्यवाद और 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 ग्रिड और बैकग्राउंड ट्रिक्स पर भरोसा करने जा रहे हैं।

यहाँ हमारी ग्रिड है, सुविधा के लिए पग में लिखा है:

- 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 में संकलित होता है:

<g style="--i: url(https://picsum.photos/id/1015/800/800)">
 <z>
   <a></a>
   <b draggable="true"></b>
 </z>
 <z>
   <a></a>
   <b draggable="true"></b>
 </z>
 <z>
   <a></a>
   <b draggable="true"></b>
 </z>
  <!-- etc. -->
</g>

मुझे यकीन है कि आप सोच रहे होंगे कि उन टैग्स के साथ क्या हो रहा है। इनमें से किसी भी तत्व का कोई विशेष अर्थ नहीं है - मुझे बस यह पता चला है कि कोड का उपयोग करके लिखना बहुत आसान है <z> के एक झुंड की तुलना में <div class="z"> जो कुछ भी।

इस तरह मैंने उन्हें मैप किया है:

  • <g> हमारा ग्रिड कंटेनर है जिसमें शामिल है N*N <z> तत्वों।
  • <z> हमारे ग्रिड आइटम का प्रतिनिधित्व करता है। यह की भूमिका निभाता है .box तत्व जो हमने पिछले भाग में देखा था।
  • <a> होवर प्रभाव को ट्रिगर करता है।
  • <b> हमारी छवि के एक हिस्से का प्रतिनिधित्व करता है। हम लागू करते हैं draggable इस पर विशेषता है क्योंकि इसे डिफ़ॉल्ट रूप से खींचा नहीं जा सकता है।

ठीक है, चलिए हमारे ग्रिड कंटेनर को रजिस्टर करते हैं <g>. यह सीएसएस के बजाय सास में है:

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

हम वास्तव में अपने ग्रिड बच्चे बनाने जा रहे हैं - the <z> तत्व - ग्रिड भी और दोनों हैं <a> और <b> एक ही ग्रिड क्षेत्र के भीतर:

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

जैसा कि आप देख सकते हैं, कुछ भी फैंसी नहीं है - हमने एक विशिष्ट आकार के साथ एक ग्रिड बनाया है। बाकी सीएसएस जो हमें चाहिए वह ड्रैग एंड ड्रॉप फीचर के लिए है, जिसके लिए हमें बोर्ड के चारों ओर बेतरतीब ढंग से टुकड़े करने की आवश्यकता होती है। मैं इसके लिए 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() समारोह। इस तरह हम पहेली के टुकड़ों के लिए यादृच्छिक स्थिति प्राप्त करते हैं। याद रखें कि हम करेंगे अक्षम करें उस स्थिति के ऊपर मँडराते समय <a> तत्व को खींचने और छोड़ने के बाद उसके अनुरूप <b> ग्रिड सेल के अंदर तत्व।

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

उसी लूप में, मैं पहेली के प्रत्येक टुकड़े के लिए पृष्ठभूमि कॉन्फ़िगरेशन को भी परिभाषित कर रहा हूं। वे सभी तार्किक रूप से एक ही छवि को पृष्ठभूमि के रूप में साझा करेंगे, और इसका आकार पूरे ग्रिड के आकार के बराबर होना चाहिए (के साथ परिभाषित) --s चर)। उसी का उपयोग करना background-image और कुछ गणित, हम अद्यतन करते हैं background-position छवि का केवल एक टुकड़ा दिखाने के लिए।

इतना ही! हमारा सीएसएस-ओनली पज़ल गेम तकनीकी रूप से पूरा हो गया है!

लेकिन हम हमेशा बेहतर कर सकते हैं, है ना? मैंने तुम्हें दिखाया पहेली टुकड़े के आकार का ग्रिड कैसे बनाएं एक अन्य लेख में। आइए हम वही विचार लें और इसे यहां लागू करें, क्या हम?

पहेली टुकड़ा आकार

यहाँ हमारा नया पहेली खेल है। समान कार्यक्षमता लेकिन अधिक यथार्थवादी आकृतियों के साथ!

यह ग्रिड पर आकृतियों का एक उदाहरण है:

मैंने एक शुद्ध सीएसएस पहेली गेम कैसे बनाया

यदि आप बारीकी से देखें तो आप देखेंगे कि हमारे पास पहेली के नौ अलग-अलग आकार हैं: चार कोने, चार किनारे, तथा बाकी सब के लिए एक.

मैंने जिस दूसरे लेख का उल्लेख किया है, उसमें पहेली के टुकड़ों की ग्रिड थोड़ी अधिक सीधी है:

हम उसी तकनीक का उपयोग कर सकते हैं जो विभिन्न आकृतियों को बनाने के लिए CSS मास्क और ग्रेडिएंट को जोड़ती है। मामले में आप से अपरिचित हैं mask और ग्रेडिएंट, मैं अत्यधिक जाँच करने की सलाह देता हूँ वह सरलीकृत मामला अगले भाग पर जाने से पहले तकनीक को बेहतर ढंग से समझने के लिए।

सबसे पहले, हमें समान आकार वाले तत्वों के प्रत्येक समूह को लक्षित करने के लिए विशिष्ट चयनकर्ताओं का उपयोग करने की आवश्यकता है। हमारे पास नौ समूह हैं, इसलिए हम आठ चयनकर्ताओं का उपयोग करेंगे, साथ ही एक डिफ़ॉल्ट चयनकर्ता जो उन सभी का चयन करेगा।

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

कोड जटिल लग सकता है, लेकिन क्या हो रहा है यह देखने के लिए एक समय में एक ग्रेडिएंट पर ध्यान दें:

दो ग्रेडियेंट दो सर्किल बनाते हैं (डेमो में हरे और बैंगनी चिह्नित), और दो अन्य ग्रेडियेंट स्लॉट बनाते हैं जो अन्य टुकड़े से जुड़ते हैं (एक चिह्नित नीला अधिकांश आकार भरता है जबकि एक चिह्नित लाल शीर्ष भाग भरता है)। एक सीएसएस चर, --r, वृत्ताकार आकृतियों की त्रिज्या निर्धारित करता है।

कैसे मैंने एक शुद्ध सीएसएस पहेली गेम प्लेटोब्लॉकचैन डेटा इंटेलिजेंस बनाया। लंबवत खोज। ऐ.
मैंने एक शुद्ध सीएसएस पहेली गेम कैसे बनाया

केंद्र में पहेली के टुकड़ों का आकार (चिह्नित .) 0 चित्रण में) बनाना सबसे कठिन है क्योंकि यह चार ढालों का उपयोग करता है और इसमें चार वक्रताएँ हैं। अन्य सभी टुकड़े कम ग्रेडियेंट को जोड़ते हैं।

उदाहरण के लिए, पहेली के टुकड़े पहेली के शीर्ष किनारे पर (चिह्नित .) 2 चित्रण में) चार के बजाय तीन ग्रेडिएंट का उपयोग करता है:

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 रेपो पर नज़र रखें.

ऊपर लपेटकर

तथा CSS एक प्रोग्रामिंग भाषा नहीं है, कहते हैं। हा!

मैं इसके द्वारा कुछ #HotDrama को जगाने की कोशिश नहीं कर रहा हूं। मैं ऐसा इसलिए कह रहा हूं क्योंकि हमने वास्तव में कुछ मुश्किल तर्क सामग्री की और रास्ते में बहुत सी सीएसएस संपत्तियों और तकनीकों को कवर किया। हमने CSS ग्रिड, ट्रांज़िशन, मास्किंग, ग्रेडिएंट्स, चयनकर्ताओं और पृष्ठभूमि गुणों के साथ खेला। कुछ Sass ट्रिक्स का उल्लेख नहीं करने के लिए जिनका उपयोग हमने अपने कोड को समायोजित करना आसान बनाने के लिए किया था।

लक्ष्य खेल का निर्माण करना नहीं था, बल्कि सीएसएस का पता लगाना और नई संपत्तियों और तरकीबों की खोज करना था जिनका उपयोग आप अन्य परियोजनाओं में कर सकते हैं। CSS में एक ऑनलाइन गेम बनाना एक चुनौती है जो आपको CSS सुविधाओं को विस्तार से जानने और उनका उपयोग करने का तरीका सीखने के लिए प्रेरित करती है। साथ ही, यह बहुत मज़ेदार है कि जब सब कुछ कहा और किया जाता है तो हमें खेलने के लिए कुछ मिलता है।

CSS एक प्रोग्रामिंग भाषा है या नहीं, यह इस तथ्य को नहीं बदलता है कि हम हमेशा नवीन सामग्री का निर्माण और निर्माण करके सीखते हैं।

समय टिकट:

से अधिक सीएसएस ट्रिक्स