आधुनिक वेब विकास में, क्लासिक और वेब अनुप्रयोगों के बीच की सीमाएँ हर दिन धुंधली होती जा रही हैं। आज हम न केवल इंटरैक्टिव वेबसाइटें बना सकते हैं, बल्कि सीधे ब्राउज़र में संपूर्ण गेम भी बना सकते हैं। इसे संभव बनाने वाले उपकरणों में से एक लाइब्रेरी है - रिएक्ट तकनीक का उपयोग करके पर आधारित 3डी ग्राफिक्स बनाने के लिए एक शक्तिशाली उपकरण।
रिएक्ट थ्री फाइबर थ्री.जेएस पर एक रैपर है जो वेब पर 3डी ग्राफिक्स बनाने के लिए रिएक्ट की संरचना और सिद्धांतों का उपयोग करता है। यह स्टैक डेवलपर्स को थ्री.जेएस की शक्ति को रिएक्ट की सुविधा और लचीलेपन के साथ संयोजित करने की अनुमति देता है, जिससे एप्लिकेशन बनाने की प्रक्रिया अधिक सहज और व्यवस्थित हो जाती है।
रिएक्ट थ्री फाइबर के मूल में यह विचार है कि एक दृश्य में आप जो कुछ भी बनाते हैं वह एक रिएक्ट घटक है। यह डेवलपर्स को परिचित पैटर्न और कार्यप्रणाली लागू करने की अनुमति देता है।
रिएक्ट थ्री फाइबर का एक मुख्य लाभ रिएक्ट पारिस्थितिकी तंत्र के साथ एकीकरण में आसानी है। इस लाइब्रेरी का उपयोग करते समय किसी भी अन्य रिएक्ट टूल को अभी भी आसानी से एकीकृत किया जा सकता है।
वेब-गेमडेव में हाल के वर्षों में बड़े बदलाव हुए हैं, जो सरल 2डी गेम से लेकर डेस्कटॉप अनुप्रयोगों के तुलनीय जटिल 3डी प्रोजेक्ट तक विकसित हुआ है। लोकप्रियता और क्षमताओं में यह वृद्धि वेब-गेमडेव को एक ऐसा क्षेत्र बनाती है जिसे नजरअंदाज नहीं किया जा सकता है।
आधुनिक ब्राउज़रों ने काफी सरल वेब ब्राउज़िंग टूल से लेकर जटिल एप्लिकेशन और गेम चलाने के लिए शक्तिशाली प्लेटफ़ॉर्म तक विकसित होकर एक लंबा सफर तय किया है। क्रोम , फ़ायरफ़ॉक्स , एज और अन्य जैसे प्रमुख ब्राउज़रों को उच्च प्रदर्शन सुनिश्चित करने के लिए लगातार अनुकूलित और विकसित किया जा रहा है, जिससे वे जटिल अनुप्रयोगों को विकसित करने के लिए एक आदर्श मंच बन गए हैं।
ब्राउज़र-आधारित गेमिंग के विकास को बढ़ावा देने वाले प्रमुख उपकरणों में से एक है। इस मानक ने डेवलपर्स को हार्डवेयर ग्राफिक्स त्वरण का उपयोग करने की अनुमति दी, जिससे 3डी गेम के प्रदर्शन में काफी सुधार हुआ। अन्य वेबएपीआई के साथ मिलकर, वेबजीएल सीधे ब्राउज़र में प्रभावशाली वेब एप्लिकेशन बनाने की नई संभावनाएं खोलता है।
सबसे पहले, हमें एक रिएक्ट प्रोजेक्ट टेम्पलेट की आवश्यकता होगी। तो चलिए इसे इंस्टॉल करके शुरू करते हैं।
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 कुंजियों का उपयोग करके नियंत्रित किया जाएगा, और स्पेसबार का उपयोग करके कूदें।
अपने स्वयं के रिएक्ट-हुक के साथ, हम चरित्र को आगे बढ़ाने के तर्क को लागू करते हैं।
आइए एक हुक.जेएस फ़ाइल बनाएं और वहां एक नया यूज़पर्सनकंट्रोल फ़ंक्शन जोड़ें।
यूज़पर्सनकंट्रोल्स हुक को लागू करने के बाद, इसका उपयोग चरित्र को नियंत्रित करते समय किया जाना चाहिए। प्लेयर घटक में हम गति स्थिति ट्रैकिंग जोड़ेंगे और चरित्र की गति दिशा के वेक्टर को अपडेट करेंगे।
चरित्र की स्थिति को अद्यतन करने के लिए, आइए @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> ); }
आइए पिछले सिंगल क्यूब को हटाकर बनाए गए क्यूब्स घटक को ऐप घटक में जोड़ें।
मॉडल को दृश्य में आयात करने के लिए आवश्यक प्रारूप प्राप्त करने के लिए, हमें 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 के माध्यम से कुछ नए राज्य जोड़ें।