এন অবজেক্টের সিস্টেমের সংঘর্ষের চেক দক্ষতা বাড়ানোর কোনও উপায় আছে কি?


9

আমি এমন একটি গেম তৈরি করছি যা অনেকগুলি অনস্ক্রিন অবজেক্ট নিয়ে গঠিত, যার মধ্যে একটি খেলোয়াড়। আমার জানা দরকার যে প্রতিটি উপাদানগুলিতে প্রতিটি পুনরাবৃত্তির সাথে সংঘর্ষ হয়।

আমি এরকম কিছু তৈরি করেছি:

for (o in objects)
{
   o.stuff();
   for (other in objects)
      if (collision(o, other))
          doStuff();

   bla.draw();
}

এটিতে ও (এন ^ 2) রয়েছে, যা আমাকে বলা খারাপ। আমি কীভাবে এটি আরও দক্ষতার সাথে করব, এটি কি সম্ভব? আমি এটি জাভাস্ক্রিপ্টে করছি, এবং এন সাধারণত 30 এর চেয়ে কম হবে, এটি যদি একই থাকে তবে কি সমস্যা হবে?


3
কোডটি কীভাবে সম্পাদন করে তা দেখার জন্য আপনি কি চেষ্টা চালিয়েছেন?
thedaian

না, আমার কাছে নেই, আমি ও এর কারণে এটি খারাপ বলে মনে করছি (এন ^ 2)।
jcora

1
শুধুমাত্র 30 টি জিনিস? আমি স্থানিক পার্টিশন করার পরামর্শ দিয়েছি তবে এটি কেবল 30 টি বস্তু দিয়ে ফলহীন হবে। কিছু ছোট্ট অপ্টিমাইজেশন রয়েছে যা অন্যরা উল্লেখ করেছে, তবে আপনি যে স্কেলটির বিষয়ে কথা বলছেন সেগুলি হ'ল এগুলি সমস্ত অপ্রয়োজনীয়।
জন ম্যাকডোনাল্ড

উত্তর:


16

সর্বোচ্চ ৩০ টি অবজেক্টের সাথে, ফ্রেমের প্রতি একাধিকবার একে অপরের বিরুদ্ধে একই দুটি জোড়া যাচাই না করা ছাড়া আপনার অন্য কোনওটিতে খুব বেশি অপ্টিমাইজেশনের প্রয়োজন হবে না। যা নীচের কোড নমুনা কভার করবে। তবে যদি আপনি বিভিন্ন অপ্টিমাইজেশনে আকর্ষণীয় হন যা কোনও পদার্থ বিজ্ঞান ইঞ্জিন ব্যবহার করবে তবে এই পোস্টের বাকি অংশে পড়া চালিয়ে যান।

আপনার যা প্রয়োজন তা হ'ল একটি স্থানিক বিভাজন বাস্তবায়ন, যেমন অক্ট্রি (3 ডি গেমসের জন্য) বা কোয়াড্ট্রি (2 ডি গেমসের জন্য)। এইগুলি বিশ্বকে উপ-বিভাগে বিভক্ত করে, এবং তারপরে প্রতিটি উপ-বিভাগকে আরও একই অংশে ভাগ করা হয় যতক্ষণ না তারা একটি সর্বনিম্ন আকারে বিভক্ত হয়। এটি আপনাকে খুব তাড়াতাড়ি যাচাই করতে দেয় যে পৃথিবীর একই অঞ্চলে অন্য কোন অবজেক্টগুলি অন্য হিসাবে রয়েছে, যা আপনাকে যে ধরণের সংঘর্ষের বিরুদ্ধে পরীক্ষা করতে হবে তা সীমাবদ্ধ করে।

স্থানিক বিভাজন ছাড়াও আমি আপনার প্রতিটি পদার্থবিজ্ঞানের বস্তুর জন্য একটি এএবিবি ( অক্ষ- প্রান্তযুক্ত বাউন্ডিং বাক্স ) তৈরি করার পরামর্শ দেব । এটি আপনাকে অন্য একটি সামগ্রীর AABB চেক করতে দেয়, যা বস্তুর মধ্যে বিশদ প্রতি পলি চেকের চেয়ে অনেক দ্রুত is

জটিল বা বড় পদার্থবিজ্ঞানের জন্য এটি আরও একটি পদক্ষেপ নেওয়া যেতে পারে, যেখানে আপনি পদার্থবিজ্ঞানের জাল নিজেই উপ-বিভক্ত করতে পারেন, প্রতিটি উপ-আকারকে তার নিজস্ব এএবিবি দেয় যা আপনি কেবল দুটি বস্তুর এএবিবি ওভারল্যাপিং করলেই তার বিরুদ্ধে পরীক্ষা করতে পারেন।

বেশিরভাগ পদার্থবিজ্ঞানের ইঞ্জিনগুলি বিশ্রামে আসার পরে পদার্থবিদ্যার সংস্থাগুলিতে সক্রিয় পদার্থবিজ্ঞানের সিমুলেশন নিষ্ক্রিয় করবে। যখন পদার্থবিদ্যার বডিটি নিষ্ক্রিয় করা হয়, তখন প্রতিটি ফ্রেমের জন্য এটির কেবলমাত্র এএএবিবির সাথে সংঘর্ষের জন্য পরীক্ষা করা প্রয়োজন এবং যদি এএবিবির সাথে কোনও সংঘর্ষ ঘটে তবে তা আবার সক্রিয় হবে এবং আরও দানাদার সংঘর্ষের চেক করবে। এটি সিমুলেশন বার ডাউন রাখে।

এছাড়াও, অনেক পদার্থবিজ্ঞানের ইঞ্জিনগুলি 'সিমুলেশন দ্বীপপুঞ্জ' ব্যবহার করে, যেখানে পদার্থবিদ্যার সংস্থাগুলির একটি গ্রুপ একত্রে একত্রে একত্রিত হয়। সিমুলেশন দ্বীপের সবকিছু যদি বিশ্রামে থাকে তবে সিমুলেশন দ্বীপ নিজেই ডিএ্যাকটিভস। সিমুলেশন দ্বীপের সুবিধা হ'ল একবার দ্বীপটি নিষ্ক্রিয় হয়ে যাওয়ার পরে এর অভ্যন্তরের সমস্ত দেহ সংঘর্ষের জন্য চেক করা বন্ধ করতে পারে এবং প্রতিটি ফ্রেমের একমাত্র চেকটি দ্বীপের এএবিবিতে প্রবেশ করেছে কিনা তা দেখতে হবে। কেবল একবার দ্বীপের এএবিবিতে প্রবেশ করার পরে দ্বীপের প্রতিটি দেহের সংঘর্ষের জন্য পরীক্ষা করা দরকার। সিমুলেশন দ্বীপটি আবার সক্রিয় হয় যদি এর ভিতরে কোনও দেহ নিজে থেকে আবার চলা শুরু করে। গ্রুপের কেন্দ্র থেকে যদি কোনও দেহ যথেষ্ট পরিমাণে সরে যায় তবে এটি দ্বীপ থেকে সরানো হবে।

শেষ অবধি আপনি এই জাতীয় কিছু রেখেছেন (সিউডো-কোডে):

// Go through each leaf node in the octree. This could be more efficient
// by keeping a list of leaf nodes with objects in it.
for ( node in octreeLeafNodes )
{
    // We only need to check for collision if more than one object
    // or island is in the bounds of this octree node.
    if ( node.numAABBsInBounds > 1)
    {
        for ( int i = 0; i < AABBNodes.size(); ++i )
        {
           // Using i+1 here allows us to skip duplicate checks between AABBS
           // e.g (If there are 5 bodies, and i = 0, we only check i against
           //      indexes 1,2,3,4. Once i = 1, we only check i against indexes
           //      2,3,4)
           for ( int j = i + 1; j < AABBNodes.size(); ++j )
           {
               if ( AABBOverlaps( AABBNodes[i], AABBNodes[j] ) )
               {
                   // If the AABB we checked against was a simulation island
                   // then we now check against the nodes in the simulation island

                   // Once you find overlaps between two actual object AABBs
                   // you can now check sub-nodes with each object, if you went
                   // that far in optimizing physics meshes.
               {
           }
        }
    }
}

আমি এটির মতো লুপগুলির মধ্যে এতগুলি লুপ না রাখারও সুপারিশ করব, উপরের নমুনাটি ঠিক আপনি ধারণাগুলি পেয়েছিলেন, আমি এটিকে একাধিক ফাংশনে বিভক্ত করব যা আপনাকে উপরের চিত্রের মতো কিছু কার্যকারিতা দেয়।

এছাড়াও, নিশ্চিত হয়ে নিন যে এএবিবিএনডস কনটেইনারটি লুপ করার সময় এটি পরিবর্তন করবেন না, কারণ এর অর্থ মিসড সংঘর্ষের চেকগুলি হতে পারে। এটি সাধারণ জ্ঞানের মতো শোনাতে পারে তবে আপনি অবাক হবেন যে সংঘর্ষে প্রতিক্রিয়াযুক্ত জিনিসগুলি আপনি যেটি প্রত্যাশা করেননি এমন কারণগুলির প্রতিক্রিয়া দেখানো কত সহজ। উদাহরণস্বরূপ, যদি কোনও সংঘর্ষের কারণে কোনও সংঘর্ষকারী বস্তুর কোনও একটিকে তার অবস্থান পরিবর্তন করতে পর্যাপ্ত অবস্থান পরিবর্তন করতে পারে যার দ্বারা আপনি যাচাই করছেন reeত্রী নোডের এএবিবি থেকে সরিয়ে ফেলা যায় তবে এটি সেই ধারকটিকে পরিবর্তন করতে পারে। এটি সমাধানের জন্য আমি চেক চলাকালীন ঘটে যাওয়া সমস্ত সংঘর্ষের ইভেন্টগুলির একটি তালিকা রাখার পরামর্শ দিচ্ছি এবং তারপরে সমস্ত চেক তালিকাটির মাধ্যমে পুরোপুরি চালানো হবে এবং কোনও সংঘর্ষের ঘটনা প্রেরণ করব।


4
বিদ্যমান পদ্ধতিগুলিতে পাঠকের মন খুলতে সুন্দর এবং দরকারী প্রযুক্তিগত নির্ভুলতার সাথে খুব সামঞ্জস্যপূর্ণ উত্তর। +1
ভালকিয়া

আমার যদি সংঘর্ষক বস্তুটি সরানোর দরকার হয় তবে কী হবে? আমি কি পাত্রে পরিবর্তন করতে পারি? আমার অর্থ এটি পাত্রে থেকে অপসারণ করা কারণ আমার আর জিনিসটির দরকার নেই কারণ এটি "ধ্বংস" হয়েছে। সংঘর্ষ শনাক্ত করার সময় আমি যদি এটি অপসারণ না করি তবে সংঘর্ষের ঘটনাগুলি চালানোর জন্য আমার আরও একটি লুপ প্রয়োজন।
newguy

সংঘর্ষকৃত বস্তুটি সরিয়ে ফেলা ঠিক আছে তবে সংঘর্ষের পাসটি পুরো সিমুলেশনটি তৈরি না হওয়া পর্যন্ত এটি করার জন্য আমি অপেক্ষা করব। সাধারণত আপনি সরিয়ে ফেলতে হবে এমন অবজেক্টগুলিকে কেবল পতাকাঙ্কিত করুন বা অপসারণের জন্য বস্তুর একটি তালিকা তৈরি করুন এবং তার পরে সংঘর্ষের সিমুলেশন সম্পন্ন হওয়ার পরে আপনি এই পরিবর্তনগুলি প্রয়োগ করেন।
নিক ফস্টার

4

আপনার উদাহরণ প্রতিটি জোড়া বস্তুর একাধিকবার পরীক্ষা করে।

আসুন 0,1,2,3 সমন্বিত একটি অ্যারের সাথে একটি খুব সাধারণ উদাহরণটি গ্রহণ করি

আপনার কোড সহ আপনি এটি পান:

  • লুপ 0 এ আপনি 1, 2 এবং 3 এর বিপরীতে পরীক্ষা করেন
  • লুপ 1 এ আপনি 0, 2 এবং 3 ===> এর বিপরীতে পরীক্ষা করেন (0-1 ইতিমধ্যে পরীক্ষিত)
  • লুপ 2 এ আপনি 0, 1 এবং 3 ===> এর বিপরীতে পরীক্ষা করেন (0-2 / 1-2 ইতিমধ্যে পরীক্ষিত)
  • লুপ 3 এ আপনি 0, 1 এবং 2 ===> এর বিপরীতে পরীক্ষা করেন (0-3 / 1-3 / 2-3 ইতিমধ্যে পরীক্ষিত)

এখন নিম্নলিখিত কোডটি দেখতে দিন:

for(i=0;i<=objects.length;i++)
{
    objects[i].stuff();

    for(j=i+1;j<=objects.length;j++)
    {
        if (collision(objects[i], objects[j]))
        doStuff();
    }

    bla.draw();
}

আমরা যদি আবার 0,1,2,3 সমন্বিত অ্যারে ব্যবহার করি তবে আমাদের নিম্নলিখিত আচরণগুলি হবে:

  • লুপ 0 এ আপনি 1, 2, 3 এর বিপরীতে পরীক্ষা করেন
  • লুপ 1 এ আপনি 2, 3 এর বিপরীতে পরীক্ষা করেন
  • লুপ 2 এ আপনি 3 এর বিপরীতে পরীক্ষা করেন
  • লুপ 3 এ আপনি কোনও কিছুর বিরুদ্ধে পরীক্ষা করেন না

দ্বিতীয় অ্যালগরিদমের সাথে আমরা 6 টি সংঘর্ষের পরীক্ষা পেয়েছি যখন আগেরটি 12 টি সংঘর্ষের পরীক্ষা চেয়েছিল।


এই অ্যালগরিদম N(N-1)/2তুলনা করে যা এখনও ও (N ^ 2) এর পারফরম্যান্স।
কাই

1
অনুরোধ হিসাবে 30 টি অবজেক্টের সাথে এর মানে হল 870 এর বিপরীতে 465 সংঘর্ষের পরীক্ষা করা ... এটি সম্ভবত আপনার দৃষ্টিকোণ থেকে অনুরূপ তবে আমার নয়। তদ্ব্যতীত, অন্য উত্তরে প্রদত্ত সমাধানটি হুবহু একই অ্যালগরিদম :)
ভলকিয়া

1
@ ভালকিয়া: আচ্ছা, এর কিছু অংশ। :)
নিক ফস্টার

@ নিকফোস্টার: হ্যাঁ আপনি ঠিক বলেছেন;) আমি নির্বাচিত বস্তুর মধ্যে সংঘর্ষের পরীক্ষা সম্পর্কে কঠোরভাবে বলছিলাম, অ্যালগরিদমের বিভাজনকারী অংশ সম্পর্কে যা স্পষ্টতই খুব মূল্যবান সংযোজন যা আমি আমার উদাহরণে যুক্ত করার চিন্তাও করি নি আমি এটা লিখছিলাম।
ভালকিয়া

এটাকে কি এমোরিটাইজেশন বলা হয়? যাইহোক ধন্যবাদ!
jcora

3

আপনার প্রয়োজনের আশেপাশে আপনার অ্যালগরিদম ডিজাইন করুন, তবে বাস্তবায়ন বিশদটি আবদ্ধ রাখুন। এমনকি জাভাস্ক্রিপ্টে, বেসিক ওওপি ধারণা প্রয়োগ হয়।

কারণ N =~ 30, O(N*N)কোনও উদ্বেগের বিষয় নয় এবং আপনার রৈখিক অনুসন্ধান সম্ভবত অন্য যে কোনও বিকল্প হিসাবে তত দ্রুত হতে পারে। তবে আপনি আপনার কোডটিতে হার্ড-কোড অনুমানগুলি করতে চান না। সিউডোকোডে আপনার একটি ইন্টারফেস থাকবে

interface itemContainer { 
    add(BoundingBox);
    remove(BoundingBox);
    BoundingBox[] getIntersections();
}

এটি আপনার তালিকা-এর আইটেমগুলি কী করতে পারে তা বর্ণনা করে। তারপরে আপনি একটি অ্যারেকন্টেইনার ক্লাস লিখতে পারেন যা এই ইন্টারফেসটি প্রয়োগ করে। জাভাস্ক্রিপ্টে কোডটি দেখতে এমন হবে:

function ArrayContainer() { ... } // this uses an array to store my objects
ArrayContainer.prototype.add = function(box) { ... };
ArrayContainer.prototype.remove = function(box) { ... };
ArrayContainer.prototype.getIntersections = function() { ... };

function QuadTreeContainer { ... } // this uses a quadtree to store my objects
... and implement in the add/remove/getIntersections for QuadTreeContainer too

এবং এখানে উদাহরণ কোড যা 300 বাউন্ডিং বাক্স তৈরি করে এবং সমস্ত ছেদগুলি পেয়েছে। আপনি ArrayContainer এবং QuadTreeContainer সঠিকভাবে বাস্তবায়িত করে থাকেন, তবে একমাত্র জিনিস আপনি আপনার কোড পরিবর্তন করতে হবে পরিবর্তন var allMyObjects = new ArrayContainer()করতে var allMyObjects = QuadTreeContainer()

var r = Math.random;
var allMyObjects = new ArrayContainer();
for(var i=0; i<300; i++)
    allMyObjects.add(new BoundingBox(r(), r()));
var intersections = allMyObjects.getIntersections();

আমি এগিয়ে গিয়েছিলাম এবং এখানে স্ট্যান্ডার্ড অ্যারে কন্টেইনারটির জন্য বাস্তবায়নটি ছাপিয়েছি:

http://jsfiddle.net/SKkN5/1/


দ্রষ্টব্য: এই উত্তরটি বানের অভিযোগ দ্বারা অনুপ্রাণিত হয়েছিল যে তার কোডবেস খুব বড়, অগোছালো এবং পরিচালনা করা শক্ত হয়ে উঠছে। যদিও এটি অ্যারে বনাম একটি গাছ ব্যবহারের আলোচনায় খুব বেশি যোগ না করে, আমি আশা করি যে এটি কীভাবে নির্দিষ্টভাবে তার কোডটি আরও ভালভাবে পরিচালনা করতে পারে সে সম্পর্কে এটি একটি প্রাসঙ্গিক উত্তর।
জিমি

2

সংবেদনশীলভাবে সংঘর্ষের তুলনায় আপনার বস্তুর প্রকারগুলিও বিবেচনা করা উচিত।

উদাহরণস্বরূপ, খেলোয়াড়কে সম্ভবত তার নিজের বুলেট ছাড়া সমস্ত কিছুর সাথে সংঘর্ষের জন্য পরীক্ষা করা দরকার। তবে শত্রুদের কেবল প্লেয়ার বুলেটগুলির বিরুদ্ধে পরীক্ষা করা প্রয়োজন। বুলেটগুলি অবশ্যই একে অপরের সাথে সংঘর্ষের প্রয়োজন হয় না।

এটিকে দক্ষতার সাথে বাস্তবায়িত করার জন্য আপনি অবজেক্টের জন্য পৃথক অবজেক্টের আলাদা তালিকা রাখতে চান।

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.