অর্ডারটি তাত্পর্যপূর্ণ এবং সংঘর্ষটি অবজেক্ট গ্রুপের ভিত্তিতে শর্তযুক্ত যেখানে আমি কোনও সংঘর্ষ ইঞ্জিনকে কীভাবে অনুকূল করতে পারি?


14

যদি এই প্রশ্নে এটি আপনার প্রথমবার হয় তবে আমি প্রথমে নীচের প্রাক-আপডেট অংশটি পড়ার পরামর্শ দিচ্ছি, তারপরে এই অংশটি। সমস্যাটির সংশ্লেষণটি এখানে, যদিও:

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


আপডেট: আমি এটিতে সত্যিই কঠোর পরিশ্রম করেছি, তবে কিছুই অপ্টিমাইজ করার ব্যবস্থা করতে পারিনি।

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

আমি একটি বড় সমস্যাও আবিষ্কার করেছি : আমার ইঞ্জিনটি ক্রম-সংঘর্ষের উপর নির্ভরশীল।

আমি অনন্য সংঘর্ষের জুড়ি প্রজন্মের একটি বাস্তবায়নের চেষ্টা করেছি , যা স্পষ্টতই অনেক কিছু দিয়ে সমস্ত গতি বাড়িয়েছিল, তবে সংঘর্ষের অর্ডারকে ভেঙেছে ।

আমাকে ব্যাখ্যা করতে দাও:

  • আমার আসল নকশায় (জোড় তৈরি হচ্ছে না), এটি ঘটে:

    1. একটি শরীরের নড়াচড়া
    2. এটি সরানোর পরে, এটি তার কোষগুলিকে সতেজ করে এবং এতে যে দেহগুলির মুখোমুখি হয় সেগুলি তা পায়
    3. যদি এটি কোনও শরীরে ওভারল্যাপ করে তবে তার বিপরীতে সমাধান করা দরকার, সংঘর্ষের সমাধান করুন

    এর অর্থ হ'ল যদি কোনও দেহ সরে যায় এবং একটি প্রাচীরের (বা অন্য কোনও দেহ) আঘাত করে তবে কেবল যে দেহটি স্থানান্তরিত হয়েছে তা তার সংঘর্ষের সমাধান করবে এবং অন্য দেহটি ক্ষতিগ্রস্থ হবে না।

    এটিই আমার আচরণের ইচ্ছা

    আমি বুঝতে পারি এটি পদার্থবিজ্ঞানের ইঞ্জিনগুলির পক্ষে সাধারণ নয়, তবে রেট্রো স্টাইলের গেমগুলির জন্য এর অনেক সুবিধা রয়েছে ।

  • সাধারণ গ্রিড ডিজাইনে (স্বতন্ত্র জোড় তৈরি করে) এটি ঘটে:

    1. সমস্ত দেহ সরানো
    2. সমস্ত দেহ সরে যাওয়ার পরে, সমস্ত কক্ষকে রিফ্রেশ করুন
    3. অনন্য সংঘর্ষের জোড়া উত্পাদন
    4. প্রতিটি জোড়া জন্য, সংঘর্ষ সনাক্তকরণ এবং রেজোলিউশন হ্যান্ডেল

    এই ক্ষেত্রে একযোগে পদক্ষেপের ফলে দুটি দেহ ওভারল্যাপিং হতে পারে, এবং তারা একই সাথে সমাধান করবে - এটি কার্যকরভাবে দেহগুলিকে "একে অপরকে চারপাশে ঠেলে" তোলে এবং একাধিক সংস্থার সাথে সংঘর্ষের স্থায়িত্বকে ভেঙে দেয়

    এই আচরণটি পদার্থবিজ্ঞানের ইঞ্জিনগুলির জন্য সাধারণ, তবে এটি আমার ক্ষেত্রে গ্রহণযোগ্য নয়

আমি আরও একটি সমস্যা পেয়েছি, যা প্রধান (যদিও এটি বাস্তব-বিশ্বের পরিস্থিতিতে হওয়ার সম্ভাবনা না থাকলেও):

  • A, B এবং W গ্রুপের সংস্থাগুলি বিবেচনা করুন
  • একটি সংঘর্ষে ডাব্লু এবং এ এর ​​বিপরীতে সমাধান হয়
  • বি সংঘর্ষে ডব্লিউ এবং বি এর বিপরীতে সমাধান করে
  • এ বি এর বিরুদ্ধে কিছুই করে না
  • খ ক এর বিপরীতে কিছুই করে না

এমন পরিস্থিতি তৈরি হতে পারে যেখানে প্রচুর এ সংস্থা এবং বি সংস্থা একই কোষ দখল করে থাকে - সেক্ষেত্রে মৃতদেহের মধ্যে প্রচুর অপ্রয়োজনীয় পুনরাবৃত্তি ঘটে যা একে অপরের সাথে প্রতিক্রিয়া প্রকাশ করে না (বা কেবল সংঘর্ষ সনাক্ত করে তবে সেগুলি সমাধান করে না) ।

একই কক্ষটি দখল করা 100 টি মৃতদেহের জন্য, এটি 100 ^ 100 পুনরাবৃত্তি! এটি ঘটে কারণ অনন্য যুগগুলি উত্পন্ন হচ্ছে না - তবে আমি অনন্য জোড়া তৈরি করতে পারি না , অন্যথায় আমি এমন আচরণ পেতে চাই যা আমি চাই না।

এই ধরণের সংঘর্ষ ইঞ্জিনকে অনুকূল করার কোনও উপায় আছে কি?

এই নির্দেশাবলী যে সম্মান করা আবশ্যক:

  • সংঘর্ষের ক্রমটি অত্যন্ত গুরুত্বপূর্ণ!

    • দেহগুলিকে অবশ্যই একবারে একটি স্থানান্তরিত করতে হবে , তারপরে একবারে সংঘর্ষের জন্য পরীক্ষা করতে হবে এবং একবারে আন্দোলনের পরে সমাধান করতে হবে
  • দেহগুলিতে 3 টি গ্রুপ বিটসেট থাকতে হবে

    • গোষ্ঠী : দলগুলি শরীরের অন্তর্ভুক্ত
    • গ্রুপসটেক : শরীরের বিরুদ্ধে গ্রুপের সংঘর্ষ সনাক্ত করতে হবে groups
    • গোষ্ঠী নো রিসলভ : গ্রুপের সাথে শরীরের সংঘর্ষের সমাধান করা উচিত নয়
    • এমন পরিস্থিতি থাকতে পারে যেখানে আমি কেবল একটি সংঘর্ষ সনাক্ত করতে পারি তবে সমাধান হয় নি



প্রি-আপডেট:

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


আমি নমনীয়তা এবং গতির উপর জোর দিয়ে একটি সাধারণ-উদ্দেশ্য সি ++ 2 ডি সংঘর্ষ সনাক্তকরণ / প্রতিক্রিয়া ইঞ্জিন তৈরি করছি।

এখানে এর স্থাপত্যের একটি খুব প্রাথমিক চিত্র রয়েছে:

বেসিক ইঞ্জিন আর্কিটেকচার

মূলত, প্রধান শ্রেণিটি হ'ল World, যা ক ResolverBase*, ক SpatialBase*এবং ক এর মেমরি পরিচালনা করে vector<Body*>

SpatialBase একটি খাঁটি ভার্চুয়াল ক্লাস যা ব্রড-ফেজ সংঘর্ষ সনাক্তকরণের সাথে সম্পর্কিত deals

ResolverBase একটি খাঁটি ভার্চুয়াল ক্লাস যা সংঘর্ষের রেজোলিউশনের কাজ করে।

দেহগুলি বস্তুগুলির World::SpatialBase*সাথে যোগাযোগ SpatialInfoকরে, দেহগুলির নিজস্ব মালিকানা।


সেখানে কৌতূহলীভাবে একটি স্থানিক শ্রেণি রয়েছে: Grid : SpatialBaseএটি একটি বেসিক ফিক্সড 2 ডি গ্রিড। এটির নিজস্ব তথ্য বর্গ রয়েছে GridInfo : SpatialInfo,।

এটির স্থাপত্যটি কীভাবে দেখায় তা এখানে:

গ্রিড স্থানিক সহ ইঞ্জিন আর্কিটেকচার

Gridবর্গ একটি 2D অ্যারে মালিক Cell*Cellবর্গ একটি সংগ্রহ (মালিকানাধীন নয়) রয়েছে Body*: একটি vector<Body*>যা সব মৃতদেহ যে কক্ষে রয়েছে।

GridInfo বস্তুগুলির মধ্যে দেহটি যে কোষে থাকে সেগুলিতে অ-মালিকানাধীন পয়েন্টারও থাকে।


আমি আগেই বলেছি, ইঞ্জিনগুলি গ্রুপগুলির উপর ভিত্তি করে।

  • Body::getGroups()একটি ফেরৎ std::bitsetসকল গোষ্ঠী শরীরের অংশ।
  • Body::getGroupsToCheck()std::bitsetশরীরের সাথে সংঘর্ষের জন্য চেক করতে থাকা সমস্ত গ্রুপের একটি ফেরত দেয় ।

দেহগুলি একক কোষের চেয়ে বেশি দখল করতে পারে। গ্রিডআইনফো সর্বদা দখলকৃত কক্ষগুলিতে অ-মালিকানার পয়েন্টার সঞ্চয় করে।


একটি একক শরীরের সরানোর পরে, সংঘর্ষ সনাক্তকরণ ঘটে। আমি ধরে নিলাম যে সমস্ত সংস্থা অক্ষ-সংযুক্ত বাউন্ডিং বাক্স।

ব্রড-ফেজ সংঘর্ষ সনাক্তকরণ কীভাবে কাজ করে:

পর্ব 1: স্থানিক তথ্য আপডেট

প্রত্যেকের জন্য Body body:

    • শীর্ষ-বামদিকের অধিষ্ঠিত ঘর এবং নীচে-ডানদিকের অধিষ্ঠিত ঘরগুলি গণনা করা হয়।
    • যদি সেগুলি পূর্ববর্তী কোষগুলির থেকে পৃথক হয়, body.gridInfo.cellsপরিষ্কার হয়ে যায় এবং দেহটি দখল করে এমন সমস্ত কোষে পূর্ণ হয় (উপরের-বামতম কোষ থেকে নীচে-ডানদিকের কোষে লুপের জন্য 2 ডি)।
  1. body এটি কোষগুলি কী দখল করে তা এখন নিশ্চিতভাবে গ্যারান্টিযুক্ত।

পার্ট 2: প্রকৃত সংঘর্ষের চেক

প্রত্যেকের জন্য Body body:

  • body.gridInfo.handleCollisions বলা হয়:

void GridInfo::handleCollisions(float mFrameTime)
{
    static int paint{-1};
    ++paint;

    for(const auto& c : cells)
        for(const auto& b : c->getBodies())
        {
            if(b->paint == paint) continue;
            base.handleCollision(mFrameTime, b);
            b->paint = paint;
        }
}

void Body::handleCollision(float mFrameTime, Body* mBody)
    {
        if(mBody == this || !mustCheck(*mBody) || !shape.isOverlapping(mBody->getShape())) return;

        auto intersection(getMinIntersection(shape, mBody->getShape()));

        onDetection({*mBody, mFrameTime, mBody->getUserData(), intersection});
        mBody->onDetection({*this, mFrameTime, userData, -intersection});

        if(!resolve || mustIgnoreResolution(*mBody)) return;
        bodiesToResolve.push_back(mBody);
    }

  • সংঘর্ষের পরে প্রতিটি শরীরের জন্য সমাধান করা হয় bodiesToResolve

  • এটাই.


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

আমার প্রশ্ন: আমি কীভাবে আমার সংঘর্ষের ইঞ্জিনের ব্রড-ফেজটি অনুকূল করতে পারি ?

এখানে কি কোনও ধরণের ম্যাজিক সি ++ অপ্টিমাইজেশন প্রয়োগ করা যেতে পারে?

আরও পারফরম্যান্সের অনুমতি দেওয়ার জন্য কি আর্কিটেকচারটি আবার ডিজাইন করা যেতে পারে?


সর্বশেষ সংস্করণটির জন্য কলগ্রিনড আউটপুট: http://txtup.co/rLJgz


প্রোফাইল এবং বাধা সনাক্ত করুন। আসুন তারা কোথায় আছেন তা আমাদের জানান, তারপরে আমাদের কাজ করার কিছু আছে।
মাইক সেমদার

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

দুঃখিত, খুঁজে পাওয়া কঠিন ছিল। আপনি আমাদের কিছু নম্বর দিতে পারেন? সেই ফাংশনে প্রক্রিয়াজাত ফাংশনের সময় এবং সংখ্যার সংখ্যা?
মাইক সেমদার

@ মাইকসেমদার: কলগার্ডের সাথে পরীক্ষিত, ব্লেয়ারে ক্লং ৩.৪ এসভিএন -৩৩: ১০০০০০ গতিশীল সংস্থার সমন্বিত একটি বাইনারি - ফাংশনটি getBodiesToCheck()6৪6২৩৩৩ বার বলা হয়েছিল এবং পুরো প্রোফাইলিংয়ের 35,1% সময় নিয়েছিল (নির্দেশ পাঠের জন্য অ্যাক্সেসের সময়)
ভিটোরিও রোমিও

2
@ কিউনাক্স: কোনও অপরাধ নেওয়া হয়নি। আমি শুধু ভালবাসা "চাকা reinventing"। আমি বুলেট বা বক্স 2 ডি নিতে পারি এবং সেই লাইব্রেরিগুলির সাথে একটি গেম তৈরি করতে পারি, তবে এটি আসলে আমার লক্ষ্য নয়। আমি স্ক্র্যাচ থেকে জিনিসগুলি তৈরি করে এবং উপস্থিত বাধাগুলি কাটিয়ে উঠার চেষ্টা করে আরও অনেক কিছু শিখি - যদিও এর অর্থ হতাশ হওয়া এবং সহায়তা চাইতে। আমার বিশ্বাস ছাড়া যে স্ক্র্যাচ থেকে কোডিং শেখার উদ্দেশ্যে অমূল্য, আমি এটিকে অনেক মজাদার এবং আমার অবসর সময় ব্যয় করে একটি দুর্দান্ত আনন্দও বোধ করি।
ভিটোরিও রোমিও

উত্তর:


14

getBodiesToCheck()

ফাংশনটিতে দুটি সমস্যা হতে পারে getBodiesToCheck(); প্রথম:

if(!contains(bodiesToCheck, b)) bodiesToCheck.push_back(b);

এই অংশটি ও (এন 2 ) তাই না?

দেহটি ইতিমধ্যে তালিকায় রয়েছে কিনা তা পরীক্ষা করে দেখার পরিবর্তে চিত্রকর্মটি ব্যবহার করুন।

loop_count++;
if(!loop_count) { // if loop_count can wrap,
    // you just need to iterate all bodies to reset it here
}
bodiesToCheck.clear();
for(const auto& q : queries)
    for(const auto& b : *q)
        if(b->paint != loop_count) {
            bodiesToCheck.push_back(b);
            b->paint = loop_count;
        }
return bodiesToCheck;

আপনি জমায়েত পর্যায়ে পয়েন্টারটিকে ডিফারেন্স করছেন, তবে আপনি পরীক্ষা পর্বে যে কোনও উপায়ে এটি ডিফারেন্স করে যাচ্ছেন তাই আপনার যদি যথেষ্ট পরিমাণে এল 1 থাকে তবে এটি কোনও বড় বিষয় নয়। আপনি উদাহরণস্বরূপ সংকলকটিতে প্রাক-আনার ইঙ্গিতগুলি যুক্ত করে কর্মক্ষমতা উন্নত করতে পারেন __builtin_prefetch, যদিও এটি ক্লাসিক for(int i=q->length; i-->0; )লুপগুলি এবং এ জাতীয়গুলির সাথে সহজ with

এটি একটি সহজ ঝাঁকুনি, তবে আমার দ্বিতীয় ধারণাটি এটির একটি আরও দ্রুততর উপায় হতে পারে:

আপনি বিটম্যাপ ব্যবহার করে যেতে পারেন পরিবর্তে এবং পুরো bodiesToCheckভেক্টর এড়িয়ে চলতে পারেন । এখানে একটি পদ্ধতির:

আপনি ইতিমধ্যে মৃতদেহের জন্য পূর্ণসংখ্যা কীগুলি ব্যবহার করছেন তবে তারপরে সেগুলি মানচিত্র এবং জিনিসগুলিতে সন্ধান করছেন এবং সেগুলির তালিকাগুলি রাখবেন keeping আপনি স্লট বরাদ্দকারীতে যেতে পারেন, যা মূলত কেবল একটি অ্যারে বা ভেক্টর। উদাহরণ:

class TBodyImpl {
   public:
       virtual ~TBodyImpl() {}
       virtual void onHit(int other) {}
       virtual ....
       const int slot;
   protected:
      TBodyImpl(int slot): slot(slot_) {}
};

struct TBodyBase {
    enum ... type;
    ...
    rect_t rect;
    TQuadTreeNode *quadTreeNode; // see below
    TBodyImpl* imp; // often null
};

std::vector<TBodyBase> bodies; // not pointers to them

এর অর্থ হ'ল প্রকৃত সংঘর্ষগুলি করার জন্য প্রয়োজনীয় সমস্ত জিনিস লিনিয়ার ক্যাশে-বান্ধব মেমরির মধ্যে রয়েছে এবং আপনি কেবলমাত্র প্রয়োগ-নির্দিষ্ট বিটটিতে যান এবং কিছু দরকার হলে এটিকে এই স্লটের একটিতে সংযুক্ত করুন।

দেহের এই ভেক্টরটিতে বরাদ্দগুলি ট্র্যাক করতে আপনি একটি বিটম্যাপ হিসাবে পূর্ণসংখ্যার অ্যারে ব্যবহার করতে পারেন এবং বিট টুইডলিং ব্যবহার করতে পারেন বা__builtin_ffs এটি বর্তমানে দখলকৃত স্লটগুলিতে স্থানান্তরিত করতে বা অ্যারেতে একটি অনিয়ন্ত্রিত স্লট সন্ধান করতে অত্যন্ত দক্ষ। এমনকি আপনি কখনও কখনও অ্যারেটি সংক্ষিপ্ত করতে পারেন যদি এটি অযৌক্তিকভাবে বড় হয় এবং তারপরে শূন্যস্থান পূরণ করতে প্রান্তটি সরিয়ে নিয়ে প্রচুর মুছুন চিহ্নিত করা থাকে।

কেবলমাত্র প্রতিটি সংঘর্ষের জন্য একবার পরীক্ষা করুন

যদি আপনি চেক করা থাকেন তাহলে একটি ধাক্কা দিতে যাচ্ছিল , আপনি যদি চেক করতে প্রয়োজন হবে না ধাক্কা দিতে যাচ্ছিল একটি খুব।

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

unsigned * bitmap;
int bitmap_len;
...

for(int i=0; i<bitmap_len; i++) {
  unsigned mask = bitmap[i];
  while(mask) {
      const int j = __builtin_ffs(mask);
      const int slot = i*sizeof(unsigned)*8+j;
      for(int neighbour: get_neighbours(slot))
          if(neighbour > slot)
              check_for_collision(slot,neighbour);
      mask >>= j;
  }

সংঘর্ষের ক্রমকে সম্মান করুন

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

প্রতিটি নোডকে একটি সিকোয়েন্স নম্বর দিয়ে চিহ্নিত করুন, যাতে আপনি বলতে পারেন:

  • একটি 10 হ'ল বি 12 টি 6 এ
  • একটি 10 হিট সি 12 এ 3

স্পষ্টতই আপনি সমস্ত সংঘর্ষগুলি একত্রিত করার পরে, আপনি এটিকে অগ্রাধিকার সারিতে সজ্জিত করতে শুরু করুন, শীঘ্রই। সুতরাং প্রথমটি আপনি পেয়েছেন এটি 10 হিট সি 12 এ 3 You আপনি প্রতিটি বস্তুর ক্রম সংখ্যা ( 10 বিট) বৃদ্ধি করেন, সংঘর্ষের মূল্যায়ন করুন এবং তাদের নতুন পথগুলি গণনা করুন এবং তাদের নতুন সংঘর্ষ একই কাতারে সংরক্ষণ করুন। নতুন সংঘর্ষটি এ 11 টি বি 12 এর 7 এ 7 হিট The

  • একটি 10 হিট বি 12 6 এ
  • একটি 11 বি 12 কে 7 এ আঘাত করে

তারপর আপনি অগ্রাধিকার কিউ এবং তার একটি থেকে পপ 10 হিট বি 12 6. এ কিন্তু আপনি দেখতে যে একটি 10 হয় মামুলি ; এ বর্তমানে ১১ এ। সুতরাং আপনি এই সংঘর্ষটি বাতিল করতে পারেন।

গাছ থেকে সমস্ত বাসি সংঘর্ষ মুছে ফেলার চেষ্টা করে বিরক্ত করা গুরুত্বপূর্ণ নয়; গাদা থেকে অপসারণ ব্যয়বহুল। আপনি যখন তাদের পপ করবেন তখন কেবল এগুলি বাতিল করুন।

গ্রিড

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

এখানে একটি সাধারণ চতুষ্কোণ:

struct Object {
    Rect bounds;
    Point pos;
    Object * prev, * next;
    QuadTreeNode * parent;
};

struct QuadTreeNode {
    Rect bounds;
    Point centre;
    Object * staticObjects;
    Object * movableObjects;
    QuadTreeNode * parent; // null if root
    QuadTreeNode * children[4]; // null for unallocated children
};

অস্থাবর বস্তুগুলি আমরা আলাদাভাবে সংরক্ষণ করি কারণ স্থির বস্তুগুলির কোনওটির সাথে সংঘর্ষ হচ্ছে কিনা তা আমাদের খতিয়ে দেখার দরকার নেই।

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

প্রতিটি গেম টিক, আপনি প্রতিটি চলমান বস্তুর চতুষ্কোণ এবং পুনরাবৃত্তি এবং সরানো - এবং সংঘর্ষের গণনা করা প্রয়োজন। এটির সাথে সংঘর্ষের জন্য এটি পরীক্ষা করতে হবে:

  • তার নোডের প্রতিটি স্থির বস্তু
  • অস্থাবর ওবজেক্টস তালিকায় তার নোডের প্রতিটি অস্থাবর বস্তু যা তার আগে (বা এর পরে; কেবল একটি দিক বাছাই করুন)
  • সমস্ত প্যারেন্ট নোডে প্রতিটি চলমান এবং স্থির অবজেক্ট

এটি অনিয়ন্ত্রিত, সমস্ত সম্ভাব্য সংঘর্ষ তৈরি করবে। আপনি তারপর চালগুলি। আপনাকে দূরত্বে এবং 'কে প্রথমে চলে' (যেটি আপনার বিশেষ প্রয়োজন) এ পদক্ষেপগুলিকে অগ্রাধিকার দিতে হবে এবং সেটিকে সেই ক্রমে কার্যকর করতে হবে। এই জন্য একটি গাদা ব্যবহার করুন।

আপনি এই চতুষ্পদ টেম্পলেটটি অনুকূল করতে পারেন; আপনার আসলে সীমানা এবং কেন্দ্র-পয়েন্ট সংরক্ষণ করার দরকার নেই; আপনি যখন গাছটিতে হাঁটেন তখন এটি সম্পূর্ণরূপে উপার্জনযোগ্য। কোনও মডেল সীমানার মধ্যে রয়েছে কিনা তা আপনাকে পরীক্ষা করার দরকার নেই, কেবল এটি কেন্দ্র-পয়েন্টের ("বিচ্ছেদের অক্ষ" পরীক্ষার) কোন দিকের রয়েছে তা পরীক্ষা করুন।

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

বড় স্ট্যাটিক অবজেক্টগুলি উপাদান অংশে বিভক্ত করা উচিত; উদাহরণস্বরূপ, একটি বড় কিউবের প্রতিটি মুখ পৃথকভাবে সংরক্ষণ করা উচিত।


"পেইন্টিং" ভাল লাগছে, আমি এটিকে চেষ্টা করে দেব এবং ফলাফলগুলি যত তাড়াতাড়ি সম্ভব প্রতিবেদন করব। যদিও আপনার উত্তরের দ্বিতীয় অংশটি আমি বুঝতে পারি না - আমি প্রাক-আনয়ন সম্পর্কে কিছু পড়ার চেষ্টা করব।
ভিটোরিও রোমিও

আমি কোয়াডট্রি সুপারিশ করব না, এটি গ্রিড করার চেয়ে জটিল complicated এবং যদি সঠিকভাবে না করা হয় তবে এটি সঠিকভাবে কাজ করবে না এবং প্রায়শই নোড তৈরি / মুছে ফেলবে।
ক্লিকারমনকি

আপনার গাদা সম্পর্কে: চলাচলের ক্রমকে কি সম্মান করা হয়? দেহ এবং দেহ বিবেচনা করুন । বি এর ডান দিকে সরানো হয়, এবং বি এ এর ​​দিকে ডান দিকে চলে যায় - এখন যখন তারা একসাথে সংঘর্ষ হয়, প্রথমে যেটি স্থানান্তরিত হয়েছিল সেটিকে প্রথমে সমাধান করা উচিত এবং অন্যটিটি প্রভাবিত হবে না।
ভিটোরিও রোমিও

@ ভিটোরিওরোমিও যদি বি এবং বি এর দিকে একই টিকের সাথে একই দিকে এগিয়ে যায় এবং একই গতিতে তারা কি মাঝখানে মিলবে? বা এ, প্রথমে চলে যাওয়া, বি শুরু হয় যেখানে বি শুরু হয়?
উইল


3

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

ক্লুটি এখানে:

const std::vector<Body *>

এটি অবিলম্বে একটি বিশাল লাল পতাকা উত্থাপন করে। আপনি কি কাঁচা নতুন কল দিয়ে এই সংস্থাগুলি বরাদ্দ করছেন? ব্যবহারের ক্ষেত্রে কি কোনও কাস্টম বরাদ্দকারী রয়েছে? আপনার নিজের দেহগুলি একটি বিশাল অ্যারেতে থাকা যাতে আপনি রৈখিকভাবে অতিক্রম করেন এটি সর্বাধিক গুরুত্বপূর্ণ । মেমরিটিকে রৈখিকভাবে ট্র্যাভার করা যদি এমন কিছু না হয় যা আপনি মনে করেন তবে পরিবর্তে একটি অন্তর্ভুক্ত লিঙ্কযুক্ত তালিকা ব্যবহার করে বিবেচনা করতে পারেন implement

অতিরিক্ত হিসাবে আপনি স্ট্যান্ড :: ম্যাপ ব্যবহার করছেন বলে মনে হচ্ছে। আপনি কি জানেন কিভাবে স্ট্যান্ড :: ম্যাপের মধ্যে মেমরি বরাদ্দ করা হয়? প্রতিটি মানচিত্রের ক্যোয়ারির জন্য আপনার কাছে একটি (এলজি (এন)) জটিলতা থাকবে এবং এটি সম্ভবত হ্যাশ টেবিলের সাহায্যে ও (1) এ বাড়ানো যেতে পারে। এর উপরে স্ট্যান্ডার্ড :: ম্যাপের দ্বারা বরাদ্দ হওয়া মেমরিটি আপনার ক্যাশেটিকে মারাত্মকভাবে ছোঁড়াবে।

আমার সমাধানটি হ'ল স্ট্যান্ড :: মানচিত্রের জায়গায় একটি হস্তক্ষেপযুক্ত হ্যাশ টেবিল ব্যবহার করা। হস্তক্ষেপযুক্ত লিঙ্কযুক্ত তালিকা এবং হস্তক্ষেপের হ্যাশ টেবিল উভয়ের একটি ভাল উদাহরণ হ'ল প্যাট্রিক উইট তার কোহো প্রকল্পের বেসে: https://github.com/webcoyote/coho

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


"আপনি কি এই মৃতদেহগুলি কাঁচা নতুন কল দিয়ে বরাদ্দ করছেন?" আমি ভেক্টরটিতে newমৃতদেহগুলি ধাক্কা দেওয়ার সময় স্পষ্টভাবে কল করছি না getBodiesToCheck- আপনার অর্থ কি এটি অভ্যন্তরীণভাবে ঘটছে? দেহগুলির গতিশীল আকারের সংগ্রহের পরেও কী তা প্রতিরোধের কোনও উপায় আছে?
ভিটোরিও রোমিও

std::mapকোনও বাধা নয় - আমি চেষ্টা করেও মনে করি এবং dense_hash_setকোনও ধরণের পারফরম্যান্স না পেয়েছি ।
ভিটোরিও রোমিও

@Vittorio, তারপর কোন অংশ getBodiesToCheck বোতলের হয়? সাহায্য করার জন্য আমাদের তথ্য দরকার।
মাইক সেমদার

@ মাইকসেমদার: প্রোফাইলার নিজেই ফাংশনটির চেয়ে গভীরতর হয় না। পুরো ফাংশনটি হ'ল বাধা, কারণ এটি প্রতি দেহে প্রতি ফ্রেম একবার বলা হচ্ছে। 10000 সংস্থা = 10000 getBodiesToCheckকল প্রতি ফ্রেম। আমার সন্দেহ হয় যে ধ্রুবক পরিষ্কার / ভেক্টরে ঠেলাঠেলি এটি নিজেই ফাংশনটির বাধা। containsপদ্ধতি এছাড়াও মন্দার এর অংশ হওয়ায়, কিন্তু যেহেতু bodiesToCheckএটা বেশি 8-10 মৃতদেহ রয়েছে কখনো, এটা যে ধীর হওয়া উচিত
ভিত্তেরিও রোমিও

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

1

প্রতিটি ফ্রেম পরীক্ষা করতে শরীরের সংখ্যা হ্রাস করুন:

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

চতুর্ভুজ ব্যবহার করুন। আমার বিস্তারিত উত্তর এখানে দেখুন

আপনার পদার্থবিজ্ঞান কোড থেকে সমস্ত বরাদ্দ সরান। আপনি এই জন্য একটি প্রোফাইলার ব্যবহার করতে চান। তবে আমি কেবল # # তে মেমরির বরাদ্দ বিশ্লেষণ করেছি, তাই আমি সি ++ নিয়ে সহায়তা করতে পারি না।

শুভকামনা!


0

আমি আপনার বাধা ফাংশনে দুটি সমস্যা প্রার্থী দেখছি:

প্রথমটি "সমন্বিত" অংশ - এটি সম্ভবত ব্যটনেকের প্রধান কারণ। এটি প্রতিটি দেহের জন্য ইতিমধ্যে পাওয়া মৃতদেহের মধ্য দিয়ে পুনরাবৃত্তি করছে। হতে পারে আপনার পরিবর্তে ভেক্টরের পরিবর্তে কিছু ধরণের হ্যাশ_ট্যাবল / হ্যাশ_ম্যাপ ব্যবহার করা উচিত। তারপরে সন্নিবেশ দ্রুত করা উচিত (সদৃশ সন্ধানের সাথে)। তবে আমি কোনও নির্দিষ্ট নম্বর জানি না - এখানে কতগুলি দেহ পুনরাবৃত্তি হয়েছে তা আমার কোনও ধারণা নেই।

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


প্রথম সমস্যাটি সম্পর্কে: আমি ভেক্টর + এর পরিবর্তে ঘন_হ্যাশ_সেট ব্যবহার করার চেষ্টা করেছি এবং এটি ধীর ছিল। আমি ভেক্টরটি পূরণ করার চেষ্টা করেছি এবং তারপরে সমস্ত নকল সরিয়ে ফেললাম, এবং এটি ধীর ছিল।
ভিটোরিও রোমিও

0

দ্রষ্টব্য: আমি সি ++ কিছুই জানি না কেবল জাভা, তবে আপনার কোডটি বের করতে সক্ষম হওয়া উচিত। পদার্থবিজ্ঞান কি সর্বজনীন ভাষা ঠিক? আমি বুঝতে পারি এটি একটি বছরের পুরানো পোস্ট, তবুও আমি কেবল এটি সবার সাথে ভাগ করে নিতে চেয়েছিলাম।

আমার কাছে একটি পর্যবেক্ষক প্যাটার্ন রয়েছে যা মূলত সত্তাটি সরিয়ে নেওয়ার পরে, এটি একটি NUL অবজেক্ট সহ যে বস্তুটির সাথে সংঘটিত হয়েছিল তা ফিরিয়ে দেয়। সহজভাবে করা:

( আমি মাইনক্রাফ্টটি পুনর্নির্মাণ করছি )

public Block collided(){
   return World.getBlock(getLocation());
}

সুতরাং বলুন যে আপনি আপনার বিশ্বে ঘোরাফেরা করছেন। আপনি যখনই ফোন move(1)করবেন তখন কল করুন collided()। যদি আপনি যে ব্লকটি চান তা পেয়ে থাকেন, তবে সম্ভবত কণা উড়ে যায় এবং আপনি বাম এবং ডানদিকে পিছনে যেতে পারেন তবে এগিয়ে যান না।

এটি উদাহরণস্বরূপ মাইনক্রাফ্টের চেয়ে আরও সাধারণভাবে ব্যবহার করা:

public Object collided(){
   return threeDarray[3][2][3];
}

সহজভাবে, জাভা এটি কীভাবে নির্দেশনা করে, কী স্থানাঙ্কগুলি নির্দেশ করে তা নির্দেশ করার জন্য একটি অ্যারে রাখুন।

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

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

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

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