আমি একটি শ্যুটার লিখছি (1942 এর মতো ক্লাসিক 2 ডি গ্রাফিক্স) এবং আমি একটি উপাদান ভিত্তিক অ্যাপ্রোচ ব্যবহার করতে চাই। এতক্ষণ আমি নিম্নলিখিত নকশা সম্পর্কে ভেবেছি:
প্রতিটি গেম উপাদান (এয়ারশিপ, প্রক্ষিপ্ত, পাওয়ারআপ, শত্রু) একটি সত্তা
প্রতিটি সত্তা উপাদানগুলির একটি সেট যা রানটাইমে যোগ বা সরানো যায়। পজিশন, স্প্রাইট, স্বাস্থ্য, আইএ, ক্ষয়ক্ষতি, বাউন্ডিংবক্স ইত্যাদি উদাহরণ are
ধারণাটি হ'ল এয়ারশিপ, প্রজেক্টাইল, শত্রু, পাওয়ারআপ কোনও গেম ক্লাস নয়। একটি সত্তা কেবল তার মালিকানাধীন উপাদানগুলির দ্বারা সংজ্ঞায়িত হয় (এবং এটি সময়ের সাথে পরিবর্তন হতে পারে)। সুতরাং প্লেয়ার আয়ারশিপ স্প্রাইট, অবস্থান, স্বাস্থ্য এবং ইনপুট উপাদান দিয়ে শুরু হয়। একটি পাওয়ারআপে স্প্রাইট, পজিশন, বাউন্ডিংবক্স রয়েছে। ইত্যাদি।
প্রধান লুপটি গেমটি "পদার্থবিজ্ঞান" পরিচালনা করে, যেমন উপাদানগুলি একে অপরকে কীভাবে যোগাযোগ করে:
foreach(entity (let it be entity1) with a Damage component)
foreach(entity (let it be entity2) with a Health component)
if(the entity1.BoundingBox collides with entity2.BoundingBox)
{
entity2.Health.decrease(entity1.Damage.amount());
}
foreach(entity with a IA component)
entity.IA.update();
foreach(entity with a Sprite component)
draw(entity.Sprite.surface());
...
মূল সি ++ অ্যাপ্লিকেশনটিতে উপাদানগুলি হার্ডকোডযুক্ত। সত্ত্বাগুলি একটি এক্সএমএল ফাইলে সংজ্ঞায়িত করা যায় (লুয়া বা পাইথন ফাইলের আইএ অংশ)।
প্রধান লুপটি সত্ত্বা সম্পর্কে খুব বেশি যত্ন করে না: এটি কেবল উপাদানগুলি পরিচালনা করে। সফ্টওয়্যার ডিজাইনের অনুমতি দেওয়া উচিত:
একটি উপাদান দেওয়া হয়েছে, এটি সত্তার সত্তাটি পান
একটি সত্তা দেওয়া হয়েছে, "টাইপ" টাইপের উপাদানটি পান
সমস্ত সত্তার জন্য, কিছু করুন
সমস্ত সত্তার উপাদানগুলির জন্য, কিছু করুন (উদাহরণস্বরূপ: সিরিয়ালাইজ)
আমি নিম্নলিখিত সম্পর্কে চিন্তা ছিল:
class Entity;
class Component { Entity* entity; ... virtual void serialize(filestream, op) = 0; ...}
class Sprite : public Component {...};
class Position : public Component {...};
class IA : public Component {... virtual void update() = 0; };
// I don't remember exactly the boost::fusion map syntax right now, sorry.
class Entity
{
int id; // entity id
boost::fusion::map< pair<Sprite, Sprite*>, pair<Position, Position*> > components;
template <class C> bool has_component() { return components.at<C>() != 0; }
template <class C> C* get_component() { return components.at<C>(); }
template <class C> void add_component(C* c) { components.at<C>() = c; }
template <class C> void remove_component(C* c) { components.at<C>() = 0; }
void serialize(filestream, op) { /* Serialize all componets*/ }
...
};
std::list<Entity*> entity_list;
এই নকশার সাহায্যে আমি # 1, # 2, # 3 (বুস্ট :: ফিউশন :: মানচিত্র অ্যালগরিদমকে ধন্যবাদ) এবং # 4 পেতে পারি। এছাড়াও সবকিছু ও (1) (ঠিক আছে, ঠিক নয়, তবে এটি এখনও খুব দ্রুত)।
আরও একটি "সাধারণ" পদ্ধতির রয়েছে:
class Entity;
class Component { Entity* entity; ... virtual void serialize(filestream, op) = 0; ...}
class Sprite : public Component { static const int type_id = 0; };
class Position : public Component { static const int type_id = 1; };
class Entity
{
int id; // entity id
std::vector<Component*> components;
bool has_component() { return components[i] != 0; }
template <class C> C* get_component() { return dynamic_cast<C> components[C::id](); } // It's actually quite safe
...
};
সত্তা শ্রেণি থেকে মুক্তি পাওয়ার জন্য আরও একটি পদ্ধতি হ'ল: প্রতিটি অংশের নিজস্ব তালিকায় বাস করে। সুতরাং একটি স্প্রাইট তালিকা আছে, একটি স্বাস্থ্য তালিকা, একটি ক্ষতির তালিকা ইত্যাদি I আমি জানি যে সত্তা আইডির কারণে তারা একই লজিক সত্তার অন্তর্ভুক্ত। এটি সহজ, তবে ধীর: আইএ উপাদানগুলির মূলত অন্যান্য সত্তার সমস্ত উপাদানগুলিতে অ্যাক্সেস প্রয়োজন এবং এর জন্য প্রতিটি পদক্ষেপে একে অপরের উপাদানগুলির তালিকা অনুসন্ধান করা প্রয়োজন।
আপনি কোন পদ্ধতির ভাল বলে মনে করেন? বুস্ট :: ফিউশন মানচিত্রটি সেভাবে ব্যবহারের জন্য উপযুক্ত?