При программировании анимации и небольших игр я осознал невероятную важность Thread.sleep (n );
Я полагаюсь на этот метод, чтобы сообщить операционной системе, когда моему приложению не потребуется ЦП, и с его помощью моя программа продвигается с предсказуемой скоростью.
Моя проблема в том, что JRE использует разные методы реализация этой функциональности в разных операционных системах. В ОС на основе UNIX (или под влиянием): например, Ubuntu и OS X, базовая реализация JRE использует хорошо работающую и точную систему для распределения процессорного времени между различными приложениями, что делает мою 2D-игру плавной и без задержек. Однако в Windows 7 и более старых системах Microsoft распределение времени ЦП, похоже, работает по-другому, и вы обычно получаете обратно свое время ЦП после заданного количества сна, которое варьируется примерно на 1-2 мс от целевого сна. Однако время от времени вы получаете дополнительные 10-20 мс времени сна. Это приводит к тому, что моя игра задерживается каждые несколько секунд, когда это происходит. Я заметил, что эта проблема существует в большинстве Java-игр, которые я пробовал в Windows, и Minecraft является ярким примером.
Теперь я искал в Интернете, чтобы найти решение этой проблемы. Я видел много людей, использующих только Thread.yield ();
вместо Thread.sleep (n);
, который работает безупречно за счет полной загрузки используемого в настоящее время ядра процессора, независимо от того, сколько процессора действительно требуется вашей игре. Это не идеально для игры на ноутбуках или рабочих станциях с высоким энергопотреблением, и это ненужный компромисс для систем Mac и Linux.
Оглядываясь дальше, я обнаружил обычно используемый метод исправления несоответствий времени сна, называемый «вращением». sleep », в котором вы заказываете засыпание только на 1 мс за раз и проверяете согласованность с помощью метода System.nanoTime ();
, который очень точен даже в системах Microsoft. Это помогает при нормальной непоследовательности сна 1-2 мс, но не поможет против случайных всплесков непостоянства сна + 10-20 мс, поскольку это часто приводит к тому, что на один цикл моего цикла тратится больше времени, чем на все вместе.
После множества поисков я нашел эту загадочную статью Энди Малакова, которая очень помогла мне улучшить мой цикл: http://andy-malakov.blogspot.com/2010/06/alternative-to-threadsleep. html
На основе его статьи я написал следующий метод сна:
// Variables for calculating optimal sleep time. In nanoseconds (1s = 10^-9ms).
private long timeBefore = 0L;
private long timeSleepEnd, timeLeft;
// The estimated game update rate.
private double timeUpdateRate;
// The time one game loop cycle should take in order to reach the max FPS.
private long timeLoop;
private void sleep() throws InterruptedException {
// Skip first game loop cycle.
if (timeBefore != 0L) {
// Calculate optimal game loop sleep time.
timeLeft = timeLoop - (System.nanoTime() - timeBefore);
// If all necessary calculations took LESS time than given by the sleepTimeBuffer. Max update rate was reached.
if (timeLeft > 0 && isUpdateRateLimited) {
// Determine when to stop sleeping.
timeSleepEnd = System.nanoTime() + timeLeft;
// Sleep, yield or keep the thread busy until there is not time left to sleep.
do {
if (timeLeft > SLEEP_PRECISION) {
Thread.sleep(1); // Sleep for approximately 1 millisecond.
}
else if (timeLeft > SPIN_YIELD_PRECISION) {
Thread.yield(); // Yield the thread.
}
if (Thread.interrupted()) {
throw new InterruptedException();
}
timeLeft = timeSleepEnd - System.nanoTime();
}
while (timeLeft > 0);
}
// Save the calculated update rate.
timeUpdateRate = 1000000000D / (double) (System.nanoTime() - timeBefore);
}
// Starting point for time measurement.
timeBefore = System.nanoTime();
}
SLEEP_PRECISION
Я обычно устанавливаю около 2 мс, а SPIN_YIELD_PRECISION
- примерно до 10 000 нс для лучшей производительности на моей машине с Windows 7.
После тонны тяжелой работы это лучшее, что я могу придумать. Итак, поскольку я все еще забочусь о повышении точности этого метода сна, и я все еще не удовлетворен производительностью, я хотел бы обратиться ко всем вам, хакерам и аниматорам java-игр, за предложениями по лучшему решению для Платформа Windows. Могу ли я использовать в Windows способ для конкретной платформы, чтобы улучшить его? Я не Я не забочусь о том, чтобы в моих приложениях был небольшой код, специфичный для платформы, при условии, что большая часть кода не зависит от ОС.
Я также хотел бы знать, есть ли кто-нибудь, кто знает о Microsoft и Oracle, разрабатывающих лучшую реализацию метод Thread.sleep (n);
, или каковы планы Oracle на будущее по улучшению своей среды как основы приложений, требующих высокой точности синхронизации, таких как музыкальное программное обеспечение и игры?
Спасибо всем за читая мой длинный вопрос / статью. Я надеюсь, что некоторые люди сочтут мое исследование полезным!