Apakah ada salahnya menjalankan loop game utama tidak terkendali?


19

Saya bertanya-tanya apakah ada bahaya yang mungkin terjadi ketika loop game saya berjalan secepat sistem memungkinkan?

Saat ini saya memiliki loop, yang, dengan mengukur waktu yang berlalu dalam nanodetik, menjalankan logika game dan merender logika pada kecepatan yang telah ditentukan tanpa masalah. Faktanya, logika apa pun yang saya lakukan di loop adalah clock ke sejumlah panggilan setiap detik.

Loop itu sendiri meskipun hanya berjalan secepat yang suka yang muncul hingga sekitar 11,7 juta loop per detik di mesin saya.

Loop (kodesemu sederhana):

while(!isGameOver){

 if(canPollInputs){
    pollInputs()
 }

 while(canStepLogic){
    stepLogic()
 }

 if(canRender){
    render()
 }
}

Pertanyaan saya pada dasarnya adalah apakah loop sederhana itu, jika tidak berjalan pada kecepatan yang terkendali, dapat membahayakan sistem?

Sunting: Itu berarti logika saya berjalan 30 kali per detik (30 tps), penyaji saya berjalan pada 60 fps, saya mengumpulkan input 100 kali per detik dan ada juga beberapa logika untuk mengatasi logika atau membuat waktu lebih lama dari yang diharapkan . Tetapi loop itu sendiri tidak dibatasi.

Sunting: Menggunakan Thread.sleep()untuk contohnya Throttle loop utama ke 250 loop per detik mengarah ke pengurangan tetapi loop berjalan di sekitar 570 loop per detik, bukan 250 yang diinginkan (akan menambahkan kode ketika saya di mesin desktop saya ..)

Sunting: Ini dia, gameloop java yang berfungsi untuk mengklarifikasi hal-hal. Juga merasa bebas untuk menggunakannya tetapi jangan mengklaim itu milik Anda;)

private void gameLoop() {

    // Time that must elapse before a new run
    double timePerPoll = 1000000000l / targetPPS;
    double timePerTick = 1000000000l / targetTPS;
    double timePerFrame = 1000000000l / targetFPS;
    int maxFrameSkip = (int) ( (1000000000l / MINIMUM_FPS) / timePerTick);

    int achievedPPS = 0;
    int achievedFPS = 0;
    int achievedTPS = 0;

    long timer = TimeUtils.getMillis();

    int loops = 0;

    int achievedLoops = 0;

    long currTime = 0l;
    long loopTime = 0l;

    long accumulatorPPS = 0l;
    long accumulatorTPS = 0l;
    long accumulatorFPS = 0l;

    long lastTime = TimeUtils.getNano();

    while(!isRequestedToStop) {
        currTime = TimeUtils.getNano();
        loopTime = currTime - lastTime;
        lastTime = currTime;

        loops = 0;

        accumulatorPPS += loopTime;
        accumulatorTPS += loopTime;
        accumulatorFPS += loopTime;

        if(accumulatorPPS >= timePerPoll) {
            pollInputs();
            playerLogic();
            achievedPPS++;
            accumulatorPPS -= timePerPoll;
        }

        while(accumulatorTPS >= timePerTick && loops < maxFrameSkip) {
            tick();
            achievedTPS++;
            accumulatorTPS -= timePerTick;
            loops++;
        }

        // Max 1 render per loop so player movement stays fluent
        if(accumulatorFPS >= timePerFrame) {
            render();
            achievedFPS++;
            accumulatorFPS -= timePerFrame;
        }

        if(TimeUtils.getDeltaMillis(timer) > 1000) {
            timer += 1000;
            logger.debug(achievedTPS + " TPS, " + achievedFPS + " FPS, "
                    + achievedPPS + " Polls, " + achievedLoops + " Loops");
            achievedTPS = 0;
            achievedFPS = 0;
            achievedLoops = 0;
        }

        achievedLoops++;
    }
}

Seperti yang Anda lihat hampir tidak ada kode yang dijalankan pada setiap loop tetapi selalu ada pilihan tertentu berdasarkan berapa banyak waktu nyata telah berlalu. Pertanyaannya mengacu pada 'lingkaran pekerja' itu dan bagaimana hal itu memengaruhi sistem.


2
tautan wajib 'perbaiki tanda waktu Anda': gafferongames.com/game-physics/fix-your-timestep, harap baca. Perhatikan juga bahwa Thread.Sleep () tidak dapat digunakan untuk membatasi waktu Anda dengan andal karena OS tidak menjamin untuk mengembalikan kontrol ke aplikasi Anda setelah jumlah waktu yang diminta. (Ini mungkin bervariasi).
Roy T.

Ya, itulah masalah dengan kodesemu. Saya melakukan sebagian besar apa yang ditulis gaffer (saat ini bekerja pada implementasi delta yang melengkapi struktur loop saya). Jika saya tidak dapat menggunakan Thread.sleep () lalu apa lagi yang tersedia dalam Java standar?
dot_Sp0T

1
Anda biasanya menggunakan loop sibuk dengan Thread.Sleep (0) dan berharap yang terbaik. Gaffer banyak membicarakan hal ini dalam beberapa artikel.
Roy T.

Yah itulah dasarnya yang telah saya lakukan, hanya tanpa utas. Tidur (0), DAN apa yang awalnya memicu pertanyaan ini. Apakah ada salahnya di loop sibuk (resp tidak sibuk karena bahkan logika berulang kecil diperketat) untuk sistem?
dot_Sp0T

Beberapa waktu yang lalu, bug menyebabkan Starcraft II melakukan ini dalam kondisi tertentu. Akhirnya benar-benar melelehkan beberapa GPU. Jadi ya, sangat mungkin loop game yang tidak terkontrol menyebabkan kerusakan.
Mason Wheeler

Jawaban:


35

Ini akan menyebabkan satu inti CPU untuk selalu berjalan pada 100%. Ini biasanya tidak menyebabkan kerusakan pada sistem. CPU dirancang untuk beroperasi pada 100% selama berjam-jam. Tetapi pada perangkat seluler itu akan menghabiskan baterai dengan cepat dan memanaskan perangkat, yang kemungkinan akan membebani Anda dengan bintang di peringkat toko Anda. Pada komputer desktop, ini bukan masalah, tetapi akan mengkonsumsi lebih banyak listrik pengguna, menyebabkan kipas CPU berputar lebih cepat yang mungkin menyebabkan beberapa kebisingan dan buang siklus CPU yang seharusnya dapat digunakan oleh proses lain. Meskipun ini bukan cacat kritis, itu masih gaya yang buruk, jadi Anda harus menghindarinya jika memungkinkan.

Anda tidak mengatakan apa-apa tentang bagaimana loop logika game Anda bekerja secara internal, tetapi ketika Anda menggunakan pendekatan delta-waktu (setiap perhitungan yang Anda lakukan membutuhkan waktu sejak panggilan terakhir ke akun), Anda berhadapan dengan delta yang sangat kecil. nilai waktu. Ini berarti Anda dapat mengalami masalah dengan ketidaktepatan floating-point yang dapat menyebabkan semua jenis perilaku aneh. Juga, resolusi dari pengatur waktu sistem seringkali terbatas, jadi ketika loop logika Anda terlalu cepat, Anda bisa mendapatkan nilai delta-t dari nol, yang kemudian dapat menyebabkan pembagian dengan nol yang mengakibatkan crash.

Untuk mengurangi masalah ini, Anda harus membatasi framerate Anda (grafik dan logika) hingga maksimum dari apa yang dapat dilihat mata manusia. Berapa banyak yang diperdebatkan dan tergantung pada jenis animasi dan pada jenis tampilan yang ditampilkan, tetapi perkiraan berkisar dari 40 FPS hingga 120 FPS. Itu berarti Anda perlu mengatur waktu minimum eksekusi setiap loop antara 20 ms dan 8 ms. Jika pengulangan selesai lebih cepat, biarkan utas cpu sleepuntuk sisa waktu yang tersisa.


Terima kasih untuk penjelasannya Philipp. Sebenarnya saya merujuk pada fakta bahwa saya menjalankan fps dan tps tertentu serta melakukan polling hanya beberapa kali dalam satu detik. Akan mencoba membuatnya lebih jelas.
dot_Sp0T

@ dot_Sp0T Setelah Anda mengedit pertanyaan Anda, hanya paragraf pertama dan kalimat terakhir yang relevan dengan kasus Anda. Namun, saya ingin mempertahankan paragraf kedua dan ketiga dari jawaban saya karena mungkin bermanfaat bagi orang lain.
Philipp

Saya mungkin akan menerima jawaban Anda karena paragraf pertama memberikan jawaban dengan baik. Apakah Anda keberatan untuk secara visual membedakannya dari sisa jawaban?
dot_Sp0T

Mainkan Peradaban 2 yang belum ditonton di desktop dan Anda akan mendapati itu sebagai masalah. Setidaknya saya lakukan. mengangkat bahu
corsiKa

1
Selain pertimbangan baterai dan kipas, peningkatan penggunaan CPU dapat menyebabkan panas berlebih yang dapat menjadi tidak nyaman (misalnya laptop, khususnya rMBP) dan bahkan menyebabkan PC mati (khususnya PC lama dengan pendingin berdebu). Faktor-faktor ini jengkel jika Anda menjalankan semua core 100%.
NPSF3000

2

Anda membuang-buang siklus CPU. Itu berarti waktu baterai lebih rendah pada notebook, tablet dan telepon, tagihan listrik yang lebih tinggi, lebih banyak panas yang dihasilkan oleh mesin, kipas yang lebih berisik. Juga, Anda mungkin makan siklus dari proses sistem penting lainnya (misalnya server jendela bisa menjadi tersentak-sentak), yang kemudian dapat mempengaruhi gameplay. Beberapa penjadwal sistem pada sistem multitasking pre-emptive hari ini juga menghukum aplikasi yang menggunakan terlalu banyak siklus, sehingga Anda mungkin cepat terlebih dahulu, lalu tiba-tiba melihat keheranan aneh ketika Anda dicekik oleh sistem.

Banyak gamer hardcore juga membuat PC khusus dari awal yang berada di ujung spesifikasi penggemar mereka, dalam hal ini hari yang panas dan panas yang dihasilkan gim Anda dapat menyebabkan keselamatan terpicu di dalam mesin (paling-paling) atau bahkan membuat bagian terlalu panas dan mati (paling buruk). Jadi jika itu target audiens Anda, Anda mungkin ingin memastikan Anda selalu meninggalkan sedikit ruang "di atas".

Akhirnya, ada masalah gameplay di mana Anda mungkin menguntungkan pemain dengan mesin lebih cepat daripada yang lebih lambat. Memiliki loop game dibatasi pada frekuensi tertentu dan menggunakan siklus tambahan semata-mata untuk aspek yang tidak relevan dengan gameplay (seperti rendering grafik kesetiaan yang lebih tinggi, efek suara surround atau apa pun) akan membuat game Anda lebih adil.


Saya akan mengatakan sebaliknya orang yang dengan penuh semangat membangun mesin mereka menggunakan penggemar yang baik, bahkan pendingin air. Hanya kasus HTPC atau mini ITX yang memiliki batasan pada bagian itu. Kalau tidak, orang miskin tetapi penggemar akan menggunakan kotak ventirad. yang bahkan cukup pada 100%, panas tapi ok.
v.oddou

Saya hanya mengulang dari pengalaman. Jika Anda melihat Star Trek Online, mereka sebenarnya memiliki pengaturan terpisah di GUI mereka yang akan memasukkan sleep () dalam loop utama mereka untuk menjaga mesin tertentu dari panas berlebihan, sehingga tidak bisa menjadi hal yang tidak biasa jika pembuat Neverwinter dan STO melihat kebutuhan untuk menambahkannya. Ingatlah gairah itu! = Keterampilan. Ada banyak penggerutu yang terampil dan bersemangat, tetapi ada juga pemula dan lainnya yang masih belajar, dan dengan tingkat drop-out yang layak, statistik mengatakan mereka mayoritas.
uliwitness

Berkat komentar ini, saya datang untuk membaca kembali jawaban Anda. Anda mendaftar poin yang valid tetapi sayangnya tidak benar-benar menjawab pertanyaan dengan kontroversi mesin yang lebih cepat vs mesin yang lebih lambat . The logika lingkaran (disebut gameloop pada ayat ketiga Anda) dibatasi. Pertanyaannya adalah tentang membatasi loop backbone yang hanya mengevaluasi ulang setiap kali dijalankan jika input harus ditarik, logika dihitung atau bingkai harus dirender - jadi tidak ada logika yang lebih cepat kecuali mesin Anda sangat lumpuh
dot_Sp0T

1

Anda seharusnya tidak memiliki gerakan / gameplay yang gelisah

Ada dua cara untuk menerapkan logika game - terikat ke waktu nyata, atau dikaitkan dengan jumlah "putaran" / langkah pemrosesan. Jika sesuatu dalam gim Anda bergerak ke kiri, apakah gerakannya akan berbeda jika stepLogic Anda () dipanggil 100 bukannya 50 kali?

Jika kode Anda memperlakukan waktu yang telah berlalu secara eksplisit di mana-mana dan melakukannya dengan benar, maka mungkin tidak apa-apa; tetapi jika ada sesuatu dalam kode Anda yang tergantung pada jumlah 'langkah' maka Anda akan mendapatkan efek samping yang tidak diinginkan.

Pertama, kecepatan benda-benda yang harus bergerak terus-menerus akan bervariasi tidak dapat diprediksi (tergantung pada penggunaan prosesor), dan ini membuat kontrol yang sangat menjengkelkan - Anda tidak dapat membuat pukulan atau lompatan yang tepat jika tiba-tiba permainan mempercepat atau memperlambat. Bahkan untuk game tanpa 'kedutan' sama sekali, itu terlihat menjengkelkan dan gelisah jika segalanya tidak berjalan lancar.

Kedua, Anda mungkin mendapatkan masalah dengan kemampuan karakter tergantung pada kecepatan komputer - contoh klasik adalah masalah Quake lama di mana rentang lompatan maksimum secara tidak sengaja tergantung pada fps Anda.

Masalah ini dapat muncul bahkan jika Anda mencoba untuk membuat kode menjadi fps-independent, akumulasi kesalahan pembulatan sering dapat menyebabkan bug seperti itu.


1
Sebanyak yang saya suka jawaban Anda tidak relevan dengan pertanyaan, karena saya tidak bertanya tentang gerakan gelisah / gameplay tetapi tentang bahaya loop yang tidak terkendali (yang tidak mengontrol logika atau render atau apa pun) dapat dilakukan untuk sistem
dot_Sp0T

1

Satu-satunya potensi bahaya adalah konsumsi daya Anda, jadi jangan lakukan ini pada perangkat seluler. Sebaliknya, beberapa sistem embedded menghabiskan seluruh hidup mereka dalam satu lingkaran menunggu hal-hal terjadi.

Dulu sepenuhnya normal untuk hanya membuat frame game secepat mungkin, kadang-kadang bahkan tanpa timer untuk mengimbangi gameplay untuk kecepatan CPU yang berbeda. Game balap Bullfrog, Hi-Octane adalah korban yang sangat buruk dalam hal ini, dan saya menduga inilah yang disebut oleh poster yang menyebutkan Civ2.

Saya akan menyarankan Anda untuk setidaknya memasukkan input pada setiap pass jika Anda menggunakan sistem Windows atau yang sejenis, untuk memastikan respons input yang tajam.


Ini bukan soal timer, ini pertanyaan tentang kronometer yang saya lebih suka katakan, atau penghitung kinerja. Orang perlu mendapatkan waktu nyata di beberapa titik, dan loop gratis berfungsi dengan baik. Namun timer (dalam arti gangguan reguler) berusaha untuk mengatur kecepatan loop dalam penggunaan umum. Saya tidak menganggap ini bagus. Lebih baik menggunakan fungsi swap/ present/ fliplakukan menunggu sinyal vsync, untuk mengatur loop game.
v.oddou
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.