Это все хорошие идеи в теории, пока вы не углубитесь. Проблема в том, что вы не можете ограничить RAF, не отменив синхронизацию, не победив его цель для существования. Таким образом , вы дайте ему поработать на полной скорости, и обновлять данные в отдельном цикле , или даже отдельный поток!
Да, я сказал это. Вы можете сделать многопоточный JavaScript в браузере!
Я знаю, что есть два метода, которые работают очень хорошо без рывков, используют гораздо меньше сока и создают меньше тепла. Точное человеческое масштабирование и эффективность машины - чистый результат.
Извинения, если это немного многословно, но здесь идет ...
Способ 1: обновить данные через setInterval и графику через RAF.
Используйте отдельный setInterval для обновления значений перемещения и поворота, физики, столкновений и т. Д. Сохраняйте эти значения в объекте для каждого анимированного элемента. Присвойте строку преобразования переменной в объекте каждый setInterval 'frame'. Храните эти объекты в массиве. Установите ваш интервал на желаемый fps в мс: ms = (1000 / fps). Это сохраняет постоянные часы, которые позволяют одинаковые кадры в секунду на любом устройстве, независимо от скорости RAF. Не назначайте преобразования для элементов здесь!
В цикле requestAnimationFrame итерируйте свой массив с циклом старой школы for - не используйте новые формы здесь, они медленные!
for(var i=0; i<sprite.length-1; i++){ rafUpdate(sprite[i]); }
В вашей функции rafUpdate получите строку преобразования из вашего объекта js в массиве и идентификатор его элементов. У вас уже должны быть элементы «спрайта», прикрепленные к переменной или легкодоступные с помощью других средств, чтобы вы не теряли время на «получение» их в RAF. Хранить их в объекте, названном в честь их html-идентификаторов, довольно хорошо. Настройте эту часть еще до того, как она попадет в ваш SI или RAF.
Используйте RAF для обновления только ваших преобразований , используйте только 3D-преобразования (даже для 2d) и установите css "will-change: transform;" на элементы, которые будут меняться. Это обеспечивает максимально возможную синхронизацию ваших преобразований с собственной частотой обновления, запускает графический процессор и сообщает браузеру, где сосредоточиться больше всего.
Таким образом, вы должны иметь что-то вроде этого псевдокода ...
// refs to elements to be transformed, kept in an array
var element = [
mario: document.getElementById('mario'),
luigi: document.getElementById('luigi')
//...etc.
]
var sprite = [ // read/write this with SI. read-only from RAF
mario: { id: mario ....physics data, id, and updated transform string (from SI) here },
luigi: { id: luigi .....same }
//...and so forth
] // also kept in an array (for efficient iteration)
//update one sprite js object
//data manipulation, CPU tasks for each sprite object
//(physics, collisions, and transform-string updates here.)
//pass the object (by reference).
var SIupdate = function(object){
// get pos/rot and update with movement
object.pos.x += object.mov.pos.x; // example, motion along x axis
// and so on for y and z movement
// and xyz rotational motion, scripted scaling etc
// build transform string ie
object.transform =
'translate3d('+
object.pos.x+','+
object.pos.y+','+
object.pos.z+
') '+
// assign rotations, order depends on purpose and set-up.
'rotationZ('+object.rot.z+') '+
'rotationY('+object.rot.y+') '+
'rotationX('+object.rot.x+') '+
'scale3d('.... if desired
; //...etc. include
}
var fps = 30; //desired controlled frame-rate
// CPU TASKS - SI psuedo-frame data manipulation
setInterval(function(){
// update each objects data
for(var i=0; i<sprite.length-1; i++){ SIupdate(sprite[i]); }
},1000/fps); // note ms = 1000/fps
// GPU TASKS - RAF callback, real frame graphics updates only
var rAf = function(){
// update each objects graphics
for(var i=0; i<sprite.length-1; i++){ rAF.update(sprite[i]) }
window.requestAnimationFrame(rAF); // loop
}
// assign new transform to sprite's element, only if it's transform has changed.
rAF.update = function(object){
if(object.old_transform !== object.transform){
element[object.id].style.transform = transform;
object.old_transform = object.transform;
}
}
window.requestAnimationFrame(rAF); // begin RAF
Это сохраняет ваши обновления объектов данных и строк преобразования синхронизированными с желаемой частотой кадров в SI, а фактические назначения преобразования в RAF синхронизированы с частотой обновления GPU. Таким образом, фактические графические обновления находятся только в RAF, но изменения в данных и построении строки преобразования находятся в SI, таким образом, нет никаких затей, а «время» течет с желаемой частотой кадров.
Поток:
[setup js sprite objects and html element object references]
[setup RAF and SI single-object update functions]
[start SI at percieved/ideal frame-rate]
[iterate through js objects, update data transform string for each]
[loop back to SI]
[start RAF loop]
[iterate through js objects, read object's transform string and assign it to it's html element]
[loop back to RAF]
Способ 2. Поместите СИ в веб-работника. Этот FAAAST и гладкий!
То же, что и в методе 1, но поместите SI в web-работника. Тогда он будет работать в совершенно отдельном потоке, оставляя страницу для работы только с RAF и пользовательским интерфейсом. Передайте массив спрайтов назад и вперед как «передаваемый объект». Это быстро. Клонирование или сериализация не требуют времени, но это не похоже на передачу по ссылке, поскольку ссылка с другой стороны уничтожается, поэтому вам нужно будет передать обе стороны на другую сторону и обновлять их только при наличии, сортировать как передавать записку туда и обратно со своей девушкой в старшей школе.
Только один может читать и писать одновременно. Это нормально, если они проверяют, не является ли оно неопределенным, чтобы избежать ошибки. RAF является БЫСТРЫМ и немедленно отбросит его, а затем пройдёт через кучу кадров GPU, просто проверяя, отправлено ли оно ещё. SI в web-работнике будет большую часть времени иметь массив спрайтов, обновлять данные о положении, движении и физике, а также создавать новую строку преобразования, а затем передавать ее обратно в RAF на странице.
Это самый быстрый способ, которым я знаю, для анимации элементов с помощью скрипта. Эти две функции будут работать как две отдельные программы в двух отдельных потоках, используя преимущества многоядерных процессоров так, как этого не делает один js-скрипт. Многопоточная анимация JavaScript.
И это будет происходить плавно без рывков, но с фактической заданной частотой кадров, с очень небольшим расхождением.
Результат:
Любой из этих двух способов гарантирует, что ваш скрипт будет работать с одинаковой скоростью на любом ПК, телефоне, планшете и т. Д. (Конечно, в пределах возможностей устройства и браузера).
requestAnimationFrame
(как подсказывает название) запрашивает кадр анимации только тогда, когда это необходимо. Допустим, вы показываете статический черный холст, вы должны получить 0 кадров в секунду, потому что новый кадр не требуется. Но если вы отображаете анимацию, которая требует 60 кадров в секунду, вы должны получить это тоже.rAF
позволяет просто «пропустить» ненужные кадры, а затем сохранить процессор.