2D प्लेटफ़ॉर्मर AABB टकराव की समस्या


51

http://dl.dropbox.com/u/3724424/Programming/Gifs/game6.gif

मुझे एएबीबी टक्कर संकल्प के साथ एक समस्या है।


मैं एक्स अक्ष को पहले हल करके एएबीबी चौराहे को हल करता हूं, फिर वाई अक्ष को। यह इस बग को रोकने के लिए किया जाता है: http://i.stack.imgur.com/NLg4j.png


वर्तमान विधि ठीक काम करती है जब कोई वस्तु खिलाड़ी में जाती है और खिलाड़ी को क्षैतिज रूप से धकेलना पड़ता है। जैसा कि आप .gif में देख सकते हैं, क्षैतिज स्पाइक्स खिलाड़ी को सही ढंग से धकेलते हैं।


जब ऊर्ध्वाधर स्पाइक्स खिलाड़ी में चले जाते हैं, हालांकि, एक्स अक्ष अभी भी पहले हल हो गया है। यह "लिफ्ट के रूप में स्पाइक्स का उपयोग करना" असंभव बनाता है।

जब खिलाड़ी ऊर्ध्वाधर स्पाइक्स में जाता है (गुरुत्वाकर्षण से प्रभावित होता है, तो उनमें गिर जाता है), उसे वाई अक्ष पर धकेल दिया जाता है, क्योंकि एक्स अक्ष पर कोई ओवरलैप नहीं था जिसके साथ शुरू करना था।


कुछ मैंने कोशिश की इस लिंक के पहले उत्तर में वर्णित विधि थी: 2 डी आयताकार वस्तु टकराव का पता लगाने

हालाँकि स्पाइक्स और मूविंग ऑब्जेक्ट्स अपनी स्थिति में परिवर्तन करके चलते हैं, वेग से नहीं, और मैं उनकी अगली अनुमानित स्थिति की गणना तब तक नहीं करता जब तक कि उनके अपडेट () विधि को नहीं कहा जाता। कहने की जरूरत नहीं है कि यह समाधान भी काम नहीं किया। :(


मुझे एएबीबी की टक्कर को इस तरह से हल करने की आवश्यकता है कि दोनों मामले ऊपर वर्णित कार्य के अनुसार।

यह मेरा वर्तमान टक्कर स्रोत कोड है: http://pastebin.com/MiCi3nA1

मैं वास्तव में आभारी रहूंगा यदि कोई इस पर गौर कर सकता है, क्योंकि यह बग शुरू से ही इंजन में सभी तरह से मौजूद है, और मैं बिना किसी सफलता के, एक अच्छा समाधान खोजने के लिए संघर्ष कर रहा हूं। यह मुझे गंभीरता से टकराव कोड को देखने में रात बिताने और मुझे "मज़ेदार हिस्सा" होने से रोक रहा है और गेम लॉजिक को कोडिंग कर रहा है :(


मैंने XNA AppHub के प्लेटफ़ॉर्मर डेमो (सामान की अधिकांश कॉपी-पेस्ट करके) के समान टकराव प्रणाली को लागू करने का प्रयास किया। हालाँकि "जंपिंग" बग मेरे खेल में होता है, जबकि यह AppHub डेमो में नहीं होता है। [जंपिंग बग: http://i.stack.imgur.com/NLg4j.png ]

कूदने के लिए मैं जाँचता हूँ कि क्या खिलाड़ी "ऑनग्राउंड" है, तो वेलोसिटी में -5 जोड़ें।

चूंकि खिलाड़ी का वेलोसिटी.एक्स वेलोसिटी से अधिक है। वे (आरेख में चौथे पैनल को देखें), ऑनगैंग सही पर सेट है जब यह नहीं होना चाहिए, और इस तरह खिलाड़ी को मध्य-हवा में कूदने की अनुमति मिलती है।

मेरा मानना ​​है कि AppHub डेमो में ऐसा नहीं होता है क्योंकि खिलाड़ी का वेलोसिटी। X वेलोसिटी से अधिक कभी नहीं होगा। हां, लेकिन मुझसे गलती हो सकती है।

मैंने इसे पहले एक्स अक्ष पर हल करने से पहले हल किया, फिर वाई अक्ष पर। लेकिन जैसा कि मैंने ऊपर कहा कि स्पाइक्स के साथ टकराव को कम कर देता है।


5
वास्तव में कुछ भी गलत नहीं हो रहा है। जिस विधि का उपयोग कर रहा हूं, वह पहले एक्स अक्ष पर पुश करता है, फिर वाई अक्ष पर। यही कारण है कि खिलाड़ी ऊर्ध्वाधर स्पाइक्स पर भी क्षैतिज रूप से धकेल दिया जाता है। मुझे एक समाधान खोजने की आवश्यकता है जो "कूदने की समस्या" से बचा जाता है और उथले अक्ष (कम से कम प्रवेश के साथ अक्ष) पर खिलाड़ी को धक्का देता है, लेकिन मुझे कोई नहीं मिल सकता है।
विटोरियो रोमियो

1
आप पता लगा सकते हैं कि खिलाड़ी किस बाधा को छू रहा है, और यह
निर्धारित करें

4
@ जोनाथन हॉब्स, प्रश्न पढ़ें। Vee जानता है कि उसका कोड क्या कर रहा है, लेकिन यह नहीं जानता कि एक निश्चित समस्या को कैसे हल किया जाए। कोड के माध्यम से कदम रखने से उसे इस स्थिति में मदद नहीं मिलेगी।
अटैकिंगहोबो

4
@Maik @Jonathan: कुछ भी नहीं "गलत चल रहा है" कार्यक्रम के साथ - वह समझता है कि उसका एल्गोरिथ्म वह कहाँ और क्यों करता है जो वह नहीं चाहता है। वह सिर्फ यह नहीं जानता कि एल्गोरिथ्म को कैसे बदलना है जो वह चाहता है। तो डिबगर इस मामले में उपयोगी नहीं है।
ब्लूराजा - डैनी पफ्लुगुएफ्ट

1
@AttackingHobo @BlueRaja मैं सहमत हूं और मैंने अपनी टिप्पणी हटा दी है। वह मुझे सिर्फ निष्कर्ष के बारे में बता रहा था कि क्या चल रहा था। मैं वास्तव में माफी माँगता हूँ कि आपको यह समझाने के लिए कि कम से कम एक व्यक्ति को गुमराह करना है। ईमानदारी से, आप अगली बार किसी भी प्रतिक्रिया को छोड़ने से पहले सवाल को ठीक से अवशोषित करने के लिए मुझ पर भरोसा कर सकते हैं।
doppelgreener

जवाबों:


9

ठीक है, मुझे पता चला कि XNA AppHub प्लेटफ़ॉर्मर डेमो में "जंपिंग" बग क्यों नहीं है: डेमो ऊपर से नीचे तक टकराव टाइल्स का परीक्षण करता है । जब एक "दीवार" के खिलाफ खिलाड़ी कई टाइलों को ओवरलैप कर रहा हो सकता है। रिज़ॉल्यूशन ऑर्डर महत्वपूर्ण है क्योंकि एक टकराव को हल करने से अन्य टकराव (लेकिन एक अलग दिशा में) भी हल हो सकते हैं। onGroundसंपत्ति केवल सेट जब टकराव y- अक्ष पर खिलाड़ी को धक्का द्वारा हल हो गई है है। यह संकल्प तब नहीं होगा जब पिछले प्रस्तावों ने खिलाड़ी को नीचे और / या क्षैतिज रूप से धक्का दिया।

मैं इस लाइन को बदलकर XNA डेमो में "जंपिंग" बग को पुन: उत्पन्न करने में सक्षम था:

for (int y = topTile; y <= bottomTile; ++y)

इसके लिए:

for (int y = bottomTile; y >= topTile; --y)

(मैंने भौतिकी से संबंधित कुछ स्थिरांक भी टाल दिए, लेकिन इससे कोई फर्क नहीं पड़ना चाहिए।)

शायद bodiesToCheckअपने खेल में टकरावों को हल करने से पहले y- अक्ष पर छाँटना "कूद" बग को ठीक कर देगा। मेरा सुझाव है कि प्रवेश के "उथले" अक्ष पर टकराव को हल करना, जैसा कि XNA डेमो करता है और ट्रेवर सुझाव देता है । यह भी ध्यान दें कि XNA डेमो प्लेयर टकराने योग्य टाइलों से दोगुना लंबा है, जिससे कई टकराव का मामला अधिक संभावना है।


यह दिलचस्प लगता है ... क्या आपको लगता है कि टकरावों का पता लगाने से पहले वाई द्वारा सब कुछ आदेश देने से मेरी सभी समस्याएं हल हो सकती हैं? क्या कोई पकड़ है?
विटोरियो रोमियो

Aaaand मैंने "पकड़" पाया। इस पद्धति का उपयोग करते हुए, जंपिंग बग को ठीक किया जाता है, लेकिन अगर मैं वेलोसिटी सेट करता हूं। छत से टकराने के बाद यह 0 से 0 हो जाता है, यह फिर से होता है।
विटोरियो रोमियो

@Vee: Position = nextPositionतुरंत forलूप के अंदर सेट करें , अन्यथा अवांछित टक्कर रिज़ॉल्यूशन (सेटिंग onGround) अभी भी होते हैं। छत से टकराने पर खिलाड़ी को नीचे की ओर (और कभी भी ऊपर नहीं) धकेलना onGroundचाहिए, इस तरह कभी सेट नहीं करना चाहिए। यह इस तरह से है कि XNA डेमो करता है, और मैं वहां "सीलिंग" बग को नहीं हटा सकता।
लेफ्टियम

pastebin.com/TLrQPeBU - यह मेरा कोड है: मैं वास्तव में "नेक्स्टपोजिशन" वैरिएबल का उपयोग किए बिना, स्थिति पर ही काम करता हूं। इसे XNA डेमो में काम करना चाहिए, लेकिन अगर मैं वेग को सेट करने वाली लाइन को रखता हूं। यह 0 से (लाइन 57) अनियोजित है तो जंपिंग बग होता है। अगर मैं इसे हटा देता हूं, तो खिलाड़ी छत पर कूदते समय तैरता रहता है। क्या इसे ठीक किया जा सकता है?
विटोरियो रोमियो

@Vee: आपका कोड दिखाता नहीं है कि कैसे onGroundसेट किया गया है, इसलिए मैं जांच नहीं कर सकता कि कूदने की अनुमति गलत तरीके से क्यों दी गई है। XNA डेमो अपने अनुरूप isOnGroundसंपत्ति को अद्यतन करता है HandleCollisions()। इसके अलावा, Velocity.Y0 पर सेट करने के बाद , गुरुत्वाकर्षण फिर से खिलाड़ी को नीचे ले जाना क्यों शुरू नहीं करता है? मेरा अनुमान है कि onGroundसंपत्ति अनुचित रूप से निर्धारित है। XNA डेमो अपडेट previousBottomऔर isOnGround( IsOnGround) पर एक नज़र डालें ।
लेफ्टियम

9

आपके लिए सबसे सरल उपाय यह होगा कि आप किसी भी टकराव को हल करने से पहले दुनिया में हर वस्तु के खिलाफ टकराव की दिशाओं की जाँच करें, और दो छोटे परिणामी "यौगिक टकरावों" को हल करें। इसका अर्थ है कि आप हमेशा पहले x को हल करने के बजाय, या हमेशा पहले y को हल करने के बजाय छोटी से छोटी राशि द्वारा हल करते हैं।

आपका कोड कुछ इस तरह दिखाई देगा:

// This loop repeats, until our object has been fully pushed outside of all
// collision objects
while ( StillCollidingWithSomething(object) )
{
  float xDistanceToResolve = XDistanceToMoveToResolveCollisions( object );
  float yDistanceToResolve = YDistanceToMoveToResolveCollisions( object );
  bool xIsColliding = (xDistanceToResolve != 0.f);

  // if we aren't colliding on x (not possible for normal solid collision 
  // shapes, but can happen for unidirectional collision objects, such as 
  // platforms which can be jumped up through, but support the player from 
  // above), or if a correction along y would simply require a smaller move 
  // than one along x, then resolve our collision by moving along y.

  if ( !xIsColliding || fabs( yDistanceToResolve ) < fabs( xDistanceToResolve ) )
  {
    object->Move( 0.f, yDistanceToResolve );
  }
  else // otherwise, resolve the collision by moving along x
  {
    object->Move( xDistanceToResolve, 0.f );
  }
}

बड़ा संशोधन : अन्य उत्तरों पर टिप्पणी पढ़ने से, मुझे लगता है कि मैंने अंततः एक अस्थिर धारणा पर ध्यान दिया है, जिसके कारण यह दृष्टिकोण काम नहीं करेगा (और जो बताता है कि मैं समस्याओं को क्यों नहीं समझ सका कि कुछ - लेकिन सभी नहीं - लोगों ने इस दृष्टिकोण के साथ देखा)। विस्तृत करने के लिए, यहाँ कुछ और छद्मकोश हैं, जो स्पष्ट रूप से दिखाते हैं कि मैंने पहले जिन कार्यों को संदर्भित किया था, वे वास्तव में होने चाहिए:

bool StillCollidingWithSomething( MovingObject object )
{
  // loop over every collision object in the world.  (Implementation detail:
  // don't test 'object' against itself!)
  for( int i = 0; i < collisionObjectCount; i++ )
  {
    // if the moving object overlaps any collision object in the world, then
    // it's colliding
    if ( Overlaps( collisionObject[i], object ) )
      return true;
  }
  return false;
}

float XDistanceToMoveToResolveCollisions( MovingObject object )
{
  // check how far we'd have to move left or right to stop colliding with anything
  // return whichever move is smaller
  float moveOutLeft = FindDistanceToEmptySpaceAlongNegativeX(object->GetPosition());
  float moveOutRight = FindDistanceToEmptySpaceAlongX(object->GetPosition());
  float bestMoveOut = min( fabs(moveOutLeft), fabs(moveOutRight) );

  return minimumMove;
}

float FindDistanceToEmptySpaceAlongX( Vector2D position )
{
  Vector2D cursor = position;
  bool colliding = true;
  // until we stop colliding...
  while ( colliding )
  {
    colliding = false;
    // loop over all collision objects...
    for( int i = 0; i < collisionObjectCount; i++ )
    {
      // and if we hit an object...
      if ( Overlaps( collisionObject[i], cursor ) )
      {
        // move outside of the object, and repeat.
        cursor.x = collisionObject[i].rightSide;
        colliding = true;

        // break back to the 'while' loop, to re-test collisions with
        // our new cursor position
        break;
      }
    }
  }
  // return how far we had to move, to reach empty space
  return cursor.x - position.x;  
}

यह "प्रति ऑब्जेक्ट जोड़ी" परीक्षण नहीं है; यह व्यक्तिगत रूप से दुनिया के नक्शे के प्रत्येक टाइल के खिलाफ चलती वस्तु का परीक्षण और हल करके काम नहीं करता है (यह दृष्टिकोण कभी मज़बूती से काम नहीं करेगा, और तेजी से भयावह तरीके से विफल होता है क्योंकि टाइल का आकार कम हो जाता है)। इसके बजाय, यह दुनिया के नक्शे में हर वस्तु के खिलाफ एक साथ चलती वस्तु का परीक्षण कर रहा है, और फिर पूरे विश्व के नक्शे के खिलाफ टकराव के आधार पर हल कर रहा है।

इस तरह से आप यह सुनिश्चित करते हैं कि (उदाहरण के लिए) एक दीवार के भीतर व्यक्तिगत दीवार टाइलें खिलाड़ी को दो आसन्न टाइलों के बीच ऊपर और नीचे कभी नहीं उछालती हैं, जिसके परिणामस्वरूप खिलाड़ी को कुछ गैर-अस्तित्व वाले स्थान में 'उनके बीच' फंस जाता है; टकराव के रिज़ॉल्यूशन की दूरी हमेशा दुनिया में खाली जगह की सभी तरह से गणना की जाती है, कि केवल एक टाइल की सीमा तक जो इसके ऊपर एक और ठोस टाइल हो सकती है।


1
i.stack.imgur.com/NLg4j.png - उपरोक्त विधि का उपयोग करने पर ऐसा होता है।
विटोरियो रोमियो

1
हो सकता है कि मैं आपके कोड को सही ढंग से समझ नहीं पा रहा हूं, लेकिन मुझे आरेख में समस्या के बारे में बताएं: चूंकि खिलाड़ी एक्स अक्ष पर तेज है, वाई पैठ की तुलना में एक्स पैठ> है। टकराव वाई अक्ष को चुनता है (क्योंकि प्रवेश छोटा है) और खिलाड़ी को लंबवत धक्का देता है। यह तब नहीं होता है जब खिलाड़ी काफी धीमा होता है ताकि X पैठ की तुलना में Y पैशन हमेशा> बना रहे।
विटोरियो रोमियो

1
@Vee आप इस दृष्टिकोण का उपयोग कर एक गलत व्यवहार देने के रूप में, चित्र के किस फलक का उल्लेख यहां कर रहे हैं? मैं फलक 5 मान रहा हूं, जिसमें खिलाड़ी स्पष्ट रूप से वाई की तुलना में एक्स में कम प्रवेश कर रहा है, जिसके परिणामस्वरूप एक्स अक्ष के साथ बाहर धकेल दिया जाएगा - जो कि सही व्यवहार है। यदि आप वेग के आधार पर रिज़ॉल्यूशन के लिए एक अक्ष का चयन कर रहे हैं (जैसा कि आपकी छवि में है), और वास्तविक प्रवेश (जैसा मैंने सुझाव दिया है) पर आधारित होने पर ही आपको बुरा व्यवहार मिलता है।
ट्रेवर पॉवेल

1
@ ट्रेवर: आह, मैं देख रहा हूँ कि तुम क्या कह रहे हो। उस स्थिति में, आप बस इसे बना सकते हैंif(fabs( yDistanceToResolve ) < fabs( xDistanceToResolve ) || xDistanceToResolve == 0) { object->Move( 0.f, yDistanceToResolve ); } else { object->Move( xDistanceToResolve, 0.f ); }
ब्लूराजा - डैनी पफ्लुगुएफ्ट

1
@ बब्लूराज महान बिंदु। जैसा कि आप सुझाव देते हैं, मैंने कम जवाबदेही का उपयोग करने के लिए अपना जवाब संपादित किया है। धन्यवाद!
ट्रेवर पॉवेल

6

संपादित करें

मैंने इसमें सुधार किया है

ऐसा लगता है कि मैंने जो महत्वपूर्ण चीज बदली है, वह चौराहों का वर्गीकरण है।

अंतर्विरोध या तो हैं:

  • छत के धक्कों
  • जमीन हिट (मंजिल से बाहर धक्का)
  • मध्य हवा की दीवार टकराव
  • जमीनी दीवार की टक्कर

और मैं उन्हें उसी क्रम में हल करता हूं

टाइल पर कम से कम 1/4 रास्ता होने के नाते एक जमीन की टक्कर को परिभाषित करें

तो यह एक जमीन पर टक्कर है और खिलाड़ी ( नीला ) टाइल के ऊपर बैठेगा ( काला ) जमीन की टक्कर

लेकिन यह एक जमीनी टकराव नहीं है और खिलाड़ी टाइल के दाईं ओर "फिसल" जाएगा जब वह उस पर लैंड करेगा ग्राउंड टक्कर खिलाड़ी होने के लिए गोनिग नहीं होगा

इस विधि से खिलाड़ी अब दीवारों के किनारों पर नहीं फंसेगा


मैंने आपके तरीके की कोशिश की (मेरा कार्यान्वयन देखें: pastebin.com/HarnNnnp ), लेकिन मुझे नहीं पता कि खिलाड़ी का वेग कहाँ से 0 पर सेट किया जाए। मैंने इसे 0 पर सेट करने की कोशिश की, अगर एनआरवाई 0 = 0 है, लेकिन इससे खिलाड़ी मध्य हवा में रुक जाता है। जबकि एक दीवार के साथ फिसलने और भी उसे बार-बार दीवार कूदने देता है।
विटोरियो रोमियो

हालांकि, यह सही ढंग से काम करता है जब खिलाड़ी स्पाइक्स के साथ बातचीत करता है (जैसा कि .gif में दिखाया गया है)। मैं वास्तव में सराहना करूंगा यदि आप मुझे दीवार कूदने (दीवारों में फंसने) की समस्या को हल करने में मदद कर सकते हैं। ध्यान रखें कि मेरी दीवारें कई एएबीबी टाइल्स से बनी हैं।
विटोरियो रोमियो

एक और टिप्पणी पोस्ट करने के लिए क्षमा करें, लेकिन एक बिलकुल नए प्रोजेक्ट में आपके कोड को कॉपी-पेस्ट करने के बाद, 5 से बदलकर और टाईल्स को दीवार के आकार में बनाकर, जंपिंग बग होता है (इस आरेख को देखें: i.stack.imgur.com /NLg4j.png)
विटोरियो रोमियो

ठीक है, अब कोशिश करो।
बोबोबो

+1 काम कोड नमूने के लिए (क्षैतिज रूप से चलती "स्पाइक" ब्लॉकों को याद करते हुए, हालांकि :)
लेफ्टियम

3

Forenote:
मेरा इंजन एक टकराव का पता लगाने वाले वर्ग का उपयोग करता है जो सभी वस्तुओं के साथ टकराव की जाँच करता है वास्तविक समय, केवल जब कोई वस्तु चलती है, और केवल ग्रिड वर्गों में यह वर्तमान में व्याप्त है।

मेरा समाधान:

जब मैं अपने 2d platformer में इस तरह की समस्याओं के खिलाफ भागा, तो मैंने निम्नलिखित की तरह कुछ किया:

- (इंजन संभव टकरावों का पता लगाता है, जल्दी से)
- (खेल किसी विशेष वस्तु के लिए सटीक टकरावों की जांच करने के लिए इंजन को सूचित करता है) [वस्तु का सदिश रिटर्न *]
- (वस्तु पैठ की गहराई को देखता है, साथ ही अन्य वस्तु की पिछली स्थिति के सापेक्ष पिछली स्थिति,) यह निर्धारित करने के लिए कि किस तरफ से स्लाइड करें)
- (ऑब्जेक्ट चलता है, और औसत यह ऑब्जेक्ट के वेग के साथ वेग है (यदि ऑब्जेक्ट चल रहा है)


"(ऑब्जेक्ट पैठ की गहराई को देखता है, साथ ही साथ अन्य ऑब्जेक्ट की पिछली स्थिति के सापेक्ष पिछली स्थिति, यह निर्धारित करने के लिए कि किस तरफ से बाहर स्लाइड करना है)" यह वह हिस्सा है जिसमें मैं दिलचस्पी रखता हूं। क्या आप विस्तृत कर सकते हैं? क्या यह .gif और आरेख द्वारा दर्शाई गई स्थिति में सफल होता है?
विटोरियो रोमियो

मुझे अभी तक ऐसी स्थिति (उच्च वेग के अलावा) नहीं मिली है कि यह विधि काम न करे।
अल्टिफिनिटस

अच्छा लगता है, लेकिन क्या आप वास्तव में समझा सकते हैं कि आप मर्मज्ञता को कैसे हल करते हैं? क्या आप हमेशा सबसे छोटी धुरी पर हल करते हैं? क्या आप टकराव के पक्ष की जांच करते हैं?
विटोरियो रोमियो

तथ्य यह है कि छोटी धुरी जाने के लिए एक अच्छा (प्राथमिक) तरीका नहीं है। IMHO। मैं आम तौर पर इस आधार पर हल करता हूं कि पहले कौन सी वस्तु दूसरे ऑब्जेक्ट के किनारे से बाहर थी, यह सबसे आम है। जब वह विफल हो जाता है, तो मैं वेग और गहराई के आधार पर जांच करता हूं।
अल्टिफिनिटस 2

2

वीडियो गेम में मैंने प्रोग्राम को एप्रोच किया है कि एक फंक्शन यह बताने के लिए है कि क्या आपकी स्थिति वैध है, अर्थात। बूल वैलिडपोस (इंट एक्स, इंट वाई, इंट वाई, इंट हे);

फ़ंक्शन खेल में सभी ज्यामिति के खिलाफ बाउंडिंग बॉक्स (x, y, wi, he) की जांच करता है और कोई भी चौराहा होने पर झूठे रिटर्न देता है।

यदि आप स्थानांतरित करना चाहते हैं, तो दाईं ओर बोलें, खिलाड़ी की स्थिति लें, 4 से x जोड़ें और जांचें कि क्या स्थिति वैध है, यदि नहीं, तो + 3, + 2 आदि के साथ जांचें जब तक यह है।

यदि आपको गुरुत्वाकर्षण की आवश्यकता है, तो आपको एक चर की आवश्यकता होती है जो तब तक बढ़ता है जब तक आप जमीन से नहीं टकराते (ग्राउंडिंग ग्राउंड: ValidPos (x, y + 1, wi, he) == सच है, y यहां नीचे की ओर सकारात्मक है)। यदि आप उस दूरी को स्थानांतरित कर सकते हैं (यानी। ValidPos (x, y + गुरुत्वाकर्षण, WI, वह) सही है) आप गिर रहे हैं, कभी-कभी उपयोगी होते हैं जब आपको गिरने पर आपको चरित्र को नियंत्रित करने में सक्षम नहीं होना चाहिए।

अब, आपकी समस्या यह है कि आपकी दुनिया में ऐसी वस्तुएं हैं जो सबसे पहले चलती हैं, तो आपको यह जांचना होगा कि क्या आपकी पुरानी स्थिति अभी भी वैध है!

यदि यह नहीं है, तो आपको एक स्थिति खोजने की आवश्यकता है। यदि ऑब्जेक्ट्स प्रति सेकंड 2 पिक्सेल प्रति गेम क्रांति की तुलना में तेज़ी से आगे नहीं बढ़ सकते हैं, तो आपको यह जांचना होगा कि क्या स्थिति (x, y-1) वैध है, तो (x, y-2) तब (x + 1, y) आदि। आदि (x-2, y-2) से (x + 2, y + 2) के बीच की पूरी जगह की जाँच की जानी चाहिए। यदि कोई मान्य स्थिति नहीं है तो इसका मतलब है कि आप 'क्रश' हो गए हैं।

HTH

Valmond


मैं अपने गेम मेकर दिनों में इस दृष्टिकोण का उपयोग करता था। मैं इसे बेहतर खोज के साथ इसे गति देने / बेहतर बनाने के तरीकों के बारे में सोच सकता हूं (आपके द्वारा यात्रा की गई जगह पर एक द्विआधारी खोज कहें, हालांकि आप कितनी दूरी पर गए थे और ज्यामिति, यह शायद धीमा है), लेकिन इस दृष्टिकोण का मुख्य दोष है यह कहने के बजाय कि सभी संभावित टकरावों के खिलाफ एक चेक करने के लिए, आप स्थिति में आपके परिवर्तन की जाँच कर रहे हैं।
जेफ

"आप अपनी स्थिति में जो भी बदलाव कर रहे हैं वह चेक कर रहा है" क्षमा करें लेकिन वास्तव में इसका क्या मतलब है? BTW बेशक आप खेल को गति देने के लिए अंतरिक्ष विभाजन तकनीकों (BSP, Octree, quadtree, Tilemap आदि) का उपयोग करेंगे, लेकिन आपको हमेशा ऐसा करने की आवश्यकता होगी (यदि नक्शा बड़ा है), तो सवाल इस बारे में नहीं है लेकिन एल्गोरिथ्म के बारे में (सही ढंग से) खिलाड़ी को स्थानांतरित करने के लिए उपयोग किया जाता है।
वालमन्ड

@Valmond मुझे लगता है कि @ जेफ का मतलब है कि अगर आप खिलाड़ी 10 पिक्सलों को छोड़ कर आगे बढ़ रहे हैं, तो आपके पास 10 अलग-अलग टकराव हो सकते हैं।
जोनाथन कोनेल

यदि वह जो अर्थ है तो वह सही है और यह इस तरह से होना चाहिए (जो अन्यथा बता सकते हैं कि क्या हम +6 पर रुक जाते हैं और +7 नहीं?)। कंप्यूटर तेज हैं, मैंने इसे S40 (~ 200mhz और इतना तेज नहीं kvm) पर इस्तेमाल किया और यह एक आकर्षण की तरह काम करता है। आप हमेशा प्रारंभिक अहंकार को अनुकूलित करने की कोशिश कर सकते हैं लेकिन यह हमेशा आपको कोने के मामले देगा जैसे ओपी के पास।
वालमन्ड

ठीक यही मेरा मतलब है
जेफ

2

इससे पहले कि मैं इसका उत्तर देना शुरू करूं, मेरे कुछ प्रश्न हैं। सबसे पहले, उस मूल बग में जिसमें आप दीवारों में फंस गए थे, क्या वे एक बड़े टाइल के विपरीत बाईं व्यक्तिगत टाइलों पर थे? और अगर वे थे, तो क्या खिलाड़ी उनके बीच फंस गया था? यदि उन दोनों प्रश्नों के लिए हाँ, तो सुनिश्चित करें कि आपकी नई स्थिति मान्य है । इसका मतलब यह है कि अगर खिलाड़ी को स्थानांतरित करने के लिए कह रहा है तो वहां पर टक्कर होगी। तो कम से कम विस्थापन के रूप में नीचे वर्णित का समाधान, और फिर उस आधार पर अपने खिलाड़ी के लिए कदम केवल वह करता है, तो कर सकते हैंवहां जाओ। लगभग नाक के नीचे भी: पी यह वास्तव में एक और बग पेश करेगा, जिसे मैं "कोने के मामले" कहता हूं। कोनों के संदर्भ में अनिवार्य रूप से (नीचे की ओर की तरह जहां क्षैतिज स्पाइक्स आपके .gif में बाहर आते हैं, लेकिन अगर स्पाइक्स नहीं थे) तो टकराव का समाधान नहीं होगा, क्योंकि यह सोचेंगे कि आपके द्वारा उत्पन्न कोई भी रिज़ॉल्यूशन एक वैध स्थिति में नहीं जाता है। । इसे हल करने के लिए, बस एक बूल रखें कि क्या टकराव हल हो गया है, साथ ही सभी न्यूनतम प्रवेश प्रस्तावों की एक सूची है। बाद में, यदि टकराव का समाधान नहीं किया गया है, तो आपके द्वारा उत्पन्न किए गए प्रत्येक रिज़ॉल्यूशन पर लूप करें, और अधिकतम एक्स और अधिकतम वाई रिज़ॉल्यूशन पर नज़र रखें (अधिकतम एक ही रिज़ॉल्यूशन से आने की ज़रूरत नहीं है)। फिर उन मैक्सिमम पर टकराव को हल करें। ऐसा लगता है कि आपकी सभी समस्याओं को हल करने के साथ-साथ मैंने जो भी सामना किया है।

    List<Vector2> collisions = new List<Vector2>();
        bool resolved = false;
        foreach (Platform p in testPlat)
        {
            Vector2 dif = p.resolveCollision(player.getCollisionMask());

            RectangleF newPos = player.getCollisionMask();

            newPos.X -= dif.X;
            newPos.Y -= dif.Y;


            if (!PlatformCollision(newPos)) //This checks if there's a collision (ie if we're entering an invalid space)
            {
                if (dif.X != 0)
                    player.velocity.X = 0; //Do whatever you want here, I like to stop my player on collisions
                if (dif.Y != 0)
                    player.velocity.Y = 0;

                player.MoveY(-dif.Y);
                player.MoveX(-dif.X);
                resolved = true;
            }
            collisions.Add(dif);
        }

        if (!resolved)
        {
            Vector2 max = Vector2.Zero;

            foreach (Vector2 v in collisions)
            {
                if (Math.Abs(v.X) > Math.Abs(max.X))
                {
                    max.X = v.X;
                }
                if (Math.Abs(v.Y) > Math.Abs(max.Y))
                {
                    max.Y = v.Y;
                }
            }

            player.MoveY(-max.Y);

            if (max.Y != 0)
                player.velocity.Y = 0;
            player.MoveX(-max.X);

            if (max.X != 0)
                player.velocity.X = 0;
        }

एक और सवाल, क्या स्पाइक्स आप एक टाइल या व्यक्तिगत टाइल दिखाते हैं? यदि वे व्यक्तिगत पतली टाइलें हैं, तो आपको क्षैतिज और ऊर्ध्वाधर लोगों के लिए एक अलग दृष्टिकोण का उपयोग करना पड़ सकता है जो मैं नीचे वर्णित करता हूं। लेकिन अगर वे पूरे टाइल हैं तो यह काम करना चाहिए।


ठीक है, इसलिए मूल रूप से यह @Trevor पॉवेल वर्णन कर रहा था। चूँकि आप केवल AABBs का उपयोग कर रहे हैं, आपको बस इतना करना है कि एक आयत दूसरे में कितना प्रवेश करती है। यह आपको एक्स अक्ष और Y में एक मात्रा देगा। दोनों में से न्यूनतम चुनें, और उस अक्ष के साथ अपनी कॉलिंग ऑब्जेक्ट को ले जाएं। आपको AABB टकराव को हल करने की आवश्यकता है। आपको इस तरह की टक्कर में एक से अधिक धुरी के साथ जाने की आवश्यकता नहीं होगी, इसलिए आपको कभी भी भ्रमित नहीं होना चाहिए कि पहले क्या हिलना है, क्योंकि आप केवल न्यूनतम चाल चलेंगे।

यहाँ एक दृष्टिकोण पर मेटानेट सॉफ्टवेयर का एक क्लासिक ट्यूटोरियल है । यह अन्य आकृतियों में भी जाता है।

यहां एक XNA फ़ंक्शन है जिसे मैंने दो आयतों के ओवरलैप वेक्टर को खोजने के लिए बनाया है:

    public Point resolveCollision(Rectangle otherRect)
    {
        if (!isCollision(otherRect))
        {
            return Point.Zero;
        }

        int minOtherX = otherRect.X;
        int maxOtherX = otherRect.X + otherRect.Width;

        int minMyX = collisionMask.X;
        int maxMyX = collisionMask.X + collisionMask.Width;

        int minOtherY = otherRect.Y;
        int maxOtherY = otherRect.Y + otherRect.Height;

        int minMyY = collisionMask.Y;
        int maxMyY = collisionMask.Y + collisionMask.Height;

        int dx, dy;

        if (maxOtherX - minMyX < maxMyX - minOtherX)
        {
            dx = (maxOtherX - minMyX);
        }
        else
        {
            dx = -(maxMyX - minOtherX);
        }

        if (maxOtherY - minMyY < maxMyY - minOtherY)
        {
            dy = (maxOtherY - minMyY);
        }
        else
        {
            dy = -(maxMyY - minOtherY);
        }

        if (Math.Abs(dx) < Math.Abs(dy))
            return new Point(dx, 0);
        else
            return new Point(0, dy);
    }

(मुझे आशा है कि यह पालन करना आसान है, क्योंकि मुझे यकीन है कि इसे लागू करने के बेहतर तरीके हैं ...)

isCollision (आयत) शाब्दिक XNA के आयत के लिए सिर्फ एक कॉल है। अंतर्देशीय (आयत)।

मैंने इसे चलते प्लेटफार्मों के साथ परीक्षण किया है और यह ठीक काम करने लगता है। मैं यह सुनिश्चित करने के लिए आपके कुछ और अधिक परीक्षण करूँगा।



मुझे लगता है कि पतली प्लेटफॉर्म के साथ काम नहीं करने पर मैंने उस टिप्पणी पर संदेह किया है। मैं एक कारण के बारे में सोच नहीं सकता कि यह क्यों नहीं होगा। यदि आप स्रोत चाहते हैं, तो भी मैं आपके लिए एक XNA प्रोजेक्ट अपलोड कर सकता हूं
Jeff

हाँ, मैं अभी कुछ और परीक्षण कर रहा था और यह दीवार में अटक जाने की आपकी उसी समस्या पर वापस जाता है। ऐसा इसलिए है क्योंकि जहां दो टाइलें एक-दूसरे के साथ पंक्तिबद्ध होती हैं, यह आपको निचले एक के कारण ऊपर जाने के लिए कहती है, और फिर ऊपरी एक के लिए (अपने मामले में) बाहर, प्रभावी रूप से गुरुत्वाकर्षण आंदोलन की उपेक्षा अगर आपका y वेग काफी धीमा है । मुझे इसके लिए एक समाधान पर ध्यान देना होगा, मुझे यह समस्या पहले याद आ रही है।
जेफ

ठीक है, मैं आपकी पहली समस्या के बारे में जानने के लिए एक बहुत ही आसान तरीका लेकर आया हूं। समाधान में प्रत्येक एएबीबी के लिए न्यूनतम पैठ ढूंढना शामिल है, केवल सबसे बड़े एक्स के साथ एक पर हल करना, फिर सबसे बड़े वाई पर केवल एक दूसरा पास हल करना। यह तब बुरा लगता है जब आपको कुचल दिया जा रहा हो, लेकिन काम लिफ्ट करता है और आपको धक्का दिया जा सकता है क्षैतिज रूप से, और आपकी मूल चिपकी हुई समस्या दूर हो गई है। यह हैकेय है, और मुझे नहीं पता कि यह अन्य आकारों में कैसे अनुवाद करेगा। एक और संभावना है कि छूने वाले ज्यामितीयों को वेल्ड किया जा सकता है, लेकिन मैंने यह भी प्रयास नहीं किया है कि
जेफ

दीवारें 16x16 टाइलों से बनी हैं। स्पाइक्स एक 16x16 टाइल है। यदि मैं न्यूनतम अक्ष पर हल करता हूं, तो जंपिंग बग होता है (आरेख को देखें)। .Gif में दिखाए गए स्थिति के साथ क्या आपका "बेहद हैकिया" समाधान काम करेगा?
विटोरियो रोमियो

हां, मेरा काम करता है। आपके चरित्र का आकार क्या है?
जेफ

1

यह आसान है।

स्पाइक्स को फिर से लिखें। यह स्पाइक्स की गलती है।

आपकी टक्कर असतत, मूर्त इकाइयों में होनी चाहिए। जहाँ तक समस्या है, मैं देख सकता हूँ:

1. Player is outside spikes
2. Spikes move into intersection position with the player
3. Player resolves incorrectly

समस्या चरण 2 के साथ है, 3 नहीं !!

यदि आप चीजों को ठोस महसूस करने की कोशिश कर रहे हैं, तो आपको वस्तुओं को एक दूसरे की तरह स्लाइड नहीं करने देना चाहिए। एक बार जब आप चौराहे की स्थिति में होते हैं, यदि आप अपना स्थान खो देते हैं, तो समस्या को हल करना कठिन हो जाता है।

खिलाड़ी के अस्तित्व के लिए स्पाइक्स को आदर्श रूप से जांचना चाहिए और जब वे चलते हैं, तो उन्हें आवश्यक रूप से धक्का देना चाहिए ।

इसे प्राप्त करने का एक आसान तरीका प्लेयर के लिए है moveXऔर ऐसे moveYकार्य हैं जो परिदृश्य को समझते हैं और एक निश्चित डेल्टा द्वारा खिलाड़ी को दूर कर देंगे या जहां तक ​​वे बिना किसी बाधा को मार सकते हैं

आम तौर पर उन्हें इवेंट लूप द्वारा बुलाया जाएगा। हालांकि उन्हें खिलाड़ी को पुश करने के लिए वस्तुओं द्वारा भी बुलाया जा सकता है।

function spikes going up:

    move spikes up

    if intersecting player:
        d = player bottom edge + spikes top edge

        player.moveY(-d)
    end if

end function

जाहिर है खिलाड़ी को अभी भी स्पाइक्स पर प्रतिक्रिया करने की आवश्यकता है यदि वह उन में जाता है

ओवररचिंग नियम है, किसी भी वस्तु के हिलने के बाद, यह बिना चौराहे की स्थिति में समाप्त होना चाहिए। इस तरह, आपके द्वारा देखे जा रहे ग्लिच को प्राप्त करना असंभव है।


चरम मामले में जहां moveYचौराहे को हटाने में विफल रहता है (क्योंकि एक और दीवार रास्ते में है) आप चौराहे के लिए फिर से जांच कर सकते हैं और या तो चाल x या बस उसे मारने की कोशिश कर सकते हैं।
क्रिस बर्ट-ब्राउन
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.