นอกเหนือจากคำตอบของ Journeyman Geek (เพราะการแก้ไขของฉันถูกปฏิเสธ) สำหรับผู้ที่สนใจในส่วนของการเข้ารหัส / มุมมองของนักพัฒนา:
จากมุมมองของโปรแกรมเมอร์สำหรับผู้ที่สนใจเวลา DOS เป็นช่วงเวลาที่ขีดของ CPU ทุกตัวมีความสำคัญดังนั้นโปรแกรมเมอร์จึงเก็บรหัสไว้อย่างรวดเร็วที่สุด
สถานการณ์โดยทั่วไปที่โปรแกรมใด ๆ จะทำงานด้วยความเร็วซีพียูสูงสุดนั้นง่าย (หลอก C):
int main()
{
while(true)
{
}
}
สิ่งนี้จะทำงานตลอดไปทีนี้มาเปลี่ยนโค้ดขนาดนี้เป็นเกมหลอก - DOS:
int main()
{
bool GameRunning = true;
while(GameRunning)
{
ProcessUserMouseAndKeyboardInput();
ProcessGamePhysics();
DrawGameOnScreen();
//close game
if(Pressed(KEY_ESCAPE))
{
GameRunning = false;
}
}
}
นอกเสียจากว่าDrawGameOnScreen
ฟังก์ชั่นนั้นจะใช้การบัฟเฟอร์คู่ / V-sync (ซึ่งค่อนข้างแพงในสมัยที่เกม DOS ถูกสร้างขึ้น) เกมจะทำงานด้วยความเร็ว CPU สูงสุด ในวันที่ทันสมัย i7 มือถือนี้จะทำงานที่ประมาณ 1,000,000 ถึง 5,000,000 ครั้งต่อวินาที (ขึ้นอยู่กับการกำหนดค่าแล็ปท็อปและการใช้ซีพียูปัจจุบัน)
นี่หมายความว่าถ้าฉันสามารถทำให้เกม DOS ใดทำงานบน CPU ที่ทันสมัยของฉันใน windows 64 บิตของฉันฉันจะได้รับมากกว่าหนึ่งพัน (1,000!) FPS ซึ่งเร็วเกินไปสำหรับมนุษย์ที่จะเล่นถ้าการประมวลผลทางฟิสิกส์ "ถือว่า" มันทำงาน ระหว่าง 50-60 fps
สิ่งที่ผู้พัฒนาในปัจจุบันสามารถทำได้คือ:
- เปิดใช้งาน V-Sync ในเกม (* ไม่สามารถใช้ได้กับแอปพลิเคชันที่มีหน้าต่าง ** [aka มีเฉพาะในแอปแบบเต็มหน้าจอ])
- วัดความแตกต่างของเวลาระหว่างการอัปเดตครั้งล่าสุดและอัปเดตฟิสิกส์ตามความแตกต่างของเวลาซึ่งทำให้เกม / โปรแกรมทำงานที่ความเร็วเดียวกันโดยไม่คำนึงถึงอัตรา FPS
- จำกัด อัตราเฟรมโดยทางโปรแกรม
*** ขึ้นอยู่กับกราฟิกการ์ด / ขับ / การกำหนดค่าระบบปฏิบัติการมันอาจจะเป็นไปได้
สำหรับจุดที่ 1 ไม่มีตัวอย่างที่ฉันจะแสดงเพราะไม่ใช่ "การเขียนโปรแกรม" จริงๆ เป็นเพียงการใช้คุณสมบัติกราฟิก
สำหรับจุดที่ 2 และ 3 ฉันจะแสดงตัวอย่างโค้ดและคำอธิบายที่เกี่ยวข้อง:
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;
}
}
}
ที่นี่คุณสามารถเห็นการป้อนข้อมูลของผู้ใช้และฟิสิกส์คำนึงถึงความแตกต่างของเวลา แต่คุณยังสามารถรับหน้าจอมากกว่า 1,000 FPS บนหน้าจอได้เนื่องจากการวนซ้ำทำงานเร็วที่สุด เนื่องจากเอ็นจิ้นฟิสิกส์รู้ว่าเวลาผ่านไปนานเท่าไรจึงไม่จำเป็นต้องพึ่งพา "ไม่มีข้อสันนิษฐาน" หรือ "อัตราเฟรมที่แน่นอน" ดังนั้นเกมจะทำงานด้วยความเร็วเท่ากันใน cpu ใด ๆ
3:
สิ่งที่นักพัฒนาสามารถทำได้เพื่อ จำกัด อัตราเฟรมตัวอย่างเช่น 30 FPS จริง ๆ แล้วไม่มีอะไรยากขึ้นมาลองดู:
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;
}
}
}
สิ่งที่เกิดขึ้นที่นี่คือโปรแกรมนับจำนวนมิลลิวินาทีที่ผ่านไปหากถึงจำนวนหนึ่ง (33 มิลลิวินาที) จากนั้นจะวาดหน้าจอเกมใหม่โดยใช้อัตราเฟรมใกล้ ~ 30
นอกจากนี้ยังขึ้นอยู่กับนักพัฒนาที่เขา / เธออาจเลือกที่จะ จำกัด การประมวลผลทั้งหมดที่ 30 fps ด้วยรหัสข้างต้นแก้ไขเล็กน้อยในเรื่องนี้:
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;
}
}
}
}
มีวิธีอื่นสองสามอย่างและบางคนก็เกลียดฉันจริงๆ
sleep(<amount of milliseconds>)
ตัวอย่างเช่นการใช้
ฉันรู้ว่านี่เป็นวิธีหนึ่งในการ จำกัด อัตราเฟรม แต่จะเกิดอะไรขึ้นเมื่อการประมวลผลเกมของคุณใช้เวลา 3 มิลลิวินาทีหรือมากกว่า แล้วคุณจะนอนหลับ ...
สิ่งนี้จะส่งผลให้มีอัตราเฟรมที่ต่ำกว่าที่sleep()
ควรเป็นสาเหตุเท่านั้น
ตัวอย่างเช่นใช้เวลาพักเครื่อง 16 มิลลิวินาที สิ่งนี้จะทำให้โปรแกรมทำงานที่ 60 เฮิร์ตซ์ ตอนนี้การประมวลผลข้อมูลอินพุตการวาดและทุกสิ่งใช้เวลา 5 ไมล์ เราอยู่ที่ 21 ไมล์ต่อวินาทีสำหรับหนึ่งวงตอนนี้ซึ่งส่งผลให้น้อยกว่า 50 เฮิร์ตซ์เล็กน้อยในขณะที่คุณสามารถอยู่ที่ 60 เฮิร์ตซ์ได้ง่าย แต่เพราะการนอนหลับมันเป็นไปไม่ได้
ทางออกหนึ่งคือการทำให้การนอนหลับแบบปรับตัวในรูปแบบของการวัดเวลาการประมวลผลและการหักเวลาการประมวลผลจากการนอนหลับที่ต้องการส่งผลในการแก้ไข "ข้อผิดพลาด" ของเรา:
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);
}
}
}