किसी भी 2D प्लेटफ़ॉर्मर के मुख्य तत्वों में से एक मुख्य पात्र है। जिस तरह से वह चलता है और नियंत्रित होता है, वह खेल के माहौल को महत्वपूर्ण रूप से आकार देता है - चाहे वह एक आरामदायक पुराने स्कूल का खेल हो या एक गतिशील स्लेशर। इसलिए, एक प्लेटफ़ॉर्मर विकसित करने में एक कैरेक्टर कंट्रोलर बनाना एक महत्वपूर्ण प्रारंभिक चरण है। इस लेख में, हम स्क्रैच से एक चरित्र बनाने की प्रक्रिया की पूरी तरह से जांच करेंगे, इसे भौतिकी के नियमों का पालन करते हुए स्तर पर घूमना सिखाएंगे। भले ही आपके पास पहले से ही कैरेक्टर कंट्रोलर बनाने का अनुभव हो, फिर भी आपको यूनिटी 2023 में नवाचारों के बारे में जानने में दिलचस्पी होगी। मेरे आश्चर्य के लिए, घटक के लिए एक लंबे समय से प्रतीक्षित विधि जोड़ी गई है, जो किनेमेटिक मोड में के अधिक प्रभावी ढंग से उपयोग की अनुमति देकर एक चरित्र नियंत्रक लिखना बहुत सरल बनाता है। पहले, यह सभी कार्यक्षमता मैन्युअल रूप से लागू की जानी थी। Rigidbody2D Slide Rigidbody2D यदि आप न केवल लेख पढ़ना चाहते हैं, बल्कि इसे व्यवहार में भी आज़माना चाहते हैं, तो मैं GitHub रिपॉजिटरी से एक स्तर टेम्पलेट डाउनलोड करने की सलाह देता हूं, जहां आपके चरित्र के परीक्षण के लिए आवश्यक संपत्ति और एक तैयार स्तर पहले से ही शामिल हैं। ट्रेजर हंटर्स अपने चरित्र की नींव रखना हमारे प्लेटफ़ॉर्मर के लिए, हमने एक नियम निर्धारित किया है कि गेम में केवल ऊर्ध्वाधर और क्षैतिज सतहें होंगी, और गुरुत्वाकर्षण बल को सख्ती से नीचे की ओर निर्देशित किया जाएगा। यह प्रारंभिक चरण में प्लेटफ़ॉर्मर के निर्माण को काफी सरल बनाता है, खासकर यदि आप वेक्टर गणित में तल्लीन नहीं होना चाहते हैं। भविष्य में, मैं अपने प्रोजेक्ट ट्रेजर हंटर्स में इन नियमों से हट सकता हूँ, जहाँ मैं यूनिटी पर 2D प्लेटफ़ॉर्मर के लिए मैकेनिक्स के निर्माण का पता लगाऊँगा। लेकिन यह किसी दूसरे लेख का विषय होगा। हमारे इस निर्णय के आधार पर कि आंदोलन क्षैतिज सतहों के साथ किया जाएगा, हमारे चरित्र का आधार आयताकार होगा। झुकी हुई सतहों का उपयोग करने के लिए एक कैप्सूल के आकार का कोलाइडर और स्लाइडिंग जैसे अतिरिक्त यांत्रिकी विकसित करने की आवश्यकता होगी। सबसे पहले, सीन पर एक खाली ऑब्जेक्ट बनाएं और उसका नाम कैप्टन रखें - यह हमारा मुख्य पात्र होगा। ऑब्जेक्ट में और घटक जोड़ें। प्रकार को Kinematic पर सेट करें ताकि हम यूनिटी की अंतर्निहित भौतिकी क्षमताओं का उपयोग करते हुए भी चरित्र की गति को नियंत्रित कर सकें। साथ ही, Freeze Rotation Z विकल्प को सक्रिय करके Z-अक्ष के साथ चरित्र के रोटेशन को लॉक करें। Rigidbody2D BoxCollider2D Rigidbody2D आपका सेटअप नीचे दिए गए चित्र जैसा दिखना चाहिए। अब आइए अपने कैप्टन में एक रूप जोड़ें। Assets/Textures/Treasure Hunters/Captain Clown Nose/Sprites/Captain Clown Nose/Captain Clown Nose with Sword/09-Idle Sword/Idle Sword 01.png में टेक्सचर ढूंढें और इसका पिक्सेल प्रति यूनिट मान 32 पर सेट करें। हम इस कोर्स में अक्सर इस मान का उपयोग करेंगे क्योंकि हमारे टेक्सचर इसी रिज़ॉल्यूशन के साथ बनाए गए हैं। स्प्राइट मोड को सिंगल पर सेट करें और सुविधा के लिए, पिवट को बॉटम पर सेट करें। अप्लाई बटन पर क्लिक करके बदलाव लागू करना न भूलें। सुनिश्चित करें कि सभी सेटिंग्स सही तरीके से की गई हैं। इस लेख में, हम चरित्र एनीमेशन पर बात नहीं करेंगे, इसलिए अभी के लिए, हम केवल एक स्प्राइट का उपयोग करेंगे। कैप्टन ऑब्जेक्ट में, Appearance नामक एक नेस्टेड ऑब्जेक्ट बनाएँ और उसमें पहले से कॉन्फ़िगर किए गए स्प्राइट को निर्दिष्ट करते हुए एक स्प्राइट रेंडरर घटक जोड़ें। जब मैंने कैप्टन की छवि पर ज़ूम इन किया, तो मैंने पाया कि गलत स्प्राइट सेटिंग के कारण यह काफी धुंधली थी। इसे ठीक करने के लिए, प्रोजेक्ट विंडो में आइडल स्वॉर्ड 01 टेक्सचर चुनें और फ़िल्टर मोड को पॉइंट (कोई फ़िल्टर नहीं) पर सेट करें। अब छवि बहुत बेहतर दिखती है। कैरेक्टर कोलाइडर सेटअप फिलहाल, कोलाइडर की स्थिति और हमारे कैप्टन की छवि मेल नहीं खाती, और कोलाइडर हमारी जरूरतों के लिए बहुत बड़ा हो जाता है। आइए इसे ठीक करें और साथ ही नीचे की ओर कैरेक्टर की धुरी को सही तरीके से रखें। हम इस नियम को गेम में सभी ऑब्जेक्ट पर लागू करेंगे ताकि आकार की परवाह किए बिना उन्हें एक ही स्तर पर रखना आसान हो। इस प्रक्रिया के प्रबंधन में आसानी के लिए, पिवट सेट के साथ टॉगल टूल हैंडल पोजीशन का उपयोग करें, जैसा कि नीचे दिखाया गया है। अगला कदम हमारे हीरो के कोलाइडर को इस तरह से समायोजित करना है कि उसका पिवट पॉइंट बिल्कुल बीच के निचले हिस्से में हो। कोलाइडर का आकार बिल्कुल चरित्र के आयामों से मेल खाना चाहिए। आवश्यक परिशुद्धता प्राप्त करने के लिए कोलाइडर के ऑफसेट और आकार मापदंडों के साथ-साथ नेस्टेड अपीयरेंस ऑब्जेक्ट की स्थिति को समायोजित करें। कोलाइडर के Offset.X पैरामीटर पर विशेष ध्यान दें: इसका मान पूर्णतः 0 होना चाहिए। यह ऑब्जेक्ट के केंद्र के सापेक्ष कोलाइडर के सममित स्थान को सुनिश्चित करेगा, जो कि बाद के वर्ण घुमावों के लिए अत्यंत महत्वपूर्ण है, जहां Transform.Scale.X का मान -1 और 1 में बदल जाता है। कोलाइडर को अपने स्थान पर बने रहना चाहिए, और दृश्य घुमाव प्राकृतिक दिखना चाहिए। पात्रों के शारीरिक व्यवहार का परिचय सबसे पहले और सबसे महत्वपूर्ण बात यह है कि पात्रों को भौतिक दुनिया के साथ बातचीत करना सिखाना ज़रूरी है - चाहे वे मुख्य नायक हों, एनपीसी हों या दुश्मन हों। उदाहरण के लिए, पात्रों को समतल सतह पर चलने, उससे कूदने और गुरुत्वाकर्षण बल के अधीन होने में सक्षम होना चाहिए, जो उन्हें वापस ज़मीन पर खींचता है। यूनिटी में एक अंतर्निहित भौतिकी इंजन है जो निकायों की गति को नियंत्रित करता है, टकरावों को संभालता है, और वस्तुओं पर बाहरी बलों के प्रभाव को जोड़ता है। यह सब घटक का उपयोग करके कार्यान्वित किया जाता है। हालाँकि, पात्रों के लिए, एक अधिक लचीला उपकरण होना उपयोगी है जो भौतिक दुनिया के साथ बातचीत करता है जबकि डेवलपर्स को ऑब्जेक्ट के व्यवहार पर अधिक नियंत्रण देता है। Rigidbody2D जैसा कि मैंने पहले बताया, यूनिटी के पिछले संस्करणों में, डेवलपर्स को यह सारा तर्क खुद ही लागू करना पड़ता था। हालाँकि, यूनिटी 2023 में, घटक में एक नई विधि जोड़ी गई, जो प्रदर्शन की गई गति के बारे में सभी आवश्यक जानकारी प्रदान करते हुए भौतिक वस्तु के लचीले नियंत्रण की अनुमति देती है। Rigidbody2D Slide आइए क्लास बनाकर शुरू करें, जिसमें भौतिक दुनिया में पात्रों को स्थानांतरित करने के लिए बुनियादी तर्क शामिल होंगे। यह क्लास मोड में उपयोग करेगा, जिसे हमने पहले ही अपने चरित्र में जोड़ दिया है। तो, पहली बात यह है कि इस घटक के लिए एक संदर्भ जोड़ना है। CharacterBody Kinematic Rigidbody2D public class CharacterBody : MonoBehaviour { [SerializeField] private Rigidbody2D _rigidbody; } कभी-कभी, चरित्र की गतिशीलता के लिए, गुरुत्वाकर्षण का सामान्य से अधिक मजबूती से कार्य करना आवश्यक होता है। इसे प्राप्त करने के लिए, हम 1 के प्रारंभिक मान के साथ एक गुरुत्वाकर्षण प्रभाव कारक जोड़ेंगे, और यह कारक 0 से कम नहीं हो सकता है। [Min(0)] [field: SerializeField] public float GravityFactor { get; private set; } = 1f; हमें यह भी परिभाषित करना होगा कि कौन सी वस्तुएँ अगम्य सतह मानी जाएँगी। ऐसा करने के लिए, हम एक फ़ील्ड बनाएंगे जो हमें आवश्यक परतों को निर्दिष्ट करने की अनुमति देगा। [SerializeField] private LayerMask _solidLayers; हम चरित्र की गति को सीमित कर देंगे ताकि उन्हें अत्यधिक उच्च गति विकसित करने से रोका जा सके, उदाहरण के लिए, गुरुत्वाकर्षण सहित कुछ बाहरी प्रभाव के कारण। हम प्रारंभिक मान 30 पर सेट करते हैं और इंस्पेक्टर में 0 से कम मान सेट करने की क्षमता को सीमित करते हैं। [Min(0)] [SerializeField] private float _maxSpeed = 30; किसी सतह पर चलते समय हम चाहते हैं कि पात्र हमेशा उससे चिपका रहे, बशर्ते उनके बीच की दूरी काफी कम हो। [Min(0)] [SerializeField] private float _surfaceAnchor = 0.01f; यद्यपि हमने निर्णय लिया था कि हमारे खेल में सतहें केवल क्षैतिज या ऊर्ध्वाधर होंगी, फिर भी, हम सतह के अधिकतम ढलान कोण को निर्दिष्ट करेंगे, जिस पर पात्र स्थिर रूप से खड़ा हो सके, जिसका प्रारंभिक मान 45º होगा। [Range(0, 90)] [SerializeField] private float _maxSlop = 45f; इंस्पेक्टर के माध्यम से, मैं चरित्र की वर्तमान गति और उनकी स्थिति भी देखना चाहता हूं, इसलिए मैं विशेषता के साथ दो फ़ील्ड जोड़ूंगा। SerializeField [SerializeField] private Vector2 _velocity; [field: SerializeField] public CharacterState State { get; private set; } हां, यहां मैंने एक नई, लेकिन अपरिभाषित इकाई पेश की है। हम इस पर आगे चर्चा करेंगे। CharacterState चरित्र की स्थिति हमारे प्लेटफ़ॉर्मर के विकास को सरल बनाने के लिए, आइए केवल दो मुख्य चरित्र अवस्थाओं को परिभाषित करें। पहला है , एक ऐसी अवस्था जिसमें पात्र सतह पर सुरक्षित रूप से खड़ा होता है। इस अवस्था में, पात्र सतह पर स्वतंत्र रूप से घूम सकता है और उससे कूद सकता है। ग्राउंडेड दूसरा है , फ्री फ़ॉल की एक अवस्था, जिसमें चरित्र हवा में होता है। इस अवस्था में चरित्र का व्यवहार प्लेटफ़ॉर्मर की बारीकियों के आधार पर अलग-अलग हो सकता है। वास्तविकता के करीब एक सामान्य मामले में, चरित्र प्रारंभिक गति के प्रभाव में चलता है और उसके व्यवहार को प्रभावित नहीं कर सकता है। हालाँकि, प्लेटफ़ॉर्मर में, सुविधा और गेमप्ले की गतिशीलता के पक्ष में भौतिकी को अक्सर सरल बनाया जाता है: उदाहरण के लिए, कई खेलों में, फ्री फ़ॉल में होने पर भी, हम चरित्र की क्षैतिज गति को नियंत्रित कर सकते हैं। हमारे मामले में, यह भी संभव है, साथ ही डबल जंप का लोकप्रिय मैकेनिक भी है, जो हवा में एक अतिरिक्त छलांग लगाने की अनुमति देता है। एयरबोर्न आइए कोड में अपने चरित्र की स्थिति को प्रस्तुत करें: /// <summary> /// Describes the state of <see cref="CharacterBody"/>. /// </summary> public enum CharacterState { /// <summary> /// The character stays steady on the ground and can move freely along it. /// </summary> Grounded, /// <summary> /// The character is in a state of free fall. /// </summary> Airborne } यह ध्यान देने योग्य है कि कई और स्थितियाँ हो सकती हैं। उदाहरण के लिए, यदि खेल में ढलान वाली सतहें शामिल हैं, तो चरित्र एक फिसलने वाली स्थिति में हो सकता है जहाँ वह स्वतंत्र रूप से दाएँ या बाएँ नहीं जा सकता है, लेकिन ढलान से नीचे की ओर खिसक सकता है। ऐसी स्थिति में, चरित्र ढलान से धक्का देकर कूद भी सकता है, लेकिन केवल ढलान की दिशा में। एक अन्य संभावित मामला एक ऊर्ध्वाधर दीवार के साथ फिसलना है, जहाँ गुरुत्वाकर्षण का प्रभाव कमजोर होता है, और चरित्र क्षैतिज रूप से धक्का दे सकता है। आवागमन की गति सीमा हमने पहले ही एक निजी फ़ील्ड परिभाषित कर दिया है, लेकिन हमें चरित्र की अधिकतम गति को सीमित करते हुए बाहर से इस मान को प्राप्त करने और सेट करने में सक्षम होना चाहिए। इसके लिए दिए गए वेग वेक्टर की अधिकतम स्वीकार्य गति से तुलना करने की आवश्यकता है। _velocity यह वेग वेक्टर की लंबाई या गणितीय शब्दों में, इसके परिमाण की गणना करके किया जा सकता है। संरचना में पहले से ही एक गुण है जो हमें ऐसा करने की अनुमति देता है। इस प्रकार, यदि पारित वेक्टर का परिमाण अधिकतम अनुमत गति से अधिक है, तो हमें वेक्टर की दिशा बनाए रखनी चाहिए लेकिन इसके परिमाण को सीमित करना चाहिए। इसके लिए, हम सामान्यीकृत वेग वेक्टर से गुणा करते हैं (सामान्यीकृत वेक्टर एक वेक्टर है जिसकी दिशा समान है लेकिन परिमाण 1 है)। Vector2 magnitude _maxSpeed कोड में यह इस प्रकार दिखता है: public Vector2 Velocity { get => _velocity; set => _velocity = value.magnitude > _maxSpeed ? value.normalized * _maxSpeed : value; } अब आइए इस बात पर करीब से नज़र डालें कि वेक्टर के परिमाण की गणना कैसे की जाती है। इसे सूत्र द्वारा परिभाषित किया जाता है: वर्गमूल की गणना करना एक संसाधन-गहन ऑपरेशन है। हालाँकि अधिकांश मामलों में गति अधिकतम से अधिक नहीं होगी, फिर भी हमें प्रति चक्र कम से कम एक बार यह तुलना करनी होगी। हालाँकि, हम इस ऑपरेशन को काफी सरल बना सकते हैं यदि हम वेक्टर के परिमाण के वर्ग की तुलना अधिकतम गति के वर्ग से करें। इसके लिए, हम अधिकतम गति के वर्ग को संग्रहीत करने के लिए एक अतिरिक्त फ़ील्ड पेश करते हैं, और हम इसे एक बार विधि में गणना करते हैं: Awake private float _sqrMaxSpeed; private void Awake() { _sqrMaxSpeed = _maxSpeed * _maxSpeed; } अब गति निर्धारण अधिक बेहतर ढंग से किया जा सकता है: public Vector2 Velocity { get => _velocity; set => _velocity = value.sqrMagnitude > _sqrMaxSpeed ? value.normalized * _maxSpeed : value; } इस प्रकार, हम अनावश्यक गणनाओं से बचते हैं और चरित्र की गति के प्रसंस्करण के प्रदर्शन में सुधार करते हैं। कठोर शरीर आंदोलन विधि जैसा कि मैंने पहले बताया, यूनिटी ने एक नया तरीका जोड़ा है, जो हमारे के विकास को बहुत सरल करेगा। हालाँकि, इस विधि का उपयोग करने से पहले, उन नियमों को परिभाषित करना आवश्यक है जिनके द्वारा ऑब्जेक्ट अंतरिक्ष में चलेगा। यह व्यवहार संरचना द्वारा निर्धारित किया जाता है। Slide() CharacterBody Rigidbody2D.SlideMovement आइए एक नया फ़ील्ड प्रारंभ करें और इसके मान सेट करें। _slideMovement private Rigidbody2D.SlideMovement _slideMovement; private void Awake() { _sqrMaxSpeed = _maxSpeed * _maxSpeed; _slideMovement = CreateSlideMovement(); } private Rigidbody2D.SlideMovement CreateSlideMovement() { return new Rigidbody2D.SlideMovement { maxIterations = 3, surfaceSlideAngle = 90, gravitySlipAngle = 90, surfaceUp = Vector2.up, surfaceAnchor = Vector2.down * _surfaceAnchor, gravity = Vector2.zero, layerMask = _solidLayers, useLayerMask = true, }; } यह समझाना महत्वपूर्ण है कि यह निर्धारित करता है कि टक्कर के परिणामस्वरूप कोई वस्तु कितनी बार दिशा बदल सकती है। उदाहरण के लिए, यदि पात्र दीवार के बगल में हवा में है और खिलाड़ी गुरुत्वाकर्षण के प्रभाव में उसे दाईं ओर ले जाने का प्रयास करता है। इस प्रकार, विधि के प्रत्येक कॉल के लिए, दाईं ओर और नीचे की ओर निर्देशित एक वेग वेक्टर सेट किया जाएगा। दीवार से टकराने पर, गति वेक्टर की पुनर्गणना की जाती है, और वस्तु नीचे की ओर बढ़ना जारी रखेगी। maxIterations Slide() ऐसी स्थिति में, यदि मान 1 पर सेट किया गया, तो वस्तु दीवार से टकराएगी, रुक जाएगी, और प्रभावी रूप से वहीं अटक जाएगी। maxIterations और के मान पहले से परिभाषित किए गए थे। अन्य फ़ील्ड पर अधिक विस्तृत जानकारी के लिए, देखें। maxIterations layerMask आधिकारिक संरचना दस्तावेज़ अंत में, चरित्र को स्थानांतरित करना अब कैप्टन को आगे बढ़ाने के लिए सब कुछ तैयार है। हम इसे में करेंगे - यूनिटी में एक कॉलबैक जिसे भौतिकी को संभालने के लिए डिज़ाइन किया गया है। पिछले कुछ वर्षों में, यूनिटी टीम ने 2D भौतिकी को संभालने में काफी सुधार किया है। वर्तमान में, प्रोसेसिंग कॉलबैक में या यहां तक कि अपने आप आवश्यक विधि को कॉल करके भी की जा सकती है। FixedUpdate Update हालाँकि, इस उदाहरण में, हम पारंपरिक और सिद्ध विधि का उपयोग करेंगे। आगे बढ़ने से पहले, के मूल्य के बारे में कुछ शब्द कहना उचित होगा। FixedUpdate Time.fixedDeltaTime गेम फिजिक्स में पूर्वानुमान सुनिश्चित करने के लिए, सिमुलेशन को निश्चित समय अंतराल पर पुनरावृत्तियों में किया जाता है। यह गारंटी देता है कि FPS या लैग में परिवर्तन ऑब्जेक्ट व्यवहार को प्रभावित नहीं करते हैं। प्रत्येक चक्र की शुरुआत में, हम वस्तु पर गुरुत्वाकर्षण के प्रभाव को ध्यान में रखेंगे। चूँकि गुरुत्वाकर्षण मुक्त पतन त्वरण के सदिश द्वारा दिया जाता है, इसलिए हम समय के साथ वस्तु के वेग में परिवर्तन की गणना सूत्र द्वारा कर सकते हैं: Δt Δv जहाँ वस्तु का स्थिर त्वरण है। हमारे मामले में, यह गुरुत्वाकर्षण के कारण त्वरण है, हमारे द्वारा प्रस्तुत गुणांक पर विचार करते हुए — । इसलिए, गणना निम्न प्रकार से की जा सकती है: a Physics2D.gravity * GravityFactor Δv Time.fixedDeltaTime * GravityFactor * Physics2D.gravity अंतिम परिणाम, जहां हम वेग बदलते हैं, ऐसा दिखता है: Velocity += Time.fixedDeltaTime * GravityFactor * Physics2D.gravity; अब हम पात्र की कठोर शारीरिक गतिविधि प्रदर्शित कर सकते हैं: var slideResults = _rigidbody.Slide( _velocity, Time.fixedDeltaTime, _slideMovement); चर संरचना का एक मान है और आंदोलन के परिणामों को संग्रहीत करता है। हमारे लिए इस परिणाम के मुख्य क्षेत्र हैं, आंदोलन के दौरान सतह के साथ टकराव का परिणाम, और - नीचे की ओर कास्ट का परिणाम, जो यह निर्धारित करने में मदद करेगा कि चरित्र एक स्थिर सतह पर खड़ा है या नहीं। slideResults SlideResults slideHit surfaceHit टकराव से निपटना सतहों से टकराते समय, उस सतह की ओर निर्देशित चरित्र की गति को सीमित करना महत्वपूर्ण है। एक सरल उदाहरण यह है कि यदि चरित्र जमीन पर स्थिर खड़ा है, तो उसे गुरुत्वाकर्षण के प्रभाव में गति प्राप्त करना जारी नहीं रखना चाहिए। प्रत्येक चक्र के अंत में, उनकी गति शून्य होनी चाहिए। इसी तरह, जब ऊपर की ओर बढ़ते हुए और छत से टकराते हैं, तो चरित्र को सभी ऊर्ध्वाधर गति खो देनी चाहिए और नीचे की ओर बढ़ना शुरू कर देना चाहिए। टकरावों के परिणाम, और , संरचना के मानों द्वारा दर्शाए जाते हैं, जिसमें टकराव सतह का सामान्य शामिल होता है। slideHit surfaceHit RaycastHit2D गति सीमा की गणना टक्कर के सामान्य पर मूल वेग वेक्टर के प्रक्षेपण को वेग वेक्टर से घटाकर की जा सकती है। यह उपयोग करके किया जाता है। आइए एक विधि लिखें जो इस ऑपरेशन को निष्पादित करेगी: डॉट उत्पाद का private static Vector2 ClipVector(Vector2 vector, Vector2 hitNormal) { return vector - Vector2.Dot(vector, hitNormal) * hitNormal; } अब इस विधि को हमारे में एकीकृत करते हैं। यहाँ, के लिए, हम गति को केवल तभी सीमित करेंगे जब इसे नीचे की ओर निर्देशित किया जाएगा, क्योंकि कास्ट यह निर्धारित करता है कि वस्तु सतह पर है या नहीं, हमेशा जमीन के साथ संपर्क की जाँच करने के लिए किया जाता है। FixedUpdate surfaceHit private void FixedUpdate() { Velocity += Time.fixedDeltaTime * GravityFactor * Physics2D.gravity; var slideResults = _rigidbody.Slide( _velocity, Time.fixedDeltaTime, _slideMovement); if (slideResults.slideHit) { _velocity = ClipVector(_velocity, slideResults.slideHit.normal); } if (_velocity.y <= 0 && slideResults.surfaceHit) { var surfaceHit = slideResults.surfaceHit; _velocity = ClipVector(_velocity, surfaceHit.normal); } } यह कार्यान्वयन पात्र की गति को सही ढंग से प्रबंधित करने, विभिन्न सतहों से टकराने पर अवांछित त्वरण से बचने और खेल में पात्रों की गति को पूर्वानुमानित और सुचारू रखने की अनुमति देता है। चरित्र की स्थिति का निर्धारण प्रत्येक चक्र के अंत में, यह निर्धारित करना आवश्यक है कि पात्र ठोस सतह पर है (ग्राउंडेड अवस्था) या मुक्त गिरावट में है (या, जैसा कि हमने इसे परिभाषित किया है, नियंत्रित गिरावट - एयरबोर्न अवस्था)। चरित्र को ग्राउंडेड अवस्था में मानने के लिए, मुख्य रूप से, उनकी ऊर्ध्वाधर गति शून्य या ऋणात्मक होनी चाहिए, जिसे हम के मान से निर्धारित करते हैं। _velocity.y एक अन्य महत्वपूर्ण मानदंड चरित्र के पैरों के नीचे एक सतह की उपस्थिति है, जिसे हम रिगिडबॉडी आंदोलन के परिणामों से पहचानते हैं, अर्थात की उपस्थिति के माध्यम से। surfaceHit तीसरा कारक सतह के झुकाव का कोण है, जिसका विश्लेषण हम इस सतह के सामान्य के आधार पर करते हैं, यानी, का मान। इस कोण की तुलना से करना आवश्यक है - सतह का अधिकतम संभव कोण जिस पर चरित्र स्थिर रूप से खड़ा हो सकता है। surfaceHit.normal _maxSlop पूरी तरह से ऊर्ध्वाधर सतह के लिए, अभिलंब पूरी तरह से क्षैतिज होगा, यानी, इसका सदिश मान (1, 0) या (-1, 0) होगा। क्षैतिज सतह के लिए, अभिलंब का मान (0, 1) होगा। झुकाव का कोण जितना छोटा होगा, का मान उतना ही अधिक होगा। कोण के लिए, इस मान की गणना इस प्रकार की जा सकती है: y alpha चूँकि हमारा कोण डिग्री में दिया गया है, और फ़ंक्शन $\cos$ को रेडियन की आवश्यकता है, इसलिए सूत्र को इस रूप में परिवर्तित किया जाता है: इसके लिए, आइए एक नया क्षेत्र प्रस्तुत करें और इसे विधि में परिकलित करें। Awake private float _minGroundVertical; private void Awake() { _minGroundVertical = Mathf.Cos(_maxSlop * Mathf.PI / 180f); //... } अब हम में अपने कोड को अपडेट करते हैं, उपरोक्त सभी शर्तों की जाँच करते हैं। FixedUpdate if (_velocity.y <= 0 && slideResults.surfaceHit) { var surfaceHit = slideResults.surfaceHit; Velocity = ClipVector(_velocity, surfaceHit.normal); State = surfaceHit.normal.y >= _minGroundVertical ? CharacterState.Grounded : CharacterState.Airborne; } else { State = CharacterState.Airborne; } यह तर्क हमें यह सटीक रूप से निर्धारित करने में सक्षम करेगा कि पात्र कब जमीन पर है और उनकी स्थिति में होने वाले परिवर्तनों पर सही ढंग से प्रतिक्रिया कैसे दी जाए। कैप्टन में कैरेक्टरबॉडी जोड़ना अब जबकि हमारा CharacterBody घटक तैयार है, अंतिम चरण इसे हमारे Captain में जोड़ना है। दृश्य पर, Captain ऑब्जेक्ट का चयन करें और घटक को इसमें जोड़ें। CharacterBody ऊपर दिए गए चित्र में दिखाए अनुसार Rigidbody को कॉन्फ़िगर करना न भूलें। Gravity Factor को 3 पर सेट करें और Solid Layer के लिए डिफ़ॉल्ट विकल्प चुनें। अब आप खेल शुरू कर सकते हैं और वेग के लिए अलग-अलग मान सेट करके प्रयोग कर सकते हैं, ताकि आप देख सकें कि हमारा पात्र दृश्य में किस प्रकार घूमता है। अब समापन बेशक, हमें अभी भी कैरेक्टर कंट्रोल जोड़ने की ज़रूरत है। हालाँकि, यह लेख पहले से ही काफी लंबा हो चुका है, इसलिए मैं अगले लेख में नए इनपुट सिस्टम का उपयोग करके कैरेक्टर के नियंत्रण के बारे में विस्तार से बताऊंगा: "यूनिटी में कैरेक्टर कंट्रोलर 2D बनाना: भाग 2।" आप इस लेख में वर्णित संपूर्ण प्रोजेक्ट को यहाँ से डाउनलोड कर सकते हैं: और यदि आपको कोई कठिनाई आती है तो व्यवहार में सब कुछ जाँच लें। 2D प्लेटफ़ॉर्मर बनाने में कैरेक्टर कंट्रोलर विकसित करना एक महत्वपूर्ण पहलू है, क्योंकि यह गेम के आगे के विकास को निर्धारित करता है। यह प्रभावित करता है कि मुख्य नायक या दुश्मनों के व्यवहार में कितनी आसानी से नई सुविधाएँ जोड़ी जाएँगी। इसलिए, स्वतंत्र रूप से अपना खुद का गेम विकसित करने में सक्षम होने के लिए मूल बातें समझना बहुत महत्वपूर्ण है। ट्रेजर हंटर्स