आधुनिक वेब विकास में, क्लासिक और वेब अनुप्रयोगों के बीच की सीमाएँ हर दिन धुंधली होती जा रही हैं। आज हम न केवल इंटरैक्टिव वेबसाइटें बना सकते हैं, बल्कि सीधे ब्राउज़र में संपूर्ण गेम भी बना सकते हैं। इसे संभव बनाने वाले उपकरणों में से एक रिएक्ट थ्री फाइबर लाइब्रेरी है - रिएक्ट तकनीक का उपयोग करके थ्री.जेएस पर आधारित 3डी ग्राफिक्स बनाने के लिए एक शक्तिशाली उपकरण।
रिएक्ट थ्री फाइबर थ्री.जेएस पर एक रैपर है जो वेब पर 3डी ग्राफिक्स बनाने के लिए रिएक्ट की संरचना और सिद्धांतों का उपयोग करता है। यह स्टैक डेवलपर्स को थ्री.जेएस की शक्ति को रिएक्ट की सुविधा और लचीलेपन के साथ संयोजित करने की अनुमति देता है, जिससे एप्लिकेशन बनाने की प्रक्रिया अधिक सहज और व्यवस्थित हो जाती है।
रिएक्ट थ्री फाइबर के मूल में यह विचार है कि एक दृश्य में आप जो कुछ भी बनाते हैं वह एक रिएक्ट घटक है। यह डेवलपर्स को परिचित पैटर्न और कार्यप्रणाली लागू करने की अनुमति देता है।
रिएक्ट थ्री फाइबर का एक मुख्य लाभ रिएक्ट पारिस्थितिकी तंत्र के साथ एकीकरण में आसानी है। इस लाइब्रेरी का उपयोग करते समय किसी भी अन्य रिएक्ट टूल को अभी भी आसानी से एकीकृत किया जा सकता है।
वेब-गेमडेव में हाल के वर्षों में बड़े बदलाव हुए हैं, जो सरल 2डी फ़्लैश गेम से लेकर डेस्कटॉप अनुप्रयोगों के तुलनीय जटिल 3डी प्रोजेक्ट तक विकसित हुआ है। लोकप्रियता और क्षमताओं में यह वृद्धि वेब-गेमडेव को एक ऐसा क्षेत्र बनाती है जिसे नजरअंदाज नहीं किया जा सकता है।
वेब गेमिंग का एक मुख्य लाभ इसकी पहुंच है। खिलाड़ियों को कोई अतिरिक्त सॉफ़्टवेयर डाउनलोड और इंस्टॉल करने की आवश्यकता नहीं है - बस अपने ब्राउज़र में लिंक पर क्लिक करें। यह खेलों के वितरण और प्रचार को सरल बनाता है, जिससे वे दुनिया भर में व्यापक दर्शकों के लिए उपलब्ध हो जाते हैं।
अंत में, वेब गेम विकास डेवलपर्स के लिए परिचित प्रौद्योगिकियों का उपयोग करके गेमडेव में अपना हाथ आजमाने का एक शानदार तरीका हो सकता है। उपलब्ध उपकरणों और पुस्तकालयों के लिए धन्यवाद, 3डी ग्राफिक्स में अनुभव के बिना भी, दिलचस्प और उच्च-गुणवत्ता वाली परियोजनाएं बनाना संभव है!
आधुनिक ब्राउज़रों ने काफी सरल वेब ब्राउज़िंग टूल से लेकर जटिल एप्लिकेशन और गेम चलाने के लिए शक्तिशाली प्लेटफ़ॉर्म तक विकसित होकर एक लंबा सफर तय किया है। क्रोम , फ़ायरफ़ॉक्स , एज और अन्य जैसे प्रमुख ब्राउज़रों को उच्च प्रदर्शन सुनिश्चित करने के लिए लगातार अनुकूलित और विकसित किया जा रहा है, जिससे वे जटिल अनुप्रयोगों को विकसित करने के लिए एक आदर्श मंच बन गए हैं।
ब्राउज़र-आधारित गेमिंग के विकास को बढ़ावा देने वाले प्रमुख उपकरणों में से एक WebGL है। इस मानक ने डेवलपर्स को हार्डवेयर ग्राफिक्स त्वरण का उपयोग करने की अनुमति दी, जिससे 3डी गेम के प्रदर्शन में काफी सुधार हुआ। अन्य वेबएपीआई के साथ मिलकर, वेबजीएल सीधे ब्राउज़र में प्रभावशाली वेब एप्लिकेशन बनाने की नई संभावनाएं खोलता है।
फिर भी, ब्राउज़र के लिए गेम विकसित करते समय, विभिन्न प्रदर्शन पहलुओं पर विचार करना महत्वपूर्ण है: संसाधन अनुकूलन, मेमोरी प्रबंधन और विभिन्न उपकरणों के लिए अनुकूलन सभी प्रमुख बिंदु हैं जो किसी परियोजना की सफलता को प्रभावित कर सकते हैं।
हालाँकि, शब्द और सिद्धांत एक चीज़ हैं, लेकिन व्यावहारिक अनुभव बिल्कुल अलग है। वेब गेम विकास की पूरी क्षमता को वास्तव में समझने और उसकी सराहना करने के लिए, सबसे अच्छा तरीका विकास प्रक्रिया में खुद को डुबो देना है। इसलिए, सफल वेब गेम विकास के एक उदाहरण के रूप में, हम अपना खुद का गेम बनाएंगे। यह प्रक्रिया हमें विकास के प्रमुख पहलुओं को सीखने, वास्तविक समस्याओं का सामना करने और उनका समाधान खोजने और यह देखने की अनुमति देगी कि वेब गेम डेवलपमेंट प्लेटफ़ॉर्म कितना शक्तिशाली और लचीला हो सकता है।
लेखों की एक श्रृंखला में, हम देखेंगे कि इस लाइब्रेरी की सुविधाओं का उपयोग करके प्रथम-व्यक्ति शूटर कैसे बनाया जाए, और वेब-गेमडेव की रोमांचक दुनिया में गोता लगाएँ!
GitHub पर रिपॉजिटरी
अब, चलिए शुरू करें!
सबसे पहले, हमें एक रिएक्ट प्रोजेक्ट टेम्पलेट की आवश्यकता होगी। तो चलिए इसे इंस्टॉल करके शुरू करते हैं।
npm create vite@latest
अतिरिक्त एनपीएम पैकेज स्थापित करें।
npm install three @react-three/fiber @react-three/drei @react three/rapier zustand @tweenjs/tween.js
फिर हमारे प्रोजेक्ट से सभी अनावश्यक हटा दें ।
Main.jsx फ़ाइल में, एक div तत्व जोड़ें जो पृष्ठ पर स्कोप के रूप में प्रदर्शित होगा। एक कैनवास घटक डालें और कैमरे का दृश्य क्षेत्र सेट करें। कैनवास घटक के अंदर ऐप घटक रखें।
आइए यूआई तत्वों को स्क्रीन की पूरी ऊंचाई तक फैलाने के लिए Index.css में स्टाइल जोड़ें और स्क्रीन के केंद्र में स्कोप को एक सर्कल के रूप में प्रदर्शित करें।
ऐप घटक में हम एक स्काई घटक जोड़ते हैं, जो आकाश के रूप में हमारे गेम दृश्य में पृष्ठभूमि के रूप में प्रदर्शित होगा।
आइए एक ग्राउंड कंपोनेंट बनाएं और इसे ऐप कंपोनेंट में रखें।
ग्राउंड में, एक सपाट सतह तत्व बनाएं। Y अक्ष पर इसे नीचे की ओर ले जाएं ताकि यह तल कैमरे के दृश्य क्षेत्र में हो। और विमान को क्षैतिज बनाने के लिए उसे X अक्ष पर भी पलटें।
भले ही हमने भौतिक रंग के रूप में ग्रे निर्दिष्ट किया है, विमान पूरी तरह से काला दिखाई देता है।
डिफ़ॉल्ट रूप से, दृश्य में कोई प्रकाश नहीं है, तो चलिए एक प्रकाश स्रोत ambientLight जोड़ते हैं, जो ऑब्जेक्ट को सभी तरफ से रोशन करता है और इसमें कोई निर्देशित किरण नहीं होती है। एक पैरामीटर के रूप में चमक की तीव्रता निर्धारित करें।
फर्श की सतह एक समान न दिखे, इसके लिए हम बनावट जोड़ेंगे। पूरी सतह पर दोहराई जाने वाली कोशिकाओं के रूप में फर्श की सतह का एक पैटर्न बनाएं।
संपत्ति फ़ोल्डर में बनावट के साथ एक पीएनजी छवि जोड़ें।
दृश्य पर बनावट लोड करने के लिए, आइए @react- three/drei पैकेज से useTexture हुक का उपयोग करें। और हुक के लिए एक पैरामीटर के रूप में हम फ़ाइल में आयातित बनावट छवि को पास करेंगे। क्षैतिज अक्षों में छवि की पुनरावृत्ति सेट करें।
@React-Three/drei पैकेज से पॉइंटरलॉककंट्रोल घटक का उपयोग करके, स्क्रीन पर कर्सर को ठीक करें ताकि जब आप माउस को घुमाएं तो वह हिले नहीं, लेकिन दृश्य पर कैमरे की स्थिति बदल जाए।
आइए ग्राउंड घटक के लिए एक छोटा सा संपादन करें।
स्पष्टता के लिए, आइए दृश्य में एक साधारण घन जोड़ें।
<mesh position={[0, 3, -5]}> <boxGeometry /> </mesh>
अभी वह अंतरिक्ष में ही लटका हुआ है.
दृश्य में "भौतिकी" जोड़ने के लिए @react- three/rapier पैकेज से भौतिकी घटक का उपयोग करें। एक पैरामीटर के रूप में, गुरुत्वाकर्षण क्षेत्र को कॉन्फ़िगर करें, जहां हम अक्षों के साथ गुरुत्वाकर्षण बल निर्धारित करते हैं।
<Physics gravity={[0, -20, 0]}> <Ground /> <mesh position={[0, 3, -5]}> <boxGeometry /> </mesh> </Physics>
हालाँकि, हमारा घन भौतिकी घटक के अंदर है, लेकिन उसे कुछ नहीं होता है। क्यूब को वास्तविक भौतिक वस्तु की तरह व्यवहार करने के लिए, हमें इसे @react- three/rapier पैकेज से RigidBody घटक में लपेटना होगा।
उसके बाद, हम तुरंत देखेंगे कि हर बार जब पृष्ठ पुनः लोड होता है, तो घन गुरुत्वाकर्षण के प्रभाव में नीचे गिर जाता है।
लेकिन अब एक और कार्य है - फर्श को एक ऐसी वस्तु बनाना आवश्यक है जिसके साथ घन बातचीत कर सके, और जिसके आगे वह नहीं गिरेगा।
आइए ग्राउंड घटक पर वापस जाएं और फर्श की सतह पर एक आवरण के रूप में एक रिगिडबॉडी घटक जोड़ें।
अब गिरते समय, घन वास्तविक भौतिक वस्तु की तरह फर्श पर रहता है।
आइए एक प्लेयर घटक बनाएं जो दृश्य पर चरित्र को नियंत्रित करेगा।
पात्र जोड़े गए घन के समान ही भौतिक वस्तु है, इसलिए इसे फर्श की सतह के साथ-साथ दृश्य पर घन के साथ भी बातचीत करनी चाहिए। इसीलिए हम RigidBody घटक जोड़ते हैं। और चलिए पात्र को एक कैप्सूल के रूप में बनाते हैं।
प्लेयर घटक को भौतिकी घटक के अंदर रखें।
अब हमारा किरदार सीन पर आ गया है.
चरित्र को WASD कुंजियों का उपयोग करके नियंत्रित किया जाएगा, और स्पेसबार का उपयोग करके कूदें।
अपने स्वयं के रिएक्ट-हुक के साथ, हम चरित्र को आगे बढ़ाने के तर्क को लागू करते हैं।
आइए एक हुक.जेएस फ़ाइल बनाएं और वहां एक नया यूज़पर्सनकंट्रोल फ़ंक्शन जोड़ें।
आइए किसी ऑब्जेक्ट को {"keycode": "क्रिया की जाने वाली क्रिया"} प्रारूप में परिभाषित करें। इसके बाद, कीबोर्ड कुंजी दबाने और जारी करने के लिए ईवेंट हैंडलर जोड़ें। जब हैंडलर चालू हो जाते हैं, तो हम वर्तमान में की जा रही कार्रवाइयों का निर्धारण करेंगे और उनकी सक्रिय स्थिति को अपडेट करेंगे। अंतिम परिणाम के रूप में, हुक एक ऑब्जेक्ट को {"कार्य प्रगति पर है": "स्थिति"} प्रारूप में लौटाएगा।
यूज़पर्सनकंट्रोल्स हुक को लागू करने के बाद, इसका उपयोग चरित्र को नियंत्रित करते समय किया जाना चाहिए। प्लेयर घटक में हम गति स्थिति ट्रैकिंग जोड़ेंगे और चरित्र की गति दिशा के वेक्टर को अपडेट करेंगे।
हम वेरिएबल्स को भी परिभाषित करेंगे जो आंदोलन दिशाओं की स्थिति को संग्रहीत करेंगे।
चरित्र की स्थिति को अद्यतन करने के लिए, आइए @react- three/fiber पैकेज द्वारा प्रदान किए गए फ़्रेम का उपयोग करें । यह हुक requestAnimationFrame के समान काम करता है और फ़ंक्शन के मुख्य भाग को प्रति सेकंड लगभग 60 बार निष्पादित करता है।
कोड स्पष्टीकरण:
1. const प्लेयरRef = useRef(); प्लेयर ऑब्जेक्ट के लिए एक लिंक बनाएं. यह लिंक दृश्य पर प्लेयर ऑब्जेक्ट के साथ सीधे संपर्क की अनुमति देगा।
2. const {आगे, पीछे, बाएँ, दाएँ, कूदें } = usePersonControls(); जब एक हुक का उपयोग किया जाता है, तो बूलियन मान वाला एक ऑब्जेक्ट यह दर्शाता है कि वर्तमान में खिलाड़ी द्वारा कौन से नियंत्रण बटन दबाए गए हैं।
3. यूज़फ़्रेम((स्टेट) => {... }); एनीमेशन के प्रत्येक फ्रेम पर हुक को बुलाया जाता है। इस हुक के अंदर, खिलाड़ी की स्थिति और रैखिक वेग अद्यतन किया जाता है।
4. यदि (!playerRef.current) वापसी; किसी प्लेयर ऑब्जेक्ट की उपस्थिति की जाँच करता है। यदि कोई प्लेयर ऑब्जेक्ट नहीं है, तो त्रुटियों से बचने के लिए फ़ंक्शन निष्पादन बंद कर देगा।
5. स्थिरांक वेग = प्लेयरRef.current.linvel(); खिलाड़ी का वर्तमान रैखिक वेग प्राप्त करें।
6. फ्रंटवेक्टर.सेट(0, 0, पिछड़ा - आगे); दबाए गए बटनों के आधार पर आगे/पीछे गति वेक्टर सेट करें।
7. साइडवेक्टर.सेट(बाएँ - दाएँ, 0, 0); बाएँ/दाएँ मूवमेंट वेक्टर सेट करें।
8. दिशा.उपवेक्टर(फ्रंटवेक्टर, साइडवेक्टर).सामान्यीकरण().गुणास्केलर(MOVE_SPEED); मूवमेंट वेक्टर को घटाकर, परिणाम को सामान्य करके (ताकि वेक्टर की लंबाई 1 हो) और मूवमेंट गति स्थिरांक से गुणा करके खिलाड़ी मूवमेंट के अंतिम वेक्टर की गणना करें।
9. प्लेयररेफ.करंट.वेकअप(); यह सुनिश्चित करने के लिए कि यह परिवर्तनों पर प्रतिक्रिया करता है, खिलाड़ी ऑब्जेक्ट को "जागृत" करता है। यदि आप इस पद्धति का उपयोग नहीं करते हैं, तो कुछ समय बाद वस्तु "सो जाएगी" और स्थिति परिवर्तन पर प्रतिक्रिया नहीं करेगी।
10. प्लेयरRef.current.setLinvel({ x: दिशा.x, y: वेग.y, z: दिशा.z }); गति की गणना की गई दिशा के आधार पर खिलाड़ी के नए रैखिक वेग को सेट करें और वर्तमान ऊर्ध्वाधर वेग को बनाए रखें (ताकि छलांग या गिरावट को प्रभावित न करें)।
परिणामस्वरूप, WASD कुंजियाँ दबाने पर, पात्र दृश्य के चारों ओर घूमने लगा। वह घन के साथ भी बातचीत कर सकता है, क्योंकि वे दोनों भौतिक वस्तुएं हैं।
जंप को लागू करने के लिए, आइए @dimforge/rapier3d-compat और @react- three/rapier पैकेज से कार्यक्षमता का उपयोग करें। इस उदाहरण में, आइए जांचें कि पात्र जमीन पर है और जंप कुंजी दबाई गई है। इस मामले में, हम Y-अक्ष पर वर्ण की दिशा और त्वरण बल निर्धारित करते हैं।
प्लेयर के लिए हम सभी अक्षों पर द्रव्यमान और ब्लॉक रोटेशन जोड़ देंगे, ताकि वह दृश्य पर अन्य वस्तुओं से टकराते समय अलग-अलग दिशाओं में न गिरे।
कोड स्पष्टीकरण:
- कॉन्स्ट वर्ल्ड = रेपियर.वर्ल्ड; रैपियर भौतिकी इंजन दृश्य तक पहुंच प्राप्त करना। इसमें सभी भौतिक वस्तुएँ शामिल हैं और उनकी परस्पर क्रिया का प्रबंधन करता है।
- स्थिरांक रे = विश्व.कास्टरे(नया RAPIER.Ray(playerRef.current.translation(), { x: 0, y: -1, z: 0 })); यहीं पर "रेकास्टिंग" (रेकास्टिंग) होती है। एक किरण बनाई जाती है जो खिलाड़ी की वर्तमान स्थिति से शुरू होती है और y-अक्ष को नीचे की ओर इंगित करती है। यह किरण दृश्य में "डाली" जाती है ताकि यह निर्धारित किया जा सके कि यह दृश्य में किसी वस्तु के साथ प्रतिच्छेद करती है या नहीं।
- स्थिरांक ग्राउंडेड = रे && रे.कोलाइडर && Math.abs(ray.toi) <= 1.5; यदि खिलाड़ी मैदान पर है तो स्थिति की जाँच की जाती है:
- किरण - क्या किरण बनाई गई थी;
- ray.collider - क्या किरण घटनास्थल पर किसी वस्तु से टकराई;
- Math.abs(ray.toi) - किरण का "एक्सपोज़र टाइम"। यदि यह मान दिए गए मान से कम या उसके बराबर है, तो यह संकेत दे सकता है कि खिलाड़ी सतह के इतना करीब है कि उसे "जमीन पर" माना जा सकता है।
आपको ग्राउंड घटक को संशोधित करने की भी आवश्यकता है ताकि "लैंडिंग" स्थिति निर्धारित करने के लिए किरण-अनुरेखित एल्गोरिदम सही ढंग से काम कर सके, एक भौतिक वस्तु जोड़कर जो दृश्य में अन्य वस्तुओं के साथ बातचीत करेगी।
आइए दृश्य को बेहतर ढंग से देखने के लिए कैमरे को थोड़ा ऊपर उठाएं।
अनुभाग कोड
कैमरे को स्थानांतरित करने के लिए, हम प्लेयर की वर्तमान स्थिति प्राप्त करेंगे और हर बार फ्रेम रीफ्रेश होने पर कैमरे की स्थिति बदल देंगे। और चरित्र को ठीक उसी प्रक्षेप पथ पर ले जाने के लिए, जहां कैमरा निर्देशित है, हमें applyEuler जोड़ने की आवश्यकता है।
कोड स्पष्टीकरण:
अप्लाईयूलर विधि निर्दिष्ट यूलर कोणों के आधार पर एक वेक्टर पर रोटेशन लागू करती है। इस मामले में, कैमरा रोटेशन दिशा वेक्टर पर लागू होता है। इसका उपयोग कैमरा ओरिएंटेशन के सापेक्ष गति का मिलान करने के लिए किया जाता है, ताकि प्लेयर कैमरा घुमाए जाने की दिशा में आगे बढ़े।
आइए प्लेयर के आकार को थोड़ा समायोजित करें और इसे क्यूब के सापेक्ष लंबा बनाएं, कैप्सूलकोलाइडर का आकार बढ़ाएं और "जंप" तर्क को ठीक करें।
अनुभाग कोड
दृश्य को पूरी तरह खाली न लगे, इसके लिए आइए क्यूब जेनरेशन जोड़ें। JSON फ़ाइल में, प्रत्येक क्यूब के निर्देशांक सूचीबद्ध करें और फिर उन्हें दृश्य पर प्रदर्शित करें। ऐसा करने के लिए, एक फ़ाइल क्यूब्स.जेसन बनाएं, जिसमें हम निर्देशांक की एक सरणी सूचीबद्ध करेंगे।
[ [0, 0, -7], [2, 0, -7], [4, 0, -7], [6, 0, -7], [8, 0, -7], [10, 0, -7] ]
Cube.jsx फ़ाइल में, एक Cubes घटक बनाएं, जो एक लूप में क्यूब्स उत्पन्न करेगा। और क्यूब घटक सीधे ऑब्जेक्ट उत्पन्न करेगा।
import {RigidBody} from "@react-three/rapier"; import cubes from "./cubes.json"; export const Cubes = () => { return cubes.map((coords, index) => <Cube key={index} position={coords} />); } const Cube = (props) => { return ( <RigidBody {...props}> <mesh castShadow receiveShadow> <meshStandardMaterial color="white" /> <boxGeometry /> </mesh> </RigidBody> ); }
आइए पिछले सिंगल क्यूब को हटाकर बनाए गए क्यूब्स घटक को ऐप घटक में जोड़ें।
आइए अब दृश्य में एक 3D मॉडल जोड़ें। आइए चरित्र के लिए एक हथियार मॉडल जोड़ें। आइए एक 3D मॉडल की तलाश से शुरुआत करें। उदाहरण के लिए, आइए इसे लेते हैं।
मॉडल को जीएलटीएफ प्रारूप में डाउनलोड करें और प्रोजेक्ट के रूट में संग्रह को अनपैक करें।
मॉडल को दृश्य में आयात करने के लिए आवश्यक प्रारूप प्राप्त करने के लिए, हमें gltf-पाइपलाइन ऐड-ऑन पैकेज स्थापित करने की आवश्यकता होगी।
npm i -D gltf-pipeline
Gltf-पाइपलाइन पैकेज का उपयोग करके, मॉडल को GLTF प्रारूप से GLB प्रारूप में पुनः परिवर्तित करें, क्योंकि इस प्रारूप में सभी मॉडल डेटा एक फ़ाइल में रखे जाते हैं। जेनरेट की गई फ़ाइल के लिए आउटपुट निर्देशिका के रूप में हम सार्वजनिक फ़ोल्डर निर्दिष्ट करते हैं।
gltf-pipeline -i weapon/scene.gltf -o public/weapon.glb
फिर हमें एक प्रतिक्रिया घटक उत्पन्न करने की आवश्यकता है जिसमें इस मॉडल को दृश्य में जोड़ने के लिए उसका मार्कअप शामिल होगा। आइए @react- three/fiber डेवलपर्स के आधिकारिक संसाधन का उपयोग करें।
कनवर्टर पर जाने से आपको परिवर्तित हथियार.जीएलबी फ़ाइल लोड करने की आवश्यकता होगी।
ड्रैग एंड ड्रॉप या एक्सप्लोरर सर्च का उपयोग करके, इस फ़ाइल को ढूंढें और इसे डाउनलोड करें।
कनवर्टर में हम जेनरेट किए गए प्रतिक्रिया-घटक को देखेंगे, जिसका कोड हम अपने प्रोजेक्ट में एक नई फ़ाइल WeaponModel.jsx में स्थानांतरित करेंगे, घटक का नाम फ़ाइल के समान नाम में बदल देंगे।
अब बनाए गए मॉडल को दृश्य में आयात करते हैं। App.jsx फ़ाइल में WeaponModel घटक जोड़ें।
हमारे दृश्य में इस बिंदु पर, कोई भी वस्तु छाया नहीं डाल रही है।
दृश्य पर छाया को सक्षम करने के लिए आपको कैनवास घटक में छाया विशेषता जोड़ने की आवश्यकता है।
इसके बाद, हमें एक नया प्रकाश स्रोत जोड़ने की आवश्यकता है। इस तथ्य के बावजूद कि हमारे पास पहले से ही दृश्य पर परिवेश प्रकाश है, यह वस्तुओं के लिए छाया नहीं बना सकता है, क्योंकि इसमें दिशात्मक प्रकाश किरण नहीं है। तो आइए डायरेक्शनललाइट नामक एक नया प्रकाश स्रोत जोड़ें और इसे कॉन्फ़िगर करें। " कास्ट " छाया मोड को सक्षम करने की विशेषता कास्टशैडो है। यह इस पैरामीटर का जोड़ है जो इंगित करता है कि यह वस्तु अन्य वस्तुओं पर छाया डाल सकती है।
उसके बाद, आइए ग्राउंड घटक में एक और विशेषता रिसीवशैडो जोड़ें, जिसका अर्थ है कि दृश्य में घटक स्वयं छाया प्राप्त और प्रदर्शित कर सकता है।
दृश्य पर अन्य वस्तुओं में समान विशेषताएं जोड़ी जानी चाहिए: क्यूब्स और प्लेयर। क्यूब्स के लिए हम कास्टशैडो और रिसीवशैडो जोड़ेंगे, क्योंकि वे दोनों छाया डाल और प्राप्त कर सकते हैं, और प्लेयर के लिए हम केवल कास्टशैडो जोड़ेंगे।
आइए प्लेयर के लिए कास्टशैडो जोड़ें।
क्यूब के लिए कास्टशैडो और रिसीवशैडो जोड़ें।
अब अगर आप ध्यान से देखेंगे तो पाएंगे कि जिस सतह पर छाया पड़ती है उसका क्षेत्रफल काफी छोटा है। और इस क्षेत्र से आगे जाने पर छाया आसानी से कट जाती है।
इसका कारण यह है कि डिफ़ॉल्ट रूप से कैमरा दिशात्मक प्रकाश से प्रदर्शित छाया के केवल एक छोटे से क्षेत्र को कैप्चर करता है। हम दृश्यता के इस क्षेत्र का विस्तार करने के लिए अतिरिक्त विशेषताओं शैडो-कैमरा- (ऊपर, नीचे, बाएँ, दाएँ) को जोड़कर दिशात्मक प्रकाश घटक का उपयोग कर सकते हैं। इन विशेषताओं को जोड़ने के बाद, छाया थोड़ी धुंधली हो जाएगी। गुणवत्ता में सुधार के लिए, हम शैडो-मैपसाइज़ विशेषता जोड़ेंगे।
आइए अब प्रथम-व्यक्ति हथियार प्रदर्शन जोड़ें। एक नया हथियार घटक बनाएं, जिसमें हथियार व्यवहार तर्क और 3डी मॉडल ही शामिल होगा।
import {WeaponModel} from "./WeaponModel.jsx"; export const Weapon = (props) => { return ( <group {...props}> <WeaponModel /> </group> ); }
आइए इस घटक को चरित्र के रिगिडबॉडी के समान स्तर पर रखें और यूज़फ़्रेम हुक में हम कैमरे से मूल्यों की स्थिति के आधार पर स्थिति और रोटेशन कोण सेट करेंगे।
चरित्र की चाल को और अधिक स्वाभाविक बनाने के लिए, हम चलते समय हथियार को थोड़ा हिलाएंगे। एनीमेशन बनाने के लिए हम स्थापित ट्विन.जेएस लाइब्रेरी का उपयोग करेंगे।
हथियार घटक को एक समूह टैग में लपेटा जाएगा ताकि आप useRef हुक के माध्यम से इसमें एक संदर्भ जोड़ सकें।
आइए एनीमेशन को सहेजने के लिए कुछ यूज़स्टेट जोड़ें।
आइए एनीमेशन आरंभ करने के लिए एक फ़ंक्शन बनाएं।
कोड स्पष्टीकरण:
- const twSwayingAnimation = new TWEEN.Tween(currentPosition) ... किसी ऑब्जेक्ट का उसकी वर्तमान स्थिति से नई स्थिति में "स्विंगिंग" एनीमेशन बनाना।
- const twSwayingBackAnimation = new TWEEN.Tween(currentPosition) ... पहला एनीमेशन पूरा होने के बाद अपनी प्रारंभिक स्थिति में वापस लौटने वाली वस्तु का एक एनीमेशन बनाना।
- twSwayingAnimation.चेन(twSwayingBackAnimation); दो एनिमेशन को कनेक्ट करना ताकि जब पहला एनीमेशन पूरा हो जाए, तो दूसरा एनीमेशन स्वचालित रूप से शुरू हो जाए।
यूज़इफ़ेक्ट में हम एनीमेशन इनिशियलाइज़ेशन फ़ंक्शन को कॉल करते हैं।
अब उस क्षण को निर्धारित करना आवश्यक है जिसके दौरान आंदोलन होता है। यह चरित्र की दिशा के वर्तमान वेक्टर को निर्धारित करके किया जा सकता है।
यदि चरित्र में कोई हलचल होती है, तो हम एनीमेशन को ताज़ा करेंगे और समाप्त होने पर इसे फिर से चलाएंगे।
कोड स्पष्टीकरण:
- स्थिरांक isMoving = दिशा.लंबाई() > 0; यहां वस्तु की गति की स्थिति की जांच की जाती है। यदि दिशा वेक्टर की लंबाई 0 से अधिक है, तो इसका मतलब है कि वस्तु की गति की दिशा है।
- यदि (isMoving && isSwayingAnimationFined) { ... } यह स्थिति तब निष्पादित होती है जब ऑब्जेक्ट घूम रहा हो और "स्विंगिंग" एनीमेशन समाप्त हो गया हो।
ऐप घटक में, आइए एक यूज़फ़्रेम जोड़ें जहां हम ट्वीन एनीमेशन को अपडेट करेंगे।
TWEEN.update() TWEEN.js लाइब्रेरी में सभी सक्रिय एनिमेशन को अपडेट करता है। यह सुनिश्चित करने के लिए कि सभी एनिमेशन सुचारू रूप से चलें, प्रत्येक एनीमेशन फ्रेम पर इस विधि को बुलाया जाता है।
अनुभाग कोड:
हमें उस क्षण को परिभाषित करने की आवश्यकता है जब गोली चलाई जाती है - अर्थात, जब माउस बटन दबाया जाता है। आइए इस स्थिति को संग्रहीत करने के लिए यूज़स्टेट जोड़ें, हथियार ऑब्जेक्ट के संदर्भ को संग्रहीत करने के लिए यूज़रेफ और माउस बटन को दबाने और छोड़ने के लिए दो ईवेंट हैंडलर जोड़ें।
आइए माउस बटन पर क्लिक करते समय एक रिकॉइल एनीमेशन लागू करें। हम इस उद्देश्य के लिए tween.js लाइब्रेरी का उपयोग करेंगे।
आइए हम पुनरावृत्ति बल और एनीमेशन अवधि के लिए स्थिरांक को परिभाषित करें।
हथियार विगल एनीमेशन की तरह, हम रिकॉइल और होम पोजीशन एनीमेशन पर लौटने के लिए दो यूज़स्टेट स्टेट्स और एनीमेशन एंड स्टेटस के साथ एक स्टेट जोड़ते हैं।
आइए रिकॉइल एनीमेशन का एक यादृच्छिक वेक्टर प्राप्त करने के लिए फ़ंक्शन बनाएं - generateRecoilOffset और generateNewPositionOfRecoil ।
रिकॉइल एनीमेशन आरंभ करने के लिए एक फ़ंक्शन बनाएं। हम useEffect भी जोड़ेंगे, जिसमें हम "शॉट" स्थिति को निर्भरता के रूप में निर्दिष्ट करेंगे, ताकि प्रत्येक शॉट पर एनीमेशन फिर से प्रारंभ हो और नए अंत निर्देशांक उत्पन्न हों।
और यूज़फ़्रेम में, आइए फायरिंग के लिए माउस कुंजी को "होल्ड" करने के लिए एक चेक जोड़ें, ताकि कुंजी जारी होने तक फायरिंग एनीमेशन बंद न हो।
चरित्र के लिए "निष्क्रियता" के एनीमेशन का एहसास करें, ताकि खेल "फांसी" की कोई भावना न हो।
ऐसा करने के लिए, आइए useState के माध्यम से कुछ नए राज्य जोड़ें।
आइए राज्य से मूल्यों का उपयोग करने के लिए "विगल" एनीमेशन की शुरुआत को ठीक करें। विचार यह है कि अलग-अलग स्थितियाँ: चलना या रुकना, एनीमेशन के लिए अलग-अलग मानों का उपयोग करेगी और हर बार एनीमेशन को पहले आरंभ किया जाएगा।
इस भाग में हमने दृश्य निर्माण और चरित्र आंदोलन को लागू किया है। हमने एक हथियार मॉडल, फायरिंग के दौरान और निष्क्रिय होने पर रिकॉइल एनीमेशन भी जोड़ा है। अगले भाग में हम नई कार्यक्षमता जोड़कर अपने गेम को परिष्कृत करना जारी रखेंगे।
यहाँ भी प्रकाशित किया गया है.