সি ++ ইঞ্জিন প্রোগ্রামিংয়ে আমি কীভাবে সিঙ্গলেটগুলি সঠিকভাবে ব্যবহার করব?


16

আমি জানি সিলেটলেটগুলি খারাপ, আমার পুরানো গেম ইঞ্জিনটি একটি সিঙ্গেলটন 'গেম' অবজেক্ট ব্যবহার করেছিল যা সমস্ত ডেটা প্রকৃত গেম লুপের সাথে রাখা থেকে সমস্ত কিছু পরিচালনা করে। এখন আমি একটি নতুন তৈরি করছি।

সমস্যাটি হ'ল, এসএফএমএল-তে কিছু আঁকুন window.draw(sprite)যেখানে আপনি উইন্ডোটি ব্যবহার করেন sf::RenderWindow। আমি এখানে 2 টি বিকল্প দেখতে পাচ্ছি:

  1. একটি সিঙ্গলটন গেম অবজেক্ট তৈরি করুন যা গেমের প্রতিটি সত্তা পুনরুদ্ধার করে (আমি যা আগে ব্যবহার করেছি)
  2. সত্তার জন্য এটি নির্মাণকারী করুন: Entity(x, y, window, view, ...etc)(এটি কেবল হাস্যকর এবং বিরক্তিকর)

সত্ত্বার কনস্ট্রাক্টরকে কেবল এক্স এবং ওয়াইতে রাখার ক্ষেত্রে এটি করার সঠিক উপায় কী হবে?

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


1
আপনি 'রেন্ডার' ফাংশনের যুক্তি হিসাবে উইন্ডোটি পাস করতে পারেন could
দারি

25
সিঙ্গেলন খারাপ না! এগুলি দরকারী এবং কখনও কখনও প্রয়োজনীয় হতে পারে (অবশ্যই এটি বিতর্কযোগ্য)।
ExOfDe

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

আমি আমার উইন্ডো এবং অন্যান্য নির্ভরতাগুলি আমার প্রধানতে ঘোষণা করি এবং তারপরে আমার অন্যান্য ক্লাসে আমার পয়েন্টার রয়েছে।
KaareZ

1
@ জ্যাব মূল () থেকে ম্যানুয়াল ইনিশিয়ালাইজেশন সহ সহজেই ঠিক করা হয়েছে। অলস সূচনাটি এটি একটি অজানা মুহুর্তে ঘটায়, যা মূল সিস্টেমগুলির পক্ষে কখনও ভাল ধারণা নয়।
সাপ

উত্তর:


3

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

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

সুতরাং আপনার শীর্ষ স্তরের শ্রেণিতে গেম আপডেট লুপটি দেখতে পারে:

EntityList entities = mCurrentLevel.getEntities();
for(auto& i : entities){
  // Run game logic...
  i->update(...);
}
// Render all the entities
for(auto& i : entities){
  mRenderer->draw(i->getSprite());
}

3
একটি সিঙ্গলটন সম্পর্কে আদর্শ কিছুই নেই। আপনার যখন দরকার নেই তখন বাস্তবায়ন কেন অভ্যন্তরীণ প্রকাশ্য করবেন? Logger::getInstance().Log(...)শুধু লেখার বদলে কেন লিখবেন Log(...)? আপনি কেবল একবার ম্যানুয়ালি এটি করতে পারেন কিনা এমন প্রশ্ন করা হলে কেন এলোমেলোভাবে ক্লাসটি শুরু করবেন? স্থির গ্লোবালগুলি উল্লেখ করার জন্য একটি বিশ্বব্যাপী ফাংশন তৈরি এবং ব্যবহার করা আরও অনেক সহজ।
সাপ 5

@ সাপ 5 স্ট্যাক এক্সচেঞ্জে এককভাবে জাস্টিফাইজ করা হিটলারের প্রতি সহানুভূতির মতো।
উইলি ছাগল

30

সহজ পদ্ধতির মধ্যে কেবল ব্যবহৃত জিনিসটি তৈরি করা ছিল Singleton<T>T পরিবর্তে বিশ্বব্যাপী জিনিসটিকে কেবল তৈরি করা। গ্লোবালগুলিরও সমস্যা আছে, তবে তারা একটি তুচ্ছ বাধা প্রয়োগ করতে অতিরিক্ত কাজ এবং বয়লারপ্লেট কোডের একগুচ্ছ প্রতিনিধিত্ব করে না। এটি মূলত একমাত্র সমাধান যা সত্তা নির্মাতাকে স্পর্শ করে না (সম্ভাব্য)।

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

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

তবে এটি সম্ভাব্য একটি মেজর উদ্যোগ aking সত্যের পরে কোনও সিস্টেমে এটি করা সম্পূর্ণরূপে বেদনাদায়ক হতে পারে। আপাতত আপনার সিস্টেমকে একা রেখে কেবল সিঙ্গলটনের সাথে ছেড়ে দেওয়া আপনার পক্ষে অনেক বেশি বাস্তবসম্মত হতে পারে (বিশেষত যদি আপনি এমন একটি খেলা শিপানোর চেষ্টা করছেন যা অন্যথায় ঠিক কাজ করে; খেলোয়াড়রা সাধারণত আপনার যত্ন নিচ্ছেন না যদি আপনার কাছে থাকে একটি সিঙ্গলটন বা সেখানে চার)।

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

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


3
আমি সি ++ এর সাথে পরিচিত নই, তবে এই ভাষার জন্য আরামদায়ক নির্ভরতা ইনজেকশন ফ্রেমওয়ার্কগুলি নেই?
বিগুসাচ

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

1
সত্তাকে এটিকে তৈরি করার হিসাবে তিনি যে পদ্ধতিটি বর্ণনা করেছেন তা সেগুলি নিজেরাই আঁকবে না তবে তথ্য ধরে রাখে এবং একটি একক সিস্টেম সমস্ত সত্ত্বাকে আঁকলে পরিচালনা করে আজ বেশিরভাগ জনপ্রিয় গেম ইঞ্জিনগুলিতে প্রচুর ব্যবহৃত হয়।
প্যাট্রিক ডব্লিউ। ম্যাকমাহন 16

1
"এটি স্থূল দেখায় এমনটি আপনাকে কিছু বলতে হবে: আপনার নকশা স্থূল হতে পারে +"
ছায়া 503

আদর্শ কেস এবং ব্যবহারিক উত্তর উভয় দেওয়ার জন্য +1।

6

এসএফ :: রেন্ডার উইন্ডো থেকে উত্তরাধিকারী

এসএফএমএল আসলে এর ক্লাস থেকে উত্তরাধিকারী হতে উত্সাহিত করে।

class GameWindow: public sf::RenderWindow{};

এখান থেকে, আপনি সত্ত্বা অঙ্কনের জন্য সদস্য অঙ্কন ফাংশন তৈরি করেন।

class GameWindow: public sf::RenderWindow{
public:
 void draw(const Entity& entity);
};

এখন আপনি এটি করতে পারেন:

GameWindow window;
Entity entity;

window.draw(entity);

এমনকি আপনার প্রতিষ্ঠানগুলি এসটি :: স্প্রাইট থেকে এনটিটি উত্তরাধিকারসূত্রে পরিণত করে নিজস্ব অনন্য স্প্রিট ধরে রাখতে চাইলে আপনি এটিকে আরও দূরে নিতে পারেন।

class Entity: public sf::Sprite{};

এখন sf::RenderWindowকেবল সত্ত্বা আঁকতে পারে, এবং সত্তাগুলির এখন setTexture()এবং এর মতো ফাংশন রয়েছে setColor()। সত্তা এমনকি স্প্রাইটের অবস্থানকে তার নিজস্ব অবস্থান হিসাবে ব্যবহার করতে পারে, আপনাকে setPosition()সত্ত্বা এবং এর স্প্রাইট উভয়কেই স্থানান্তর করার জন্য ফাংশনটি ব্যবহার করার অনুমতি দেয় ।


শেষ পর্যন্ত , এটি আপনার কাছে ঠিক থাকলে খুব সুন্দর:

window.draw(game);

নীচে কয়েকটি দ্রুত উদাহরণ বাস্তবায়ন দেওয়া হল

class GameWindow: public sf::RenderWindow{
 sf::Sprite entitySprite; //assuming your Entities don't need unique sprites.
public:
 void draw(const Entity& entity){
  entitySprite.setPosition(entity.getPosition());
  sf::RenderWindow::draw(entitySprite);
 }
};

অথবা

class GameWindow: public sf::RenderWindow{
public:
 void draw(const Entity& entity){
  sf::RenderWindow::draw(entity.getSprite()); //assuming Entities hold their own sprite.
 }
};

3

আপনি গেম ডেভেলপমেন্টে সিলেটলেটনগুলিকে একইভাবে এড়িয়ে যান যেমন আপনি অন্য প্রতিটি ধরণের সফ্টওয়্যার বিকাশে তাদের এড়ান: আপনি নির্ভরতাগুলি পাস করেন

উপায় যে সঙ্গে, আপনি নির্ভরতা খালি প্রকার (মত সরাসরি পাস করা চয়ন করতে পারেন int, Window*ইত্যাদি) অথবা আপনি (যেমন ধরনের মোড়কের এক বা একাধিক কাস্টম তাদের পাস করা চয়ন করতে পারেন EntityInitializationOptions)।

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


3

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

বিশ্বব্যাপী একটি একককে প্রতিস্থাপনের একমাত্র বৈধ কারণ হ'ল ধর্মীয় সিঙ্গলটন বিদ্বেষীদের শান্ত করা।

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

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


1
আমি ধর্মীয় সিঙ্গলটন বিদ্বেষী এবং আমি বিশ্বব্যাপী কোনও সমাধানও বিবেচনা করি না। : এস
ড্যান প্যান্ট্রি

1

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

RenderSystem(IWindow* window);

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

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

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