سؤال

أقوم ببناء لعبة ثلاثية الأبعاد من الصفر بلغة C++ باستخدام OpenGL وSDL على نظام Linux كهواية ومعرفة المزيد حول هذا المجال من البرمجة.

أتساءل عن أفضل طريقة لمحاكاة الوقت أثناء تشغيل اللعبة.من الواضح أن لدي حلقة تبدو كالتالي:

void main_loop()
{
    while(!quit)
    {
         handle_events();
         DrawScene();
         ...
         SDL_Delay(time_left());
    }
}

أنا أستخدم SDL_Delay وtime_left() للحفاظ على معدل إطارات يبلغ حوالي 33 إطارًا في الثانية.

كنت أعتقد أنني بحاجة فقط إلى بعض المتغيرات العالمية مثل

int current_hour = 0;
int current_min = 0;
int num_days = 0;
Uint32 prev_ticks = 0;

ثم وظيفة مثل:

void handle_time()
{
    Uint32 current_ticks;
    Uint32 dticks;
    current_ticks = SDL_GetTicks();
    dticks = current_ticks - prev_ticks; // get difference since last time

    // if difference is greater than 30000 (half minute) increment game mins
    if(dticks >= 30000) {
         prev_ticks = current_ticks;
         current_mins++;
         if(current_mins >= 60) {
            current_mins = 0;
            current_hour++;
         }
         if(current_hour > 23) {
            current_hour = 0;
            num_days++;
         }
    }
 }

ثم قم باستدعاء الدالة Handle_time() في الحلقة الرئيسية.

يتم تجميعه وتشغيله (باستخدام printf لكتابة الوقت إلى وحدة التحكم في الوقت الحالي) ولكني أتساءل عما إذا كانت هذه هي أفضل طريقة للقيام بذلك.هل هناك طرق أسهل أم طرق أكثر فعالية؟

هل كانت مفيدة؟

المحلول

ولقد ذكرت هذا من قبل في المواضيع الأخرى المتعلقة اللعبة. كما هو الحال دائما، اتبع الاقتراحات جلين فيدلر في لعبة الفيزياء سلسلة

وما تريد القيام به هو استخدام <م> خطوة زمنية ثابتة التي تحصل من خلال تجميع دلتا الوقت. إذا كنت تريد 33 تحديثات في الثانية، ثم خطوة زمنية ثابتة الخاص بك يجب أن تكون 1/33. يمكنك أيضا أن نسمي هذا <م> تردد التحديث . يجب عليك أيضا فصل منطق اللعبة من جعل لأنها لا تنتمي معا. كنت تريد أن تكون قادرة على استخدام تردد التحديث منخفض أثناء تقديم بأسرع ما تسمح للآلة. وفيما يلي بعض نموذج التعليمات البرمجية:

running = true;
unsigned int t_accum=0,lt=0,ct=0;
while(running){
    while(SDL_PollEvent(&event)){
        switch(event.type){
            ...
        }
    }
    ct = SDL_GetTicks();
    t_accum += ct - lt;
    lt = ct;
    while(t_accum >= timestep){
        t += timestep; /* this is our actual time, in milliseconds. */
        t_accum -= timestep;
        for(std::vector<Entity>::iterator en = entities.begin(); en != entities.end(); ++en){
            integrate(en, (float)t * 0.001f, timestep);
        }
    }
    /* This should really be in a separate thread, synchronized with a mutex */
    std::vector<Entity> tmpEntities(entities.size());
    for(int i=0; i<entities.size(); ++i){
        float alpha = (float)t_accum / (float)timestep;
        tmpEntities[i] = interpolateState(entities[i].lastState, alpha, entities[i].currentState, 1.0f - alpha);
    }
    Render(tmpEntities);
}

وهذا يعالج undersampling وكذلك الإفراط. إذا كنت تستخدم صحيح الحساب مثل القيام به هنا، يجب أن تكون الفيزياء اللعبة ما يقرب من 100٪ حتمية، بغض النظر عن مدى بطء أو سرعة الجهاز. هذا هو الاستفادة من زيادة الوقت في فترات زمنية ثابتة. يتم احتساب الدولة تستخدم لجعل من التحريف بين الدول السابقة والحالية، حيث يتم استخدام قيمة متبقية داخل تراكم الوقت كعامل الاستيفاء. هذا يضمن أن التقديم هو على نحو سلس، مهما كانت كبيرة وخطوة زمنية غير.

نصائح أخرى

وبخلاف القضايا أشرنا (يجب عليك استخدام هيكل لمرات وتمريرها إلى handle_time () ودقيقة الخاص بك سوف تحصل على يتزايد كل نصف دقيقة) الحل على ما يرام لتتبع إدارة الوقت في اللعبة.

ولكن، بالنسبة لمعظم أحداث اللعبة التي تحتاج إلى أن يحدث بين الحين والآخر ربما يجب عليك قاعدة لهم الخروج من اللعبة حلقة رئيسية بدلا من الوقت الفعلي ولذلك سوف يحدث في نفس النسب مع إطارا في الثانية مختلفة.

إحدى منشورات جلين التي سترغب حقًا في قراءتها هي أصلح خطوتك الزمنية!.وبعد البحث في هذا الرابط لاحظت ذلك جنون وجهتك إلى نفس المكان العام في بلده إجابة.

وأنا لست مطور لينكس، ولكن قد ترغب في إلقاء نظرة على استخدام مؤقتات بدلا من الاقتراع لالقراد.

http://linux.die.net/man/2/timer_create

تعديل:
SDL تبدو لدعم المدد الزمنية: SDL_SetTimer

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top