Cave: शुरूआती मार्गदर्शिका

Back to Learn

Cave: शुरुआत मार्गदर्शिका

Lesson 15 of 19 • 50 XP

Keep your place in this quest

Log in or sign up for free to subscribe, follow lesson progress, and access more learning content.

अब जब आपने देखा है कि कैव में कैरेक्टर्स और एनीमेशन कैसे काम करते हैं, तो चलिए एक कदम पीछे हटकर समझते हैं स्क्रिप्टिंग सिस्टम को जो आमतौर पर सब कुछ जोड़ता है: Python

कैव में प्लेयर व्यवहार, एडिटर टूल्स, UI कॉलबैक्स, एनीमेशन कॉलबैक्स, टाइमलाइन इवेंट्स, और छोटे कस्टम लॉजिक के लिए Python का इस्तेमाल किया जाता है, जो बिल्ट-इन कंपोनेंट के रूप में बहुत विशेष हो सकते हैं। कैव का उपयोग करने से पहले आपको एक अनुभवी Python प्रोग्रामर बनने की जरूरत नहीं है, लेकिन कैव स्क्रिप्ट का मूल स्वरूप समझना बहुत उपयोगी है।

इस पाठ में, आप सीखेंगे:

  • कैव में Python का क्या उपयोग है।
  • Python Script अस्सेट्स और Python Components कैसे मिलकर काम करते हैं।
  • start() और update() क्या करते हैं।
  • स्क्रिप्ट से वर्तमान entity को कैसे एक्सेस करें।
  • किसी entity से कंपोनेंट्स कैसे प्राप्त करें।
  • Python Component या Python Code Component कब उपयोग करें।

लक्ष्य पूरा Python भाषा सिखाना नहीं है। लक्ष्य यह है कि जब आप कैव स्क्रिप्ट्स खोलें तो वे समझने में आसान लगें।

Python कहाँ सीखें?

यदि आप Python कोडिंग नहीं जानते हैं, तो Uniday Studio Python पर मुफ्त लर्निंग क्वेस्ट भी प्रदान करता है। सभी विकल्प देखने के लिए uniday.studio/learn पर जाएं या यहाँ से शुरू करें:

इस अनुभाग के लिए, हम मान लेते हैं कि आपको इन दोनों लर्न क्वेस्ट्स में दिए गए विषयों की समझ है।


कैव में Python का उपयोग

कैव में, Python वह स्क्रिप्टिंग लेयर है जिसका उपयोग तब होता है जब गेम ऑब्जेक्ट को व्यवहार की जरूरत होती है।

उदाहरण के लिए, Python का उपयोग निम्न कार्यों के लिए किया जा सकता है:

  • प्लेयर या दुश्मन को मूव करना।
  • दरवाजा खोलना।
  • एनीमेशन चलाना।
  • साउंड ट्रिगर करना।
  • टाइमलाइन शुरू करना।
  • सीन बदलना।
  • UI एलिमेंट अपडेट करना।
  • कस्टम एडिटर टूल्स बनाना।

मूल रूप से, आप Python स्क्रिप्ट्स लिखकर अपने गेम की सभी लॉजिक बना सकते हैं।

इसलिए स्टार्टअप प्रोजेक्ट में पहले से Python स्क्रिप्ट्स शामिल होती हैं। उदाहरण के लिए, डिफ़ॉल्ट प्लेयर केवल एनीमेशन वाला मेष नहीं है, बल्कि इसमें इनपुट पढ़ना, कैरेक्टर को मूव करना, मेष को घुमाना और सही एनीमेशन चलाना जैसी गेमप्ले लॉजिक भी होती है।

तो, जब आप कैव में Python लिख रहे होते हैं, तो आमतौर पर आप अलग-थलग कोड नहीं लिख रहे होते। आप उस entity को नियंत्रित करने वाली लॉजिक लिख रहे होते हैं और उस entity से जुड़े कंपोनेंट्स से बात कर रहे होते हैं।

स्क्रिप्ट अस्सेट्स और Python Components

Python कोड आमतौर पर एक Python Script अस्सेट के अंदर रहता है।

image.png

फिर, उस स्क्रिप्ट को सीन में चलाने के लिए, आप एक entity में Python Component जोड़ते हैं और उस स्क्रिप्ट की वह क्लास चुनते हैं जिसे चलाना है।

इसे इस तरह सोचें:

हिस्सा क्या करता है
Python Script asset कोड को स्टोर करता है।
Python Component उस स्क्रिप्ट से एक क्लास को entity पर चलाता है।
Entity वह ऑब्जेक्ट जिसे स्क्रिप्ट नियंत्रित करती है।
cave.Component क्लास वह व्यवहार जो आपने लिखा है।

उदाहरण के लिए, आपके पास Door Controller नामक स्क्रिप्ट अस्सेट हो सकता है। इसके अंदर एक क्लास DoorController हो सकता है, जो cave.Component से इनहेरिट करता है। फिर आप अपने दरवाज़े की entity में Python Component जोड़ते हैं और उस क्लास को चुनते हैं।

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

एक न्यूनतम Cave कंपोनेंट

एक बेसिक Cave Python कंपोनेंट इस तरह दिखता है:

import cave

class MyComponent(cave.Component):
    def start(self, scene):
        print("The component started!")

    def update(self):
        pass

यहाँ कुछ महत्वपूर्ण बातें हैं:

  • import cave आपकी स्क्रिप्ट को Cave के Python API तक पहुंच देता है।
  • class MyComponent(cave.Component) एक कंपोनेंट क्लास बनाता है जिसे Cave चला सकती है।
  • start(self, scene) कंपोनेंट के शुरू होने पर चलता है।
  • update(self) जब कंपोनेंट सक्रिय हो तो हर फ्रेम चलता है।

नाम MyComponent कुछ भी हो सकता है, लेकिन वास्तविक प्रोजेक्ट्स में स्पष्ट नाम जैसे DoorController, EnemyAI, Checkpoint, या PlayerHealth इस्तेमाल करें।

लाइफसायकल मेथड्स

जब आपका कंपोनेंट चल रहा होता है तो Cave कुछ मेथड्स अपने आप कॉल करता है।

सबसे आम मेथड्स:

मेथड कब चलता है सामान्य उपयोग
start(self, scene) कंपोनेंट शुरू होने पर। रिफरेंस लेना, प्रॉपर्टीज पढ़ना, वेरिएबल्स तैयार करना।
firstUpdate(self) हर Entity Component के start के बाद, पहले update में। अन्य कंपोनेंट्स के इनिशियलाइज होने पर निर्भर वेरिएबल्स बनाना।
update(self) हर फ्रेम, यदि सीन पॉज़ नहीं है। मूवमेंट, इनपुट, टाईमर्स, स्टेट चेक्स।
pausedUpdate(self) हर फ्रेम, यदि सीन पॉज़ है। पॉज़्ड लॉजिक।
end(self, scene) कंपोनेंट खत्म होने पर। सफाई (clean up) यदि आवश्यक हो।

अधिकांश शुरुआती स्क्रिप्ट्स start() और update() का उपयोग करते हैं। उदाहरण के लिए, यदि आप एक मूविंग प्लेटफॉर्म बना रहे हैं, तो start() में आप मूल स्थान स्टोर कर सकते हैं, और update() में हर फ्रेम प्लेटफॉर्म को मूव कर सकते हैं।

editorUpdate और lateUpdate भी हैं, लेकिन वे थोड़े एडवांस हैं और यहाँ चर्चा नहीं करेंगे।

वर्तमान entity तक पहुंच

एक Cave कंपोनेंट के अंदर, self.entity वह entity होती है जिसके पास Python Component है।

यह Cave स्क्रिप्टिंग का सबसे महत्वपूर्ण विचारों में से एक है। स्क्रिप्ट खुद से सीन में नहीं तैरती; यह एक entity से जुड़ी होती है।

सरल उदाहरण:

import cave

class DoorController(cave.Component):
    def start(self, scene):
        self.transform = self.entity.getTransform()
        self.isOpen = False

    def update(self):
        pass

इस स्क्रिप्ट में:

  • self.entity दरवाज़े की entity है।
  • self.entity.getTransform() दरवाज़े का Transform Component प्राप्त करता है।
  • self.isOpen एक वेरिएबल है जो स्क्रिप्ट में याद रखता है कि दरवाज़ा खुला है या नहीं।

आप अक्सर इस पैटर्न का उपयोग करेंगे। पहले entity प्राप्त करें, फिर आवश्यक कंपोनेंट्स या चाइल्ड entity प्राप्त करें, और फिर अपनी लॉजिक में उनका उपयोग करें।

अन्य कंपोनेंट्स प्राप्त करना

किसी entity को नियंत्रित करने के लिए, आपको आमतौर पर उससे एक या अधिक कंपोनेंट्स प्राप्त करने होंगे।

उदाहरण के लिए, एक प्लेयर स्क्रिप्ट ले:

  • मूवमेंट या रोटेशन के लिए Transform कंपोनेंट।
  • कैरेक्टर मूवमेंट के लिए Character कंपोनेंट।
  • एनीमेशन चलाने के लिए चाइल्ड मेष entity से Animation कंपोनेंट।
  • लूपिंग साउंड के लिए Audio कंपोनेंट।

यहाँ एक छोटा उदाहरण है:

import cave

class SimpleMover(cave.Component):
    def start(self, scene):
        self.transform = self.entity.getTransform()
        self.speed = 2.0

    def update(self):
        self.transform.move(0, 0, self.speed * cave.getDeltaTime(), local=True)

यह entity को हर फ्रेम आगे बढ़ाता है।

महत्वपूर्ण हिस्सा है cave.getDeltaTime()। क्योंकि update() हर फ्रेम चलता है, इसलिए मूवमेंट को डेल्टा टाइम से गुणा करने से मूवमेंट की गति फ्रेम रेट बदलने पर भी स्थिर रहती है।

कस्टम प्रॉपर्टीज पढ़ना

पहले टेस्ट के लिए हार्डकोडेड मान ठीक हैं, लेकिन संपादित करने योग्य प्रॉपर्टीज असली गेम ऑब्जेक्ट्स के लिए बेहतर होती हैं।

उदाहरण के लिए, यह लिखने के बजाय:

self.speed = 2.0

आप entity की प्रॉपर्टीज से मान पढ़ सकते हैं:

self.speed = self.entity.properties.get("speed", 2.0)

इसका मतलब:

  • यदि entity में speed प्रॉपर्टी है, तो उसका उपयोग करें।
  • यदि नहीं है, तो डिफ़ॉल्ट मान 2.0 लें।

यह पुन: उपयोग करने योग्य स्क्रिप्ट्स के लिए बहुत उपयोगी है। आप एक SimpleMover स्क्रिप्ट बना सकते हैं और उसे कई entities पर उपयोग कर सकते हैं, हर एक की अलग गति के साथ।

उदाहरण:

Entity speed प्रॉपर्टी
Slow Platform 1.0
Fast Platform 4.0
Moving Hazard 7.0

स्क्रिप्ट समान रहती है, लेकिन व्यवहार entity के अनुसार बदलता है।

वैकल्पिक रूप से, आप कंपोनेंट के लिए लोकल वेरिएबल्स भी बना सकते हैं जिन्हें प्रत्येक इंस्टेंस में अलग से बदला जा सकता है। जैसे:

import cave

class PlatformMover(cave.Component):
    # यह लोकल होगा:
    speed = 2.0

    def start(self, scene: cave.Scene):
        pass

    def update(self):
        events = cave.getEvents()

यह speed वेरिएबल हर कंपोनेंट इंस्टेंस के लिए लोकल रूप से परिवर्तनीय होगा:

image.png


चाइल्ड Entities प्राप्त करना

कई Cave ऑब्जेक्ट्स छोटे हाइरार्की के रूप में बने होते हैं।

प्लेयर टेम्पलेट इसका अच्छा उदाहरण है। रूट Player entity में कैरेक्टर फिजिक्स और लॉजिक है, जबकि चाइल्ड Mesh entity में विजुअल कैरेक्टर मेष और Animation Component है।

इसलिए, यदि रूट प्लेयर entity की एक स्क्रिप्ट एनीमेशन चलाना चाहती है, तो पहले वह चाइल्ड मेष entity प्राप्त करती है:

import cave

class PlayerAnimationExample(cave.Component):
    def start(self, scene):
        self.mesh = self.entity.getChild("Mesh")
        self.animator = self.mesh.get("Animation")

    def update(self):
        self.animator.playByName("p-idle", blend=0.2, loop=True)

यह वही पैटर्न है जो डिफ़ॉल्ट प्लेयर कंट्रोलर इस्तेमाल करता है:

  1. चाइल्ड entity प्राप्त करें।
  2. उस चाइल्ड से कंपोनेंट प्राप्त करें।
  3. जरूरत पड़ने पर कंपोनेंट का उपयोग करें।

जब आप इस पैटर्न को समझ लेते हैं, तो कई Cave स्क्रिप्ट्स पढ़ना बहुत आसान हो जाता है।

getChild मेथड में एक ऑप्शनल "recursive" पैरामीटर होता है, जो डिफ़ॉल्ट रूप से True होता है। यदि True हो, तो यह सभी entity के चाइल्ड्स, चाइल्ड्स के चाइल्ड्स समेत, तब तक क्वेरी करेगा जब तक कि वह नाम से मांगे गए entity को न पा ले।

सीन Entities प्राप्त करना (Scene Queries)

जब आप कोई गेम बना रहे होते हैं, तो संभव है कि आपको सीन में अन्य entities प्राप्त करने की जरूरत पड़े। तो आइए इसे देखें। पहला कदम है सीन को प्राप्त करना, और कैव में इसे प्राप्त करने के दो तरीके हैं:

# Returns the active scene:
scene = cave.getScene()

# Returns the scene the entity belongs to:
scene = self.entity.getScene()

सुविधा के लिए, cave.Component के start और end मेथड्स में भी सीन को एक पैरामीटर के रूप में प्राप्त किया जाता है, क्योंकि यह बहुत संभावना है कि आप उन्हें उन मेथड्स में उपयोग करेंगे। लोकल कोड जैसे कि Python Code Component के लिए, डिफ़ॉल्ट रूप से आपके लिए एक scene वेरिएबल भी परिभाषित किया गया है जिसे आप जादुई रूप से "बस उपयोग करें" और अपेक्षा करें कि यह काम करेगा।

एक बार जब आपको सीन मिल जाए, तो आप निम्नलिखित कोड का उपयोग करके किसी विशिष्ट Entity को उसके नाम से प्राप्त कर सकते हैं:

watchtower = scene.get("Watch Tower 01")

Cave सीन क्लास में कई अन्य मेथड्स प्रदान करता है ताकि आप अन्य सीन क्वेरीज़ कर सकें। आप रे कास्ट, स्फीयर कास्ट कर सकते हैं, किसी संपर्क बॉक्स या स्फीयर के लिए मूलतः कॉलीशन क्वेरीज़ कर सकते हैं, या यहां तक ​​कि सभी entities, सभी मूल entities, किसी विशेष टैग वाले सभी entities, किसी विशिष्ट गुण वाले सभी entities, या किसी विशिष्ट नाम वाले entities भी प्राप्त कर सकते हैं। इसलिए अधिक विवरण के लिए Python API को देखना लाभदायक है।

हमेशा यह जांचना न भूलें कि आपकी क्वेरी ने कुछ वैध वापस किया है या नहीं। उदाहरण के लिए:

# Querying a non existent Entity:
ent = scene.get("This Entity Doesnt Exist")

if ent is None:
    print("Invalid Entity!")

Entity Components प्राप्त करना

एक बार जब आपके पास कोई विशिष्ट entity हो और आप जांच लें कि वह ज्ञात है, तो यह समझना अच्छा विचार है कि आप इससे विशेष components कैसे प्राप्त कर सकते हैं।

entity के पास एक विशेष मेथड है जिसे get कहा जाता है जिसमें आप कंपोनेंट का नाम स्ट्रिंग के रूप में पास कर सकते हैं और यह अपने आप entity लेकर यह देखने की कोशिश करता है कि क्या आपकी खोज से मेल खाने वाला कोई कंपोनेंट है:

animator = self.entity.get("Animation Component")

आसान बनाने के लिए, यदि किसी कंपोनेंट का नाम "Component" शब्द पर समाप्त होता है, जो बहुत सामान्य है, तो आप इस विधि में कंपोनेंट नाम लिखते समय इस अंत को पूरी तरह से छोड़ सकते हैं। आप यह भी चुन सकते हैं कि आप मल्टी-वर्ड कंपोनेंट नामों में व्हाइट स्पेस शामिल करना चाहते हैं या सब कुछ जोड़कर लिखना चाहते हैं।

उदाहरण के लिए, यदि आप किसी Entity से Rigid Body Component प्राप्त करना चाहते हैं, भले ही इसका Python नाम RigidBodyComponent है, नीचे दिए गए सभी विकल्प काम करेंगे:

rb = self.entity.get("Rigid Body")
rb = self.entity.get("RigidBody")
rb = self.entity.get("Rigid Body Component")
rb = self.entity.get("RigidBodyComponent")
rb = self.entity.get("RigidBody Component")

चूंकि Python बहुत अधिक टाइप-हेवी नहीं है, Cave में एक अच्छी प्रोग्रामिंग प्रैक्टिस है कि आप components के प्रकार के लिए टाइप हिंट प्रदान करें, जिसे नीचे दिए तरीके से किया जा सकता है। ध्यान दें कि इस मामले में, आपको पूर्ण कंपोनेंट नाम शामिल करना होगा क्योंकि यह Python सेमांटिक है:

rb : cave.RigidBodyComponent = self.entity.get("Rigid Body")

यह IntelliSense को बाहरी संपादकों जैसे Visual Studio Code में काम करने की अनुमति देता है या यहां तक ​​कि Cave Engine द्वारा दिए गए बिल्ट-इन ऑटोकम्प्लीट को भी इसके एम्बेडेड स्क्रिप्ट एडिटर में।

Transform Component के लिए, क्योंकि यह सबसे सामान्य कंपोनेंट प्रकारों में से एक है और आप इसे अक्सर क्वेरी करेंगे, entity के पास इसका प्रमुख Transform प्राप्त करने के लिए एक मूल मेथड है:

transf = self.entity.getTransform()

self.entity.getTransform() को कॉल करके इसे प्राप्त करना self.entity.get("Transform") को कॉल करने जैसा ही परिणाम देता है, लेकिन पहला विकल्प तेजी से और अधिक अनुकूलित है।

यदि किसी entity के पास एक ही प्रकार के कई components हैं, तो यह पहली मैचिंग लौटाएगा, लेकिन कभी-कभी आप सभी मैचिंग चाहते हैं। उदाहरण के लिए, एक मल्टी-मैटेरियल मेष जो cave में एक entity द्वारा दर्शाया जाता है जिसमें कई मेष components होते हैं, आप सभी मेष components प्राप्त करना चाह सकते हैं। इसके लिए, आप getAll मेथड का उपयोग कर सकते हैं:

meshCmps = self.entity.getAll("Mesh")

# Changing all the materials to a glowing one:
for meshCmp in meshCmps:
    meshCmp.material.setAsset("Glowing Material")

Entity Python Components प्राप्त करना

अब हम जान गए कि नेटिव Cave Components कैसे प्राप्त करें, लेकिन अगर आप किसी entity से Python में खुद द्वारा लिखा गया एक कस्टम कंपोनेंट प्राप्त करना चाहते हैं तो क्या?

इसके लिए, आपको एक विशेष मेथड getPy की जरूरत होती है, और यह नियमित get मेथड की तरह ही काम करता है, बस यह Python कंपोनेंट भी लौटाता है:

myCmp = self.entity.getPy("MyCustomComponent")

यह एक विशेष मेथड इसलिए आवश्यक है क्योंकि आंतरिक अनुकूलनों के चलते Cave को जितनी तेजी से संभव हो चलाने के लिए।

एक बार जब आपके पास आपका कस्टम Python Component होता है, तो आप इसके Python में बने वेरिएबल्स और मेथड्स को स्वतंत्र रूप से एक्सेस कर सकते हैं:

myCmp = self.entity.getPy("MyCustomComponent")

# Python वेरिएबल्स बदलना:
myCmp.customValue = 10

# कस्टम मेथड्स कॉल करना:
myCmp.doSomething()
myCmp.applyDamage(10)

Python Code Component

साधारण Python Component के अलावा, Cave में एक Python Code Component भी होता है। Python Code Component उपयोगी होता है सीधे entity पर लिखे गए त्वरित स्क्रिप्ट्स के लिए, बिना पहले अलग Python Script asset बनाए।

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

यह उपयोगी होता है:

  • त्वरित परीक्षणों के लिए।
  • छोटे कॉलबैक के लिए।
  • एकबारगी व्यवहार के लिए।
  • प्रोटोटाइप के लिए।

यह बड़े गेमप्ले सिस्टम के लिए सबसे अच्छा विकल्प नहीं है क्योंकि कोड को पुन: उपयोग और व्यवस्थित करना कठिन होता है, लेकिन यह छोटे कोड के लिए आदर्श है।

Python Component बनाम Python Code Component

इसे एक सरल नियम के रूप में उपयोग करें:

यह उपयोग करें कब
Python Component व्यवहार को पुन: उपयोग किया जाना चाहिए, एक asset के रूप में संपादित किया जाना चाहिए, या समय के साथ बढ़ना चाहिए।
Python Code Component व्यवहार छोटा, स्थानीय है।

उदाहरण के लिए, पुन: उपयोग योग्य EnemyAI को एक Python Script asset होना चाहिए जो Python Component द्वारा उपयोग किया जाए। एक छोटा कोड जो कुछ प्रिंट करता है या एक बटन दबाने पर फ़ंक्शन कॉल करता है, वह Python Code Component हो सकता है।

एक अच्छा पहला स्क्रिप्ट लक्ष्य

एक अच्छा पहला Cave स्क्रिप्ट कुछ छोटा और दिखाई देने वाला होता है।

इनमें से एक बनाने का प्रयास करें:

  • एक ऐसा प्लेटफ़ॉर्म जो आगे बढ़ता हो।
  • एक ऐसा दरवाजा जो सीन शुरू होते ही खुल जाए।
  • एक ऐसी लाइट जो हर कुछ सेकंड में चालू और बंद हो जाए।
  • एक ऐसा pickup जो आवाज़ बजाए और खुद को डिसेबल कर दे।
  • एक बटन जो दूसरे सीन में बदलता हो।

ये उदाहरण छोटे हैं, लेकिन ये सबसे महत्वपूर्ण वर्कफ़्लो सिखाते हैं: entity प्राप्त करना, component प्राप्त करना, कुछ बदलना, Play Mode में परीक्षण करना, और समायोजन करना।

आपको क्या याद रखना चाहिए

Cave में Python स्क्रिप्ट्स आमतौर पर entities से Python Components के माध्यम से जुड़ी होती हैं।

सबसे महत्वपूर्ण शुरुआती पैटर्न:

  1. start() का उपयोग संदर्भ प्राप्त करने और मान तैयार करने में करें।
  2. update() को हर फ्रेम व्यवहार चलाने के लिए उपयोग करें।
  3. self.entity का उपयोग उस entity तक पहुँचने के लिए करें जो स्क्रिप्ट का मालिक है।
  4. वास्तविक रूप से ऑब्जेक्ट को मूव, एनीमेट, साउंड प्ले, या नियंत्रित करने के लिए components का उपयोग करें।

जब यह पैटर्न स्वाभाविक लगने लगे, तब Cave में स्क्रिप्टिंग अधिक रहस्यमय नहीं रह जाती। आप केवल कोड नहीं लिख रहे हैं। आप entities को व्यवहार करना सिखा रहे हैं।