সি ++ তে সত্ত্বা উপাদান সিস্টেমের মধ্যে সংযোগ স্থাপনের পরামর্শ


10

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

for (entity x : listofentities) {
   for (system y : listofsystems) {
       if ((x.componentBitmask & y.bitmask) == y.bitmask)
             y.update(x, deltatime)
       }
 }

তবে আমি মনে করি একটি স্ক্রিপ্টিং ভাষা এম্বেড করার ক্ষেত্রে একটি বিটমাস্ক সিস্টেম নমনীয়তাটিকে ব্লক করবে। অথবা প্রতিটি সিস্টেমের জন্য স্থানীয় তালিকাগুলি ক্লাসগুলির জন্য মেমরির ব্যবহার বাড়িয়ে তুলবে। আমি ভীষণ বিভ্রান্ত


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

উদাহরণস্বরূপ একটি বিটমাস্ক ব্যবহার করে কেবল 32 টি আলাদা উপাদান থাকবে। আমি বোঝাচ্ছি না যে সেখানে 32 টিরও বেশি উপাদান থাকবে তবে আমার যদি তা থাকে তবে? আমাকে আর একটি ইনট বা 64৪ বিবিট ইনট তৈরি করতে হবে, এটি গতিশীল হবে না।
deniz

আপনি রান-টাইম ডায়নামিক হতে চান বা না চান তার উপর নির্ভর করে আপনি std :: বিটসেট বা std :: ভেক্টর <bool> ব্যবহার করতে পারেন।
বেনিয়ামিন ক্লোস্টার

উত্তর:


7

প্রতিটি সিস্টেমের জন্য স্থানীয় তালিকাগুলি ক্লাসগুলির জন্য মেমরির ব্যবহার বাড়িয়ে তুলবে।

এটি একটি traditional তিহ্যবাহী স্পেস-টাইম ট্রেড অফ ।

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

এটি বলেছিল, আপনার লক্ষ্যগুলির উপর নির্ভর করে এই পদ্ধতিটি এখনও যথেষ্ট ভাল হতে পারে।

যদিও, আপনি যদি গতি সম্পর্কে চিন্তিত হন তবে অবশ্যই বিবেচনার জন্য আরও একটি সমাধান রয়েছে।

প্রতিটি সিস্টেমে তাদের আগ্রহী সত্তাগুলির স্থানীয় তালিকা থাকা উচিত?

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

এখন কীভাবে এই "আগ্রহের তালিকাগুলি" বজায় রাখা যায় তা স্পষ্ট নাও হতে পারে। ডেটা কনটেইনার হিসাবে std::vector<entity*> targetsসিস্টেমের শ্রেণীর অভ্যন্তর পুরোপুরি যথেষ্ট। এখন আমি যা করি তা হ'ল:

  • সত্তা তৈরিতে খালি এবং কোনও সিস্টেমের সাথে সম্পর্কিত নয়।
  • যখনই আমি কোনও সত্তায় কোনও উপাদান যুক্ত করব:

    • এটির বর্তমান বিট স্বাক্ষর পান ,
    • পর্যাপ্ত পরিমাণের আকারের পুলের মানচিত্রের আকারের আকার (ব্যক্তিগতভাবে আমি বুস্ট :: পুল ব্যবহার করি) এবং সেখানে উপাদানটি বরাদ্দ করি
    • সত্তার নতুন বিট স্বাক্ষর (যা কেবল "বর্তমান বিট স্বাক্ষর" প্লাস নতুন উপাদান) পান
    • বিশ্বের সব ব্যবস্থা মাধ্যমে পুনরুক্তি এবং যদি একটি সিস্টেম যার স্বাক্ষর রয়েছে নেই সত্তা বর্তমান স্বাক্ষর মেলে এবং নেই নতুন স্বাক্ষর মেলে, এটি সুস্পষ্ট হয়ে আমরা সেখানে আমাদের সত্তা পয়েন্টার push_back করা উচিত নয়।

          for(auto sys = owner_world.systems.begin(); sys != owner_world.systems.end(); ++sys)
                  if((*sys)->components_signature.matches(new_signature) && !(*sys)->components_signature.matches(old_signature)) 
                          (*sys)->add(this);

কোনও সত্তা অপসারণ করা সম্পূর্ণরূপে সাদৃশ্যপূর্ণ, কেবলমাত্র সেই ব্যবধানের সাথে আমরা যদি মুছে ফেলি তবে যদি কোনও সিস্টেম আমাদের বর্তমান স্বাক্ষরের সাথে মিলিত হয় (যার অর্থ হ'ল সত্তাটি ছিল) এবং নতুন স্বাক্ষরের সাথে মেলে না (যার অর্থ সত্তা আর থাকা উচিত নয়) )।

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

স্টাড :: তালিকা আপনাকে ও (1) মুছে ফেলবে কিন্তু অন্যদিকে আপনার অতিরিক্ত মেমরির ওভারহেডের পরিমাণ রয়েছে। এছাড়াও মনে রাখবেন যে বেশিরভাগ সময় আপনি সত্তাগুলি প্রক্রিয়াকরণ করবেন এবং তাদের অপসারণ করবেন না - এবং এটি অবশ্যই স্ট্যান্ড :: ভেক্টর ব্যবহার করে দ্রুত সম্পন্ন করা হবে।

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


5

এমন একটি পদ্ধতির বিষয়টি বিবেচনা করা উচিত যেখানে প্রতিটি সিস্টেমের নিজের সাথে যুক্ত উপাদানগুলির মালিকানা রয়েছে এবং সত্ত্বাগুলি কেবল তাদের উল্লেখ করে। মূলত, আপনার (সরলীকৃত) Entityশ্রেণিটি এর মতো দেখাচ্ছে:

class Entity {
  std::map<ComponentType, Component*> components;
};

যখন আপনি কোনও RigidBodyসংযুক্তিকে কোনও সংযুক্তি বলবেন Entity, আপনি এটি আপনার Physicsসিস্টেম থেকে অনুরোধ করবেন । সিস্টেম উপাদান তৈরি করে এবং সত্তাটিকে এটিতে একটি পয়েন্টার রাখতে দেয়। আপনার সিস্টেমটি তখন এর মতো দেখাচ্ছে:

class PhysicsSystem {
  std::vector<RigidBodyComponent> rigidBodyComponents;
};

এখন, এটি প্রথমে কিছুটা পাল্টা স্বজ্ঞাত দেখাতে পারে তবে উপাদান সত্তা সিস্টেমগুলি তাদের রাষ্ট্র আপডেট করার উপকারটি in প্রায়শই, আপনি আপনার সিস্টেমে পুনরাবৃত্তি করবেন এবং অনুরোধ করুন তারা সম্পর্কিত উপাদানগুলি আপডেট করুন

for(auto it = systems.begin(); it != systems.end(); ++it) {
  it->update();
}

নিয়মিত স্মৃতিতে সিস্টেমের মালিকানাধীন সমস্ত উপাদান থাকার শক্তি হ'ল যখন আপনার সিস্টেমটি প্রতিটি উপাদানকে পুনরুক্ত করে এটি আপডেট করে, মূলত এটি করতে হয়

for(auto it = rigidBodyComponents.begin(); it != rigidBodyComponents.end(); ++it) {
  it->update();
}

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

এই মুহুর্তে Worldসিস্টেমগুলির মাধ্যমে আপনার কেবল লুপ হয় এবং updateসত্তাগুলি পুনরাবৃত্তি করার প্রয়োজন ছাড়াই তাদেরকে কল করে। এটি (ইমো) আরও ভাল নকশা কারণ তখন সিস্টেমগুলির দায়িত্বগুলি আরও পরিষ্কার হয় are

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


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

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

আপনি যদি বলেন দক্ষতার পক্ষে এটি আরও ভাল হবে, তবে আমি আপনার ধরণটি ব্যবহার করব।
ডেনিজ

@ এডিনিজ নিশ্চিত হয়ে নিন যে আপনি আসলে আপনার কোডটি প্রারম্ভিক এবং প্রায়শই আপনার নির্দিষ্ট
ইঞ্জিনের

ঠিক আছে :) আমি ধরণ চাপ পরীক্ষা কি করতে হবে
Deniz

1

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

এর পরে, আপনি যদি প্রতিটি সিস্টেমে বিভিন্ন বস্তুগুলিতে বা একটি নির্দিষ্ট ক্রমে পরিচালনা করতে চান তবে প্রতিটি সিস্টেমে সক্রিয় উপাদানগুলির একটি তালিকা তৈরি করা ভাল। সিস্টেমে আপনি যে পয়েন্টারগুলি তৈরি করতে এবং পরিচালনা করতে পারেন তার সমস্ত তালিকাগুলি একটি লোড হওয়া সংস্থান থেকে কম।

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