Sebagai tambahan untuk jawaban Journeyman Geek (karena hasil edit saya ditolak) untuk orang-orang yang tertarik pada bagian pengkodean / perspektif pengembang:
Dari perspektif programmer, bagi mereka yang tertarik, waktu DOS adalah waktu di mana setiap centang CPU sangat penting sehingga programmer menyimpan kode secepat mungkin.
Skenario khas di mana program mana pun akan berjalan pada kecepatan CPU maks adalah ini sederhana (pseudo C):
int main()
{
while(true)
{
}
}
ini akan berjalan selamanya, sekarang, mari kita ubah snipet kode ini menjadi pseudo-DOS-game:
int main()
{
bool GameRunning = true;
while(GameRunning)
{
ProcessUserMouseAndKeyboardInput();
ProcessGamePhysics();
DrawGameOnScreen();
//close game
if(Pressed(KEY_ESCAPE))
{
GameRunning = false;
}
}
}
kecuali DrawGameOnScreen
fungsi menggunakan buffering ganda / V-sync (yang agak mahal di hari-hari ketika game DOS dibuat), game akan berjalan pada kecepatan CPU maksimum. Pada ponsel modern i7 ini akan berjalan sekitar 1.000.000 hingga 5.000.000 kali per detik (tergantung pada konfigurasi laptop dan penggunaan cpu saat ini).
Ini berarti bahwa jika saya bisa membuat game DOS bekerja pada CPU modern saya di windows 64bit saya, saya bisa mendapatkan lebih dari seribu (1000!) FPS yang terlalu cepat untuk dimainkan manusia jika proses fisika "mengasumsikan" itu berjalan antara 50-60 fps.
Apa yang dilakukan pengembang saat ini adalah:
- Aktifkan V-Sync di dalam game (* tidak tersedia untuk aplikasi berjendela ** [alias hanya tersedia di aplikasi layar penuh])
- Ukur perbedaan waktu antara pembaruan terakhir dan perbarui fisika sesuai dengan perbedaan waktu yang secara efektif membuat game / program berjalan pada kecepatan yang sama terlepas dari tingkat FPS
- Batasi framerate secara terprogram
*** tergantung pada konfigurasi kartu grafis / driver / os itu mungkin menjadi mungkin.
Untuk poin 1 tidak ada contoh yang akan saya tunjukkan karena sebenarnya tidak ada "pemrograman". Hanya menggunakan fitur grafis.
Sedangkan untuk poin 2 dan 3 saya akan menunjukkan cuplikan dan penjelasan kode yang sesuai:
2:
int main()
{
bool GameRunning = true;
long long LastTick = GetCurrentTime();
long long TimeDifference;
while(GameRunning)
{
TimeDifference = GetCurrentTime()-LastTick;
LastTick = GetCurrentTime();
//process movement based on how many time passed and which keys are pressed
ProcessUserMouseAndKeyboardInput(TimeDifference);
//pass the time difference to the physics engine so it can calculate anything time-based
ProcessGamePhysics(TimeDifference);
DrawGameOnScreen();
//close game if escape is pressed
if(Pressed(KEY_ESCAPE))
{
GameRunning = false;
}
}
}
Di sini Anda dapat melihat input pengguna dan fisika memperhitungkan perbedaan waktu, namun Anda masih bisa mendapatkan 1000+ FPS di layar karena loop berjalan secepat mungkin. Karena mesin fisika tahu berapa lama waktu berlalu, itu tidak harus bergantung pada "tidak ada asumsi" atau "framerate tertentu" sehingga permainan akan bekerja pada kecepatan yang sama pada cpu apa pun.
3:
Apa yang dapat dilakukan pengembang untuk membatasi framerate, misalnya, 30 FPS sebenarnya tidak lebih sulit, lihat saja:
int main()
{
bool GameRunning = true;
long long LastTick = GetCurrentTime();
long long TimeDifference;
double FPS_WE_WANT = 30;
//how many milliseconds need to pass before we need to draw again so we get the framerate we want?
double TimeToPassBeforeNextDraw = 1000.0/FPS_WE_WANT;
//For the geek programmers: note, this is pseudo code so I don't care for variable types and return types..
double LastDraw = GetCurrentTime();
while(GameRunning)
{
TimeDifference = GetCurrentTime()-LastTick;
LastTick = GetCurrentTime();
//process movement based on how many time passed and which keys are pressed
ProcessUserMouseAndKeyboardInput(TimeDifference);
//pass the time difference to the physics engine so it can calculate anything time-based
ProcessGamePhysics(TimeDifference);
//if certain amount of milliseconds pass...
if(LastTick-LastDraw >= TimeToPassBeforeNextDraw)
{
//draw our game
DrawGameOnScreen();
//and save when we last drawn the game
LastDraw = LastTick;
}
//close game if escape is pressed
if(Pressed(KEY_ESCAPE))
{
GameRunning = false;
}
}
}
Apa yang terjadi di sini adalah bahwa program menghitung berapa milidetik yang telah berlalu, jika jumlah tertentu tercapai (33 ms) maka ia menggambar ulang layar permainan, secara efektif menerapkan frame rate mendekati ~ 30.
Juga, tergantung pada pengembangnya, ia dapat memilih untuk membatasi SEMUA pemrosesan hingga 30 fps dengan kode di atas sedikit dimodifikasi untuk ini:
int main()
{
bool GameRunning = true;
long long LastTick = GetCurrentTime();
long long TimeDifference;
double FPS_WE_WANT = 30;
//how many miliseconds need to pass before we need to draw again so we get the framerate we want?
double TimeToPassBeforeNextDraw = 1000.0/FPS_WE_WANT;
//For the geek programmers: note, this is pseudo code so I don't care for variable types and return types..
double LastDraw = GetCurrentTime();
while(GameRunning)
{
LastTick = GetCurrentTime();
TimeDifference = LastTick-LastDraw;
//if certain amount of miliseconds pass...
if(TimeDifference >= TimeToPassBeforeNextDraw)
{
//process movement based on how many time passed and which keys are pressed
ProcessUserMouseAndKeyboardInput(TimeDifference);
//pass the time difference to the physics engine so it can calculate anything time-based
ProcessGamePhysics(TimeDifference);
//draw our game
DrawGameOnScreen();
//and save when we last drawn the game
LastDraw = LastTick;
//close game if escape is pressed
if(Pressed(KEY_ESCAPE))
{
GameRunning = false;
}
}
}
}
Ada beberapa metode lain, dan beberapa di antaranya benar-benar saya benci.
Misalnya, menggunakan sleep(<amount of milliseconds>)
.
Saya tahu ini adalah salah satu metode untuk membatasi framerate, tetapi apa yang terjadi ketika pemrosesan gim Anda membutuhkan 3 milidetik atau lebih? Dan kemudian Anda menjalankan tidur ...
ini akan menghasilkan framerate yang lebih rendah daripada yang sleep()
seharusnya hanya menyebabkan.
Sebagai contoh, mari kita ambil waktu tidur 16 ms. ini akan membuat program berjalan pada 60 hz. sekarang pemrosesan data, input, gambar dan semua hal membutuhkan waktu 5 milidetik. kami berada di 21 milidetik untuk satu putaran sekarang yang menghasilkan sedikit kurang dari 50 hz, sementara Anda dapat dengan mudah masih berada di 60 hz tetapi karena tidur tidak mungkin.
Salah satu solusinya adalah membuat tidur adaptif dalam bentuk mengukur waktu pemrosesan dan mengurangi waktu pemrosesan dari tidur yang diinginkan sehingga memperbaiki "bug" kami:
int main()
{
bool GameRunning = true;
long long LastTick = GetCurrentTime();
long long TimeDifference;
long long NeededSleep;
while(GameRunning)
{
TimeDifference = GetCurrentTime()-LastTick;
LastTick = GetCurrentTime();
//process movement based on how many time passed and which keys are pressed
ProcessUserMouseAndKeyboardInput(TimeDifference);
//pass the time difference to the physics engine so it can calculate anything time-based
ProcessGamePhysics(TimeDifference);
//draw our game
DrawGameOnScreen();
//close game if escape is pressed
if(Pressed(KEY_ESCAPE))
{
GameRunning = false;
}
NeededSleep = 33 - (GetCurrentTime()-LastTick);
if(NeededSleep > 0)
{
Sleep(NeededSleep);
}
}
}