Можно ли создать 2 цикла в javascript, где один цикл будет иметь приоритет в случае недостатка ресурсов?(Оба обрабатывают тики игры)

Проблема как таковая:

В многопользовательской игре на основе js и asm.js у меня есть две петли.

Один обрабатывает фактические игровые тики, такие как положение юнита, скорость и бой.

Другой обрабатывает рендеринг этого мира на холст, чтобы пользователь мог его увидеть.

Я хотел бы, чтобы процессор /GPU(они делали то же самое на некоторых машинах сейчас, не могу сказать, что я этому рад) слишком сильно перегружен, и цикл рендеринга должен пропустить и, таким образом, прекратить изменять холст. Т.е. замораживание игрового экрана в лаге щуки.

Между тем, оставшаяся небольшая вычислительная мощность используется для успешного завершения реального тика игры, предотвращая рассинхронизацию с другими игровыми клиентами.

(Это RTS-подобная игра, когда дело доходит до загрузки, поэтому пользовательский ввод вместо позиций всех объектов передается по сети).

В противном случае клиент должен был бы быть выгнан другими клиентами, или все клиенты должны были бы сделать паузу для его повторного подключения и повторной синхронизации. т.е. плохо плохо плохо!

Неаккуратный импровизированный способ сделать это, вероятно, заключался бы в использовании временных меток и прекращении графического цикла, если он не будет завершен к определенному времени. Можно предположить, что это можно сделать, определив максимальное время выполнения для типов пакетов в стеке цикла, и немедленно прервите цикл, если "время выполнения значения" всех пакетов вместе слишком велико, чтобы иметь дело с пропускной способностью ресурса временными метками указывают на замедление измерения. Черт, может быть, это радикально, но, возможно, даже пропустить прерывание графического цикла, когда любое замедление обнаружено только для того, чтобы избежать рассинхронизации.

Таким образом, приоритет над одним циклом над другим (оба обрабатывают тики) и заставляет второй пропускать, если обнаруживается нехватка ресурсов, чтобы гарантировать, что первый цикл всегда завершает свой тик в течение каждого таймфрейма (здесь 10 тиков в секунду).

Ребята, можете ли вы рассказать мне о каких-либо возможностях или методах лучшей практики?

РЕДАКТИРОВАТЬ: Сосредоточьтесь на способности измерять доступность ресурсов ЦП и пропуск / завершение для одного такта графического цикла, если эти ресурсы не будут доступны достаточно для завершения обоих циклов (то есть, если циклы не завершатся через 100 мс после какой тик следующего цикла уже должен запускаться, не запускайте / не прекращайте графический цикл).

2 ответа

Одним из решений будет использование веб-работника для выполнения цикла обновления мира, а затем обычного цикла JavaScript для рендеринга. Вам нужно будет передать состояние обратно и прямо из веб-работника, но цикл рендеринга будет опираться только на обновленные данные.

Преимущество состоит в том, что у вас все еще может быть реакционный код отображения в основном цикле пользовательского интерфейса.

Это также имеет то преимущество, что веб-работник может использовать другое ядро, а с несколькими веб-работниками вы можете использовать несколько дополнительных ядер.

Для логического цикла я бы взял setInterval и для краски - requestAnimationFrame, И даже больше - обратный вызов в requestAnimationFrame также получает временную метку, так что вы можете отслеживать временные метки и пропускать один кадр, если возникает некоторая нехватка.


процессор может выполнять другие задачи, а также отображать анимацию

Это утверждение неверно - процессор может обрабатывать только одну задачу, и requestAnimationFrame на самом деле это не рендеринг, это ваш обратный вызов - общий javascript. Вы можете думать об этом как setTimeout, Единственное отличие состоит в том, что он пытается выполнить обратный вызов на следующем кадре свободной частоты кадров. Вот почему это намного лучше, чем setTimeout, Так что для анимации вы должны использовать requestAnimationFrame, Другая хорошая часть об этом, когда веб-страница находится в фоновом режиме (другая вкладка открыта). Тогда обратный вызов не будет вызван, пока он не выйдет на передний план. Это экономит время процессора, так как в этом обратном вызове ничего не вычисляется.

Возвращаясь к вашему вопросу: вы сейчас, но, что за один раз может быть обработан только один обратный вызов, поэтому, если процессор в определенное время занят логической функцией, обратный вызов цикла анимации не будет запущен. В этом случае это называется "отставание". Но, как я понял, это действительно желаемое поведение - дать функции логического обратного вызова больше времени. Но есть и другая сторона. Что если ваша анимационная функция занята, когда пришло время для логической функции? В этом случае он будет запущен только после завершения функции анимации. С этим ничего не поделаешь. Если ваша функция анимации "тяжелая", вы можете попытаться разделить ее только на 2 кадра. Один кадр - подготовить все для рендера, второй - рендер.

Но в любом случае, вы никогда не станете идеальным интервалом или тайм-аутом в миллисекундах в javascript. Как его хочется вызывать до тех пор, пока событие-цикл не станет свободным. Чтобы получить идею:

var seconds = 0;
setInterval(function(){ seconds++; var x = 10e8; while(--x); }, 1000);

Зависит от вашего процессора, но через 10 секунд переменная 'seconds' будет намного меньше 10.

И еще одна вещь, если вы действительно полагаетесь на время, тогда безопаснее использовать Date.now() для синхронизации следующего логического тика:

var setLogicalLoop = (function(){

    var _startedAt,
        _stop,
        _ms;


    function frame(){
        if (_stop === true) 
            return;

        // calculations

        var dt = Date.now() - _startedAt,
            diff = dt % _ms;

        setTimeout(frame, ms - diff);
    };

    return function (callback, ms){

        _startedAt = Date.now();
        _stop = false;

        setTimeout(frame, ms);


        return function(){
            _stop = true;
        };
    };
});


// -> start
var stopLoop = setLogicalLoop(myFunction, ms);
// -> stop
stopLoop();
Другие вопросы по тегам