একটি উপাদান ভিত্তিক গেম ডিজাইন করা


16

আমি একটি শ্যুটার লিখছি (1942 এর মতো ক্লাসিক 2 ডি গ্রাফিক্স) এবং আমি একটি উপাদান ভিত্তিক অ্যাপ্রোচ ব্যবহার করতে চাই। এতক্ষণ আমি নিম্নলিখিত নকশা সম্পর্কে ভেবেছি:

  1. প্রতিটি গেম উপাদান (এয়ারশিপ, প্রক্ষিপ্ত, পাওয়ারআপ, শত্রু) একটি সত্তা

  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()); 

...

মূল সি ++ অ্যাপ্লিকেশনটিতে উপাদানগুলি হার্ডকোডযুক্ত। সত্ত্বাগুলি একটি এক্সএমএল ফাইলে সংজ্ঞায়িত করা যায় (লুয়া বা পাইথন ফাইলের আইএ অংশ)।

প্রধান লুপটি সত্ত্বা সম্পর্কে খুব বেশি যত্ন করে না: এটি কেবল উপাদানগুলি পরিচালনা করে। সফ্টওয়্যার ডিজাইনের অনুমতি দেওয়া উচিত:

  1. একটি উপাদান দেওয়া হয়েছে, এটি সত্তার সত্তাটি পান

  2. একটি সত্তা দেওয়া হয়েছে, "টাইপ" টাইপের উপাদানটি পান

  3. সমস্ত সত্তার জন্য, কিছু করুন

  4. সমস্ত সত্তার উপাদানগুলির জন্য, কিছু করুন (উদাহরণস্বরূপ: সিরিয়ালাইজ)

আমি নিম্নলিখিত সম্পর্কে চিন্তা ছিল:

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 আমি জানি যে সত্তা আইডির কারণে তারা একই লজিক সত্তার অন্তর্ভুক্ত। এটি সহজ, তবে ধীর: আইএ উপাদানগুলির মূলত অন্যান্য সত্তার সমস্ত উপাদানগুলিতে অ্যাক্সেস প্রয়োজন এবং এর জন্য প্রতিটি পদক্ষেপে একে অপরের উপাদানগুলির তালিকা অনুসন্ধান করা প্রয়োজন।

আপনি কোন পদ্ধতির ভাল বলে মনে করেন? বুস্ট :: ফিউশন মানচিত্রটি সেভাবে ব্যবহারের জন্য উপযুক্ত?


2
কেন ডাউনটা? এই প্রশ্নে ভুল কি?
এমিলিয়ানো

উত্তর:


6

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

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

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


"ডেটা-ওরিয়েন্টেড" বলতে কী বোঝ?
এমিলিয়ানো

গুগলে প্রচুর তথ্য রয়েছে, তবে এখানে একটি শালীন নিবন্ধ রয়েছে যা পপ আপ হয়েছে যা একটি উচ্চ-স্তরের ওভারভিউ প্রদান করবে, এরপরে এটি আলোচনার পরে উপাদান উপাদানগুলির সাথে সম্পর্কিত: গেমসফ্রমেউইথন. com / ডাটা-ওরিয়েন্টেড-
স্কাইলার ইয়র্ক

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

এটি আমার প্রশ্নের সরাসরি উত্তর দেয় না তবে এটি খুব তথ্যপূর্ণ। আমার বিশ্ববিদ্যালয়ের দিনগুলিতে ডেটাফ্লো সম্পর্কে কিছু মনে পড়েছিল। এটি এখন পর্যন্ত সেরা উত্তর, এবং এটি "জিতেছে"।
এমিলিয়ানো

-1

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

// declare components here------------------------------
class component
{
};

class health:public component
{
public:
    int value;
};

class boundingbox:public component
{
public :
    int left,right,top,bottom;
    bool collision(boundingbox& other)
    {
        if (left < other.right || right > other.left)
            if (top < other.bottom || bottom > other.top)
                return true;
        return false;
    }
};

class damage : public component
{
public:
    int value;
};

// declare enteties here------------------------------

class entity
{
    virtual int id() = 0;
    virtual int size() = 0;
};

class aircraft :public entity, public health,public boundingbox
{
    virtual int id(){return 1;}
    virtual int size() {return sizeof(*this);};
};

class bullet :public entity, public damage, public boundingbox
{
    virtual int id(){return 2;}
    virtual int size() {return sizeof(*this);};
};

int main()
{
    entity* gameobjects[3];
    gameobjects[0] = new aircraft;
    gameobjects[1] = new bullet;
    gameobjects[2] = new bullet;
    for (int i=0;i<3;i++)
        for(int j=0;j<3;j++)
            if (dynamic_cast<boundingbox*>(gameobjects[i]) && dynamic_cast<boundingbox*>(gameobjects[j]) &&
                dynamic_cast<boundingbox*>(gameobjects[i])->collision(*dynamic_cast<boundingbox*>(gameobjects[j])))
                if (dynamic_cast<health*>(gameobjects[i]) && dynamic_cast<damage*>(gameobjects[j]))
                    dynamic_cast<health*>(gameobjects[i])->value -= dynamic_cast<damage*>(gameobjects[j])->value;
}

এই পদ্ধতির মধ্যে প্রতিটি উপাদান একটি সত্তার জন্য ভিত্তি তাই উপাদানটির নির্দেশকটি একটি সত্তাও দেওয়া হয়! দ্বিতীয়টি যা আপনি জিজ্ঞাসা করেছেন তা হ'ল কিছু সত্তার উপাদানগুলিতে সরাসরি অ্যাক্সেস পাওয়া। যখন আমি ব্যবহার করি আমার dynamic_cast<damage*>(entity)->valueযে কোনও একটি সত্তায় ক্ষতির অ্যাক্সেস করা দরকার , সুতরাং entityক্ষতির উপাদান থাকলে এটির মান ফিরে আসবে। যদি আপনি নিশ্চিত না হন entityযে উপাদানটির ক্ষতি আছে কি না আপনি সহজেই এর if (dynamic_cast<damage*> (entity))রিটার্ন মানটি dynamic_castসর্বদা নুল হয় যদি castালাই বৈধ না হয় এবং একই পয়েন্টার তবে অনুরোধ করা প্রকারের সাথে বৈধ কিনা। তাই নীচের মতো করে entitiesকিছু componentকরতে পারে এমন কিছু সহ কিছু করার জন্য

for (int i=0;i<enteties.size();i++)
    if (dynamic_cast<component*>(enteties[i]))
        //do somthing here

অন্য কোন প্রশ্ন থাকলে আমি উত্তর দিতে খুশি হবে।


আমি কেন ভোট পেয়েছি? আমার সমাধানে কি ভুল ছিল?
Ali1S232

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

প্রথমে প্রশ্নের কাঠামোর জন্য জিজ্ঞাসা করে যে প্রতিটি উপাদান উদাহরণ কেবল একটি সত্তার সাথে সম্পর্কিত, এবং আপনি কেবল bool isActiveবেস বেস উপাদানগুলি যোগ করে উপাদানগুলি সক্রিয় ও নিষ্ক্রিয় করতে পারেন । এখনও ব্যবহারযোগ্য উপাদান প্রবর্তনের প্রয়োজন হয় যখন আপনি enteties সংজ্ঞা হয় কিন্তু আমি এটা বিবেচনা করা হয় না একটি সমস্যা হিসেবে, এবং এখনও আপনি seprate componnent আপডেট (মত পারছেন স্মরণ dynamic_cast<componnet*>(entity)->update()
Ali1S232

এবং আমি একমত যে যখনই সে উপাদানটি রাখতে পারে যা তথ্য ভাগ করে নিতে পারে তখনই সমস্যা থাকবে তবে তিনি যা চেয়েছিলেন তা বিবেচনা করে আমি মনে করি যে এর জন্য কোনও সমস্যা হবে না এবং আবারও সেই সমস্যার জন্য কিছু কৌশল আছে যে আপনি যদি আমি ব্যাখ্যা করতে চান চাই।
Ali1S232

যদিও আমি একমত যে এটি এভাবে বাস্তবায়ন করা সম্ভব, তবে আমি এটি একটি ভাল ধারণা বলে মনে করি না। আপনার ডিজাইনাররা নিজেরাই অবজেক্টগুলি রচনা করতে পারবেন না, যদি না আপনার কাছে একটি ওবার ক্লাস থাকে যা সমস্ত সম্ভাব্য উপাদানগুলির উত্তরাধিকার সূত্রে প্রাপ্ত হয়। এবং আপনি যখন কেবল একটি উপাদানটিতে আপডেট কল করতে পারেন, এতে মেমরির লেআউটটি ভাল থাকবে না, একটি রচিত মডেলটিতে একই ধরণের সমস্ত উপাদান দৃষ্টান্তের সাথে মেমরির কাছে রাখা যেতে পারে এবং কোনও ক্যাশে মিস না করে পুনরুক্ত করা যায়। আপনি আরটিটিআইয়ের উপরও নির্ভর করছেন যা পারফরম্যান্সের কারণে সাধারণত গেমসে বন্ধ হয়ে যায়। বেশিরভাগ ক্ষেত্রে একটি ভাল সাজানো অবজেক্ট লেআউট স্থির করে।
অকার্যকর
আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.