ওপেনজিএলে গেম লুপ তৈরির একটি ভাল উপায়


31

আমি বর্তমানে স্কুলে ওপেনজিএল শিখতে শুরু করেছি, এবং আমি অন্য দিন (নিজে থেকে, স্কুলের জন্য নয়) একটি সহজ খেলা তৈরি শুরু করেছি। আমি ফ্রিগ্লুট ব্যবহার করছি, এবং এটি সিতে তৈরি করছি, তাই আমার গেম লুপের জন্য আমি সত্যিই কেবল glutIdleFuncএকটি পাসে সমস্ত অঙ্কন এবং পদার্থবিজ্ঞানের আপডেট করতে পাস করেছি এমন একটি ফাংশন ব্যবহার করছি । এটি সরল অ্যানিমেশনগুলির জন্য ঠিক ছিল যে আমি ফ্রেমের হার সম্পর্কে খুব বেশি যত্ন নিই না, তবে যেহেতু গেমটি বেশিরভাগ পদার্থবিজ্ঞান ভিত্তিক, তাই আমি আপডেট করতে চাইছি (দ্রুততার সাথে) এটি বেঁধে দিতে চাই।

সুতরাং আমার প্রথম প্রয়াসটি ছিল আমার আগের ফাংশনটি আমি glutIdleFunc( myIdle()) এ পৌঁছে দিয়েছিলাম যে পূর্বের কলটি থেকে এটির জন্য কতটা সময় কেটে গেছে তার উপর নজর রাখা এবং পদার্থবিজ্ঞান (এবং বর্তমানে গ্রাফিক্স) প্রতি এত মিলি সেকেন্ডে আপডেট করুন। আমি timeGetTime()এটি (ব্যবহার করে <windows.h>) করতাম । এবং এটি আমাকে ভাবতে পেয়েছে, নিষ্ক্রিয় ফাংশনটি গেম লুপটি সম্পর্কে কী সত্যই ভাল ব্যবহার করা যায়?

আমার প্রশ্ন হ'ল ওপেনগিএলে গেম লুপটি প্রয়োগের আরও ভাল উপায় কী? নিষ্ক্রিয় ফাংশনটি ব্যবহার করা আমার এড়ানো উচিত?



আমি মনে করি এই প্রশ্নটি ওপেনজিএল-এর কাছে আরও নির্দিষ্ট এবং লুপের জন্য জিএলটি ব্যবহার করা যুক্তিযুক্ত কিনা
জেফ

1
এখানে মানুষ , বড় প্রকল্পগুলির জন্য GLUT ব্যবহার করবেন না । ছোটদের ক্ষেত্রে এটি ঠিক আছে।
bobobobo

উত্তর:


29

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

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

আমি এটির সেরা ব্যাখ্যা এবং টিউটোরিয়ালটি পেয়েছি হ'ল গ্লেন ফিডলার এর ফিক্স ইয়োর টাইমস্টেপ

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

// The amount of time we want to simulate each step, in milliseconds
// (written as implicit frame-rate)
timeDelta = 1000/30
timeAccumulator = 0
while ( game should run )
{
  timeSimulatedThisIteration = 0
  startTime = currentTime()

  while ( timeAccumulator >= timeDelta )
  {
    stepGameState( timeDelta )
    timeAccumulator -= timeDelta
    timeSimulatedThisIteration += timeDelta
  }

  stepAnimation( timeSimulatedThisIteration )

  renderFrame() // OpenGL frame drawing code goes here

  handleUserInput()

  timeAccumulator += currentTime() - startTime 
}

এটি এইভাবে করে, আপনার রেন্ডার কোড, ইনপুট হ্যান্ডলিং বা অপারেটিং সিস্টেমের স্টলগুলি আপনার গেমের রাজ্যের পিছনে পড়বে না। এই পদ্ধতিটি বহনযোগ্য এবং গ্রাফিক্স লাইব্রেরি স্বাধীন।

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

  • জিএলএফডাব্লু যা আপনাকে ইনপুট ইভেন্টগুলি ইনলাইন (আপনার নিজস্ব প্রধান লুপে) পাওয়ার ক্ষমতা দেয়।
  • এসডিএল , তবে এর জোর বিশেষভাবে ওপেনএল নয়।

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

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

1
অন্য কিছুর জন্য GLUT খননের জন্য +1 যতদূর আমি জানি, GLUT কখনই পরীক্ষামূলক অ্যাপ্লিকেশন ছাড়া আর কিছু নয়।
জারি কম্প্পা

আপনার এখনও সিস্টেম ইভেন্টগুলি পরিচালনা করতে হবে যদিও, না? আমার বোধগম্যতা ছিল যে glutIdleFunc ব্যবহার করে, এটি কেবল (উইন্ডোজে) গেটমেসেজ-ট্রান্সলেশনমেসেজ-ডিসপ্যাচমেসেজ লুপটি পরিচালনা করে এবং যখনই কোনও বার্তা পাওয়া যায় না তখন আপনার ফাংশনটি কল করে। আপনি যেভাবেই হোক না কেন এটি করবেন, না হলে আপনার অ্যাপ্লিকেশনটিকে প্রতিক্রিয়াহীন হিসাবে পতাকাঙ্কিত করতে ওএসের অধৈর্যতা ভোগ করবেন, তাই না?
রিকিট

@ রিকেট প্রযুক্তিগতভাবে, গ্লুটমেনলুপইভেন্ট () নিবন্ধিত কলব্যাকগুলিতে কল করে আগত ইভেন্টগুলি পরিচালনা করে। glutMainLoop () কার্যকরভাবে {glutMainLoopEvent (); IdleCallback (); } একটি কী বিবেচনা এখানে পুনরায় আঁকার হয় যে, এছাড়াও একটি কলব্যাক ঘটনা লুপ মধ্যে থেকে ঘাঁটা। আপনি করতে পারেন একটি সময় চালিত এক মত একটি ইভেন্ট চালিত গ্রন্থাগার আচরণ করতে, কিন্তু মাসলোর হাতুড়ি এবং যা ...
charstar

4

আমার মনে glutIdleFuncহয় ঠিক আছে; এটি মূলত যা আপনি হাতে ব্যবহার করেই শেষ করতে চান, যদি আপনি এটি ব্যবহার না করেন। আপনি কী আঁট লুপ যাচ্ছেন যা নির্দিষ্ট প্যাটার্নে ডাকা হয় না এবং আপনি এটি একটি নির্দিষ্ট সময়ের লুপে রূপান্তর করতে চান বা পরিবর্তনশীল-সময় লুপ রাখতে চান এবং তা তৈরি করতে হবে তা বিবেচনা করেই নয় অবশ্যই আপনার সমস্ত গণিত আন্তঃবিবাহ সময় জন্য অ্যাকাউন্ট। এমনকি এগুলির একটি মিশ্রণও একরকম।

আপনি অবশ্যই একটি myIdleফাংশন রাখতে পারেন যা আপনি পাস করেছেন glutIdleFuncএবং তার মধ্যে, যে সময়টি পেরিয়ে গেছে তা পরিমাপ করুন, এটি আপনার নির্দিষ্ট টাইমস্টেপ দ্বারা বিভক্ত করুন এবং অন্য কোনও ফাংশনকে বহুবার কল করুন।

না করার জন্য এখানে :

void myFunc() {
    // (calculate timeDifference here)
    int numOfTimes = timeDifference / 10;
    for(int i=0; i<numOfTimes; i++) {
        fixedTimestep();
    }
}

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

পরিবর্তে, এর মতো কিছু করুন:

long queuedMilliseconds; // static or whatever, this must persist outside of your loop

void myFunc() {
    // (calculate timeDifference here)
    queuedMilliseconds += timeDifference;
    while(queuedMilliseconds >= 10) {
        fixedTimestep();
        queuedMilliseconds -= 10;
    }
}

এখন এই লুপ কাঠামোটি নিশ্চিত করে যে আপনার fixedTimestepফাংশনটি প্রতি মিলি সেকেন্ডে একবারে কল হয়ে যাবে, কোনও মিলিসেকেন্ড বাদে বা এর মতো কিছু না হারিয়ে।

অপারেটিং সিস্টেমগুলির মাল্টিটাস্কিং প্রকৃতির কারণে আপনি প্রতি 10 মিলিসেকেন্ড হিসাবে ডাকা কোনও ফাংশনের উপর নির্ভর করতে পারবেন না; তবে উপরের লুপটি এত তাড়াতাড়ি ঘটবে যে আশা করা যায় এটি যথেষ্ট কাছাকাছি থাকবে এবং আপনি ধরে নিতে পারেন যে প্রতিটি কল fixedTimestepআপনার সিমুলেশনটি 10 ​​মিলিসেকেন্ডের মূল্য বাড়িয়ে তুলবে।

দয়া করে এই উত্তরটি এবং বিশেষত উত্তরে প্রদত্ত লিঙ্কগুলি পড়ুন।

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