গেমের বিষয়গুলি কীভাবে দুর্ঘটনাক্রমে সি ++ এ মুছে ফেলা যায়


20

ধরা যাক আমার গেমটিতে এমন একটি দানব রয়েছে যা কমিকাজে প্লেয়ারের উপর বিস্ফোরিত হতে পারে। আসুন এ দানবটির জন্য এলোমেলোভাবে একটি নাম বেছে নেওয়া যাক: একটি লতা। সুতরাং, Creeperক্লাসটির এমন একটি পদ্ধতি রয়েছে যা দেখতে এরকম কিছু দেখাচ্ছে:

void Creeper::kamikaze() {
    EventSystem::postEvent(ENTITY_DEATH, this);

    Explosion* e = new Explosion;
    e->setLocation(this->location());
    this->world->addEntity(e);
}

ইভেন্টগুলি সারিবদ্ধ নয়, তারা তাত্ক্ষণিক প্রেরণ করা হবে। এটি Creeperকলটির অভ্যন্তরে কোথাও মুছে ফেলা হবে postEvent। এটার মতো কিছু:

void World::handleEvent(int type, void* context) {
    if(type == ENTITY_DEATH){
        Entity* ent = dynamic_cast<Entity*>(context);
        removeEntity(ent);
        delete ent;
    }
}

কারণ পদ্ধতিটি চলমান Creeperঅবস্থায় অবজেক্টটি মুছে ফেলা হয়েছে kamikaze, এটি অ্যাক্সেস করার চেষ্টা করলে ক্রাশ হবে this->location()

একটি সমাধান হ'ল ইভেন্টগুলি বাফারে সারি করে পরে তা প্রেরণ করা। এটি কি সি ++ গেমগুলির সাধারণ সমাধান? এটি কিছুটা হ্যাকের মতো মনে হয়, তবে এটি কেবল ভিন্ন মেমরি পরিচালনার অনুশীলন সহ অন্যান্য ভাষার সাথে আমার অভিজ্ঞতার কারণেই হতে পারে।

সি ++-তে, এই সমস্যাটির আরও ভাল কোনও সাধারণ সমাধান হতে পারে যেখানে কোনও বস্তু ঘটনাক্রমে তার কোনও পদ্ধতির অভ্যন্তর থেকে নিজেকে মুছে ফেলে?


6
আহ, আপনি কীভাবে পোস্টের শুরুতে কমিকেজ পদ্ধতিটির শেষে শুরুতে কল করবেন না?
হ্যাকওয়ার্থ

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

আপনি autoreleaseঅবজেক্টিভ-সি এর বাস্তবায়নটি একবার দেখে নিতে পারেন , যেখানে "কিছুটা" অবধি মুছে ফেলা বন্ধ রয়েছে।
ক্রিস বার্ট-ব্রাউন 14

উত্তর:


40

মুছবেন না this

এমনকি স্পষ্টভাবে।

- কখনও -

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

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


6
প্রথম বন্ধনে আপনার উত্তরটির দ্বিতীয়ার্ধটি সহায়ক ছিল। একটি পতাকা জন্য ভোটদান একটি ভাল সমাধান। তবে, আমি কীভাবে এটি করা এড়াতে হবে তা জিজ্ঞাসা করছিলাম, এটি করা ভাল বা খারাপ জিনিস নয়। যদি কোনও প্রশ্ন জিজ্ঞাসা করে যে " আমি কীভাবে এক্স দুর্ঘটনাবশত এড়াতে পারি? ", এবং আপনার উত্তরটি " কখনও কখনও এক্স করবেন না, এমনকি দুর্ঘটনাক্রমেও " সাহসী হয়ে থাকে, তবে এটি আসলে প্রশ্নের উত্তর দেয় না।
টম ডালিং

7
আমার উত্তরের প্রথমার্ধে আমি যে মন্তব্য করেছি তার পেছনে আমি দাঁড়িয়ে আছি এবং আমি অনুভব করি যে তারা প্রশ্নের উত্তরটিকে মূলত বর্ণিত হিসাবে পুরোপুরি উত্তর দিয়েছে। আমি এখানে যে গুরুত্বপূর্ণ বিষয়টি পুনরাবৃত্তি করব তা হ'ল কোনও বস্তু নিজে থেকে মুছবে না। কখনও । এটি মুছতে অন্য কাউকে কল করে না। কখনও । পরিবর্তে, আপনার অবজেক্টের বাইরে অন্য কিছু থাকা দরকার যা বস্তুর মালিক এবং যখন বিষয়টিকে ধ্বংস করতে হবে তখন এটি দেখার জন্য দায়বদ্ধ। এটি কোনও "দৈত্যের মৃত্যুর সময়" জিনিস নয়; এটি সর্বদা, সর্বত্র, সর্বকালের জন্য সমস্ত সি ++ কোডের জন্য। কোন আশা নাই.
ট্রেভর পাওয়েল

3
@ ট্রেভরপওয়েল আমি বলছি না যে আপনি ভুল। আসলে, আমি আপনার সাথে একমত। আমি কেবল বলছি এটি আসলে যে প্রশ্নটি করা হয়েছিল তার উত্তর দেয় না। এটি যদি আপনি আমাকে জিজ্ঞাসা করেন তবে " আমি আমার গেমটিতে অডিও কীভাবে করব? " এবং আমার উত্তর ছিল " আমি বিশ্বাস করতে পারি না আপনার অডিও নেই don't এখনই আপনার গেমটিতে অডিও রাখুন। " তারপরে প্রথম বন্ধনে আমি "" আপনি এফএমওডি ব্যবহার করতে পারেন) , "এটি একটি আসল উত্তর।
টম ডালিং

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

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

21

বাফারে ইভেন্টগুলি সারিবদ্ধ করার পরিবর্তে বাফারে মুছে ফেলার সারি সারি করুন । বিলম্বিত-মুছে ফেলার যুক্তিটি ব্যাপকভাবে সরল করার সম্ভাবনা রয়েছে; আপনি আসলে কোনও ফ্রেমের শেষে বা শুরুতে মেমরিটি মুক্ত করতে পারেন যখন আপনি জানেন যে আপনার জিনিসগুলির সাথে আকর্ষণীয় কিছু ঘটছে না এবং একেবারে যে কোনও জায়গা থেকে মুছুন।


1
মজার আপনি এটি উল্লেখ করেছেন, কারণ আমি ভাবছিলাম যে NSAutoreleasePoolএই পরিস্থিতিতে উদ্দেশ্য-সি থেকে কতটা সুন্দর হবে। DeletionPoolসি ++ টেম্পলেট বা কিছু দিয়ে একটি তৈরি করতে পারে।
টম ডালিং

@ টমডালিং আপনি বাফারটিকে অবজেক্টের বাহ্যিক করে তোলেন সে সম্পর্কে সাবধানতা অবলম্বন করার একটি বিষয় হ'ল কোনও একক ফ্রেমে একাধিক কারণে মুছে ফেলা হতে পারে এবং এটি বেশ কয়েকবার মুছে ফেলার চেষ্টা করা সম্ভব হবে।
জন কলসবেক

খুবই সত্য. আমাকে পয়েন্টারগুলি একটি স্টাডি :: সেটে রাখতে হবে।
টম ডালিং

5
মুছে ফেলার জন্য বস্তুর বাফারের পরিবর্তে আপনি কেবলমাত্র বস্তুটিতে একটি পতাকা সেট করতে পারেন। একবার আপনি যখন বুঝতে চান যে আপনি নতুন কল করা বা রানটাইম চলাকালীন মুছে ফেলতে চান এবং একটি বস্ত পুলে চলে যেতে চান, তখন তা আরও সহজ এবং দ্রুত হবে।
শান মিডলডিচ

4

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

এই জাতীয় শ্রেণীর উদাহরণ এরকম হবে: http://ideone.com/7Upza


+1, এটি সত্তা সরাসরি ফ্ল্যাগ করার বিকল্প ging আরও সরাসরি, সরাসরি Worldশ্রেণিতে সরাসরি জীবিত-তালিকা এবং সত্ত্বার একটি মৃত তালিকা রয়েছে ।
লরেন্ট কুইভিডউ

2

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

উদাহরণ স্বরূপ

Object* o = gFactory->Create("Explosion");

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

একটি ফ্রেমের বিলম্ব সহ সমস্ত বার্তা প্রেরণ বিবেচনা করুন। কেবলমাত্র কয়েকটি ব্যতিক্রম রয়েছে যেখানে আপনাকে অবিলম্বে প্রেরণ করতে হবে, কেবলমাত্র বিশাল ক্ষেত্রে


2

আপনি নিজেই সি ++ তে ম্যানেজড-মেমোরি প্রয়োগ করতে পারেন, যাতে যখন ENTITY_DEATHডাকা হয় তখন যা ঘটে তা হ'ল এর রেফারেন্সের সংখ্যাটি একে একে হ্রাস করা হয়।

পরবর্তীতে @ জন প্রতিটি ফ্রেমের ভিক্ষাবৃত্তির পরামর্শ অনুসারে আপনি কোন সত্তাকে অকেজো (যা শূন্য রেফারেন্স সহ রয়েছে) পরীক্ষা করতে পারেন এবং সেগুলি মুছতে পারেন। উদাহরণস্বরূপ আপনি ব্যবহার করতে পারেন boost::shared_ptr<T>( এখানে ডকুমেন্টেড ) বা আপনি যদি সি ++ 11 (ভিসি 2010) ব্যবহার করছেনstd::tr1::shared_ptr<T>


শুধু std::shared_ptr<T>, প্রযুক্তিগত রিপোর্ট নয়! - আপনাকে একটি কাস্টম মোছা নির্দিষ্ট করে দিতে হবে, অন্যথায় রেফারেন্স গণনা শূন্যে পৌঁছলে তা অবিলম্বে বস্তুটি মুছবে।
বাম দিকের বাইরে

1
@ বামদিকের চারপাশে এটি সত্যিই নির্ভর করে, কমপক্ষে আমাকে জিসিসিতে tr1 ব্যবহার করা দরকার। তবে ভিসিতে এর দরকার ছিল না।
Ali1S232

2

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


1

আমরা একটি গেমে যা করেছি তা হ'ল নতুন স্থান নির্ধারণ

SomeEvent* obj = new(eventPool.alloc()) new SomeEvent();

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

আমাদের ইভেন্ট সিস্টেমটি যেভাবে কাজ করেছিল তার কারণে আমাদেরকে ইভটিংসে ডেস্ট্রাক্টরদের কল করার দরকার পড়েনি। সুতরাং পুলটি কেবল মেমরির ব্লককে নিখরচায় নিবন্ধভুক্ত করবে এবং এটি বরাদ্দ করবে।

এটি আমাদের বিশাল গতি দিয়েছে।

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

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