गैर-समग्र आर्थिक योजना की अद्भुत दुनिया में आपका स्वागत है । मैं एक जाली ग्रिड पथ योजनाकार का उपयोग करके ऐसा करने की सलाह देता हूं । अन्य विकल्पों में किनाडायनामिक आरआरटी , और प्रक्षेपवक्र अनुकूलन शामिल हैं । गैर-होलोनोमिक सिस्टम में कार, नाव, यूनीसाइकिल, या वास्तव में कुछ भी शामिल है जहां वाहन किसी भी दिशा में यात्रा नहीं कर सकता है। इन प्रणालियों की योजना होलोनोमिक प्रणालियों की तुलना में बहुत कठिन है और ~ 2000 तक शैक्षणिक अनुसंधान के किनारे पर थी। आजकल चुनने के लिए बहुत सारे एल्गोरिदम हैं, जो शालीनता से काम करते हैं।
यहां देखिए यह कैसे काम करता है।
राज्य
आपकी कार का कॉन्फ़िगरेशन क्यू वास्तव में कार की एक्स, वाई स्थिति और इसके अभिविन्यास टी युक्त 3 डी राज्य है । आपके ए * एल्गोरिथ्म में नोड वास्तव में 3 डी वैक्टर हैं।
class Node
{
// The position and orientation of the car.
float x, y, theta;
}
क्रिया
तो किनारों का क्या?
यह थोड़ा कठिन है, क्योंकि आपकी कार वास्तव में पहिया को चालू करने के लिए अनंत तरीके चुन सकती है । इसलिए, हम कार को असतत सेट, ए पर ले जा सकने वाली क्रियाओं की संख्या को सीमित करके एक जाली ग्रिड प्लानर के लिए इसे सुलभ बना सकते हैं । सादगी के लिए मान लें कि कार में तेजी नहीं है, बल्कि इसके वेग को तुरंत बदल सकता है। हमारे मामले में, ए इस प्रकार हो सकता है:
class Action
{
// The direction of the steering wheel.
float wheelDirection;
// The speed to go at in m/s.
float speed;
// The time that it takes to complete an action in seconds.
float dt;
}
अब, हम कार्यों का एक असतत सेट बना सकते हैं जो कार किसी भी समय ले सकती है। उदाहरण के लिए, 0.5 सेकंड के लिए पूरी तरह से गैस को दबाते समय एक कठोर अधिकार इस तरह दिखाई देगा:
Action turnRight;
turnRight.speed = 1;
turnRight.wheelDirection = 1;
turnRight.dt = 0.5;
कार को रिवर्स और बैक अप में लाना इस तरह होगा:
Action reverse;
reverse.speed = -1;
reverse.wheelDirection = 0;
reverse.dt = 0.5;
और आपके कार्यों की सूची इस तरह दिखाई देगी:
List<Action> actions = { turnRight, turnLeft, goStraight, reverse ...}
आपको यह परिभाषित करने के तरीके की भी ज़रूरत है कि नोड पर की गई कार्रवाई नए नोड में कैसे परिणाम देती है। इसे सिस्टम की आगे की गतिशीलता कहा जाता है।
// These forward dynamics are for a dubin's car that can change its
// course instantaneously.
Node forwardIntegrate(Node start, Action action)
{
// the speed of the car in theta, x and y.
float thetaDot = action.wheelDirection * TURNING_RADIUS;
// the discrete timestep in seconds that we integrate at.
float timestep = 0.001;
float x = start.x;
float y = start.y;
float theta = start.theta;
// Discrete Euler integration over the length of the action.
for (float t = 0; t < action.dt; t += timestep)
{
theta += timestep * thetaDot;
float xDot = action.speed * cos(theta);
float yDot = action.speed * sin(theta);
x += timestep * xDot;
y += timestep * yDot;
}
return Node(x, y, theta);
}
असतत ग्रिड कोशिकाओं
अब, जाली ग्रिड का निर्माण करने के लिए, हमें कार के राज्यों को असतत ग्रिड कोशिकाओं में हैश करने की आवश्यकता है । यह उन्हें असतत नोड्स में बदल देता है जो ए * द्वारा पीछा किया जा सकता है। यह अति-महत्वपूर्ण है क्योंकि अन्यथा A * में यह जानने का कोई तरीका नहीं होगा कि दो कार राज्य वास्तव में उनकी तुलना करने के लिए समान हैं या नहीं। हैशिंग से पूर्णांक ग्रिड सेल मानों तक, यह तुच्छ हो जाता है।
GridCell hashNode(Node node)
{
GridCell cell;
cell.x = round(node.x / X_RESOLUTION);
cell.y = round(node.y / Y_RESOLUTION);
cell.theta = round(node.theta / THETA_RESOLUTION);
return cell;
}
अब, हम एक ए * योजना कर सकते हैं जहां ग्रिडसील्स नोड्स हैं, एक्ट्स नोड्स के बीच के किनारे हैं, और ग्रिडसील्स के संदर्भ में स्टार्ट और गोल व्यक्त किए जाते हैं। दो GridCells के बीच अनुमानी x और y के बीच की दूरी है, जो थीटा में कोणीय दूरी है।
पथ का अनुसरण
अब जब हमारे बीच ग्रिडस्केल्स और क्रियाओं के संदर्भ में एक रास्ता है, तो हम कार के लिए एक पथ अनुयायी लिख सकते हैं। चूँकि ग्रिड कोशिकाएँ असतत होती हैं, इसलिए कार इनबिल्टीन कोशिकाओं को कूदती है। इसलिए हमें रास्ते में कार की गति को सुचारू करना होगा। यदि आपका गेम एक भौतिकी इंजन का उपयोग कर रहा है, तो इसे स्टीयरिंग कंट्रोलर लिखकर पूरा किया जा सकता है जो कार को रास्ते के करीब रखने की कोशिश करता है। अन्यथा, आप बीज़ियर कर्व्स का उपयोग करके पथ को चेतन कर सकते हैं या बस पथ के निकटतम कुछ बिंदुओं से औसत कर सकते हैं।