গেম লুপ, একবার কন্ডিশনের জন্য কীভাবে চেক করবেন, কিছু করুন, তারপরে আবার করবেন না


13

উদাহরণস্বরূপ, আমার একটি গেম ক্লাস রয়েছে এবং এটি intপ্লেয়ারের জীবনকে ট্র্যাক করে রাখে । আমার শর্তসাপেক্ষ আছে

if ( mLives < 1 ) {
    // Do some work.
}

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

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

এর সঠিক সমাধান কী (আমার উদাহরণের জন্য নয়, তবে সমস্যা ডোমেনের জন্য)? আপনি কিভাবে একটি খেলায় এটি করবেন?


উত্তরের জন্য ধন্যবাদ, আমার সমাধানটি এখন কেটিডিসকো এবং ক্র্যানক্র্যান উত্তরগুলির সংমিশ্রণ।
এডিভিভি 2323

উত্তর:


13

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

void subtractPlayerLife() {
    // Generic life losing stuff, such as mLives -= 1
    if (mLives < 1) {
        // Do specific stuff.
    }
}

এটি, পরিবর্তে, ধরে নেয় যে subtractPlayerLifeকেবলমাত্র নির্দিষ্ট উপলক্ষে ডাকা হবে, এটি সম্ভবত এমন পরিস্থিতিতে তৈরি হবে যে আপনাকে অবশ্যই প্রতিটি ফ্রেম পরীক্ষা করতে হবে (সংঘর্ষ, সম্ভবত)।

আপনার কোডটি কার্যকরভাবে কীভাবে কার্যকর করে তা নিয়ন্ত্রণ করে আপনি স্ট্যাটিক বুলিয়ানগুলির মতো নোংরা সমাধানগুলি এড়াতে পারবেন এবং একক ফ্রেমে কত কোড কার্যকর করা হবে তার বিট-বিট বিট কেটে ফেলতে পারবেন।

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

#define ONE_TIME_IF(condition, statement) \
    static bool once##__LINE__##__FILE__; \
    if(!once##__LINE__##__FILE__ && condition) \
    { \
        once##__LINE__##__FILE__ = true; \
        statement \
    }

যা নিম্নলিখিত কোড তৈরি করবে:

while (true) {
    ONE_TIME_IF(1 > 0,
        printf("something\n");
        printf("something else\n");
    )
}

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

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


সমাধান করা ভাল +1 এক সময়। অগোছালো, তবে দুর্দান্ত।
kender

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

1
@ গাজু এটি সত্য, শর্তটি পুনরায় সেট করা বা সংরক্ষণ করা দরকার হলে এটি একটি সমস্যা। আমি এটি স্পষ্ট করতে সম্পাদনা করেছি। এজন্যই আমি এটিকে একেবারে শেষ অবলম্বন হিসাবে বা কেবল ডিবাগ করার জন্য সুপারিশ করেছি।
কেভিনটোডিসকো 7'13

আমি কি (0) মূর্খতা দেওয়ার সময় suggest do করার পরামর্শ দিতে পারি? আমি জানি যে আমি ব্যক্তিগতভাবে কিছু স্ক্রু করতাম এবং সেমিকোলন রাখতাম যেখানে আমার উচিত ছিল না। দুর্দান্ত ম্যাক্রো যদিও, ব্র্যাভো।
michael.bartnett

5

এটি রাষ্ট্রীয় প্যাটার্নটি ব্যবহারের ক্লাসিক ক্ষেত্রে বলে মনে হচ্ছে। এক রাজ্যে আপনি আপনার জীবন যাপনের জন্য শর্তটি পরীক্ষা করেন <১। যদি এই শর্তটি সত্য হয়ে যায়, আপনি বিলম্বিত অবস্থায় রূপান্তর করুন। এই বিলম্বের অবস্থাটি নির্দিষ্ট সময়কালের জন্য অপেক্ষা করে এবং তারপরে আপনার প্রস্থান স্থিতিতে ট্রান্সজিশন করে।

সবচেয়ে তুচ্ছ পদ্ধতির মধ্যে:

switch(mCurrentState) {
  case LIVES_GREATER_THAN_0:
    if(lives < 1) mCurrentState = LIVES_LESS_THAN_1;
    break;
  case LIVES_LESS_THAN_1:
    timer.expires(5000); // expire in 5 seconds
    mCurrentState = TIMER_WAIT;
    break;
  case TIMER_WAIT:
    if(timer.expired()) mCurrentState = EXIT;
    break;
  case EXIT:
    mQuit = true;
    break;
}

আপনি স্টেটম্যানেজার / স্টেটম্যাচিনের সাথে স্টেট ম্যানেজার / স্টেটম্যাচিনের সাথে রাষ্ট্রের মধ্যে পরিবর্তন বা ধাক্কা / সংক্রমণকে স্যুইচ স্টেটমেন্টের পরিবর্তে ব্যবহার করার বিষয়ে বিবেচনা করতে পারেন।

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


1

আপনি যদি কর্মক্ষমতা সম্পর্কে চিন্তিত হন তবে একাধিকবার যাচাই করার কার্য সম্পাদন সাধারণত তাৎপর্যপূর্ণ নয়; বুল শর্ত থাকার জন্য ditto।

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

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

class SomeLevel {
  int numLives = 3;
  FooClass behaviour = new DoNothing();
  ...
  void tick() { 
    if (numLives < 1) {
      behaviour = new CallFoo();
    }

    behaviour.execute();
  }
}

এটি কিছুটা "কাঁচা" উদাহরণ; মূল বিষয়গুলি হ'ল:

  • FooClassকোনটি হতে পারে তার কোনও নজরে রাখুন DoNothingবা CallFoo। এটি একটি বেস শ্রেণি, বিমূর্ত শ্রেণি বা ইন্টারফেস হতে পারে।
  • সর্বদা executeসেই শ্রেণীর পদ্ধতিটি কল করুন ।
  • ডিফল্টরূপে, শ্রেণি কিছুই করে না ( DoNothingউদাহরণ)।
  • যখন জীবন শেষ হয়ে যায়, উদাহরণটি এমন কোনও উদাহরণের জন্য অদলবদল করা হয় যা আসলে কিছু করে ( CallFooউদাহরণ)।

এটি মূলত কৌশল এবং নাল নিদর্শনগুলির মিশ্রণের মতো।


তবে এটি প্রতিটি ফ্রেমকে নতুন কলফু () তৈরি করতে থাকবে, যা আপনাকে নতুনের আগে মুছতে হবে এবং সমস্যাটি স্থির করে না এমনটি ঘটতে থাকবে। উদাহরণস্বরূপ যদি আমার কলফু () কল করে এমন পদ্ধতিতে কল করত যা কয়েক সেকেন্ডের মধ্যে নির্বাহের জন্য টাইমার সেট করে, সেই টাইমারটি প্রতিটি ফ্রেম একই সময়ে সেট করা হত। যতদূর আমি আপনার সমাধানটি বলতে পারি ঠিক তেমনই (numLives <1) stuff // কর স্টাফ করুন} অন্য {// খালি}
এডিভিভি 23

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