Đây là tất cả những ý tưởng tốt trong lý thuyết, cho đến khi bạn đi sâu. Vấn đề là bạn không thể điều tiết RAF mà không đồng bộ hóa nó, đánh bại mục đích hiện tại của nó. Vì vậy, bạn hãy để nó chạy ở tốc độ đầy đủ và cập nhật dữ liệu của bạn trong một vòng lặp riêng biệt , hoặc thậm chí một thread riêng biệt!
Vâng, tôi đã nói nó. Bạn có thể thực hiện JavaScript đa luồng trong trình duyệt!
Có hai phương pháp tôi biết rằng hoạt động cực kỳ tốt mà không cần jank, sử dụng ít nước trái cây và tạo ra ít nhiệt hơn. Thời gian chính xác quy mô con người và hiệu quả máy là kết quả ròng.
Xin lỗi nếu điều này hơi dài dòng, nhưng ở đây đi ...
Phương pháp 1: Cập nhật dữ liệu qua setInterval và đồ họa qua RAF.
Sử dụng một setInterval riêng để cập nhật các giá trị dịch và xoay, vật lý, va chạm, v.v. Giữ các giá trị đó trong một đối tượng cho mỗi thành phần hoạt hình. Gán chuỗi biến đổi cho một biến trong đối tượng mỗi setInterval 'frame'. Giữ các đối tượng trong một mảng. Đặt khoảng thời gian của bạn thành khung hình / giây mong muốn của bạn trong ms: ms = (1000 / khung hình / giây). Điều này giữ cho đồng hồ ổn định cho phép cùng một khung hình / giây trên bất kỳ thiết bị nào, bất kể tốc độ RAF. Đừng chỉ định các biến đổi cho các yếu tố ở đây!
Trong vòng lặp requestAnimationFrame, lặp qua mảng của bạn với vòng lặp trường cũ - không sử dụng các biểu mẫu mới hơn ở đây, chúng rất chậm!
for(var i=0; i<sprite.length-1; i++){ rafUpdate(sprite[i]); }
Trong hàm rafUpdate của bạn, lấy chuỗi biến đổi từ đối tượng js của bạn trong mảng và id phần tử của nó. Bạn đã có các yếu tố 'sprite' của mình được gắn vào một biến hoặc có thể truy cập dễ dàng thông qua các phương tiện khác để bạn không mất thời gian 'lấy chúng trong RAF. Giữ chúng trong một đối tượng được đặt tên theo id html của chúng hoạt động khá tốt. Đặt phần đó lên trước khi nó đi vào SI hoặc RAF của bạn.
Sử dụng RAF để chỉ cập nhật các biến đổi của bạn , chỉ sử dụng các biến đổi 3D (thậm chí cho 2d) và đặt css "will-change: Transform;" trên các yếu tố sẽ thay đổi. Điều này giữ cho các biến đổi của bạn được đồng bộ hóa với tốc độ làm mới riêng càng nhiều càng tốt, khởi động GPU và cho trình duyệt biết nơi tập trung nhất.
Vì vậy, bạn nên có một cái gì đó giống như mã giả này ...
// 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
Điều này giữ cho các cập nhật của bạn đến các đối tượng dữ liệu và các chuỗi biến đổi được đồng bộ hóa với tốc độ 'khung hình' mong muốn trong SI và các phép gán biến đổi thực tế trong RAF được đồng bộ hóa với tốc độ làm mới GPU. Vì vậy, các bản cập nhật đồ họa thực tế chỉ có trong RAF, nhưng những thay đổi về dữ liệu và xây dựng chuỗi biến đổi nằm trong SI, do đó không có jankies mà 'thời gian' chảy ở tốc độ khung hình mong muốn.
Lưu lượng:
[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]
Phương pháp 2. Đặt SI trong một nhân viên web. Đây là một FAAAST và mịn!
Tương tự như phương pháp 1, nhưng đặt SI trong web-worker. Sau đó, nó sẽ chạy trên một luồng hoàn toàn riêng biệt, để trang chỉ xử lý RAF và UI. Truyền mảng sprite qua lại dưới dạng 'đối tượng có thể chuyển'. Đây là buko nhanh. Không mất thời gian để sao chép hoặc tuần tự hóa, nhưng nó không giống như chuyển qua tham chiếu ở chỗ tham chiếu từ phía bên kia bị hủy, vì vậy bạn sẽ cần phải chuyển cả hai bên sang phía bên kia và chỉ cập nhật chúng khi có mặt, sắp xếp giống như chuyển một ghi chú qua lại với bạn gái của bạn ở trường trung học.
Chỉ một người có thể đọc và viết tại một thời điểm. Điều này là tốt miễn là họ kiểm tra nếu nó không được xác định để tránh lỗi. RAF là NHANH CHÓNG và sẽ khởi động lại ngay lập tức, sau đó đi qua một loạt các khung GPU chỉ để kiểm tra xem nó đã được gửi lại chưa. SI trong trình xử lý web sẽ có mảng sprite hầu hết thời gian và sẽ cập nhật dữ liệu vị trí, chuyển động và vật lý, cũng như tạo chuỗi biến đổi mới, sau đó chuyển nó trở lại RAF trong trang.
Đây là cách nhanh nhất mà tôi biết để làm động các yếu tố thông qua kịch bản. Hai chức năng sẽ chạy như hai chương trình riêng biệt, trên hai luồng riêng biệt, tận dụng CPU đa lõi theo cách mà một tập lệnh js duy nhất không có. Hoạt hình javascript đa luồng.
Và nó sẽ làm rất trơn tru mà không cần jank, nhưng ở tốc độ khung hình được chỉ định thực tế, với rất ít sự phân kỳ.
Kết quả:
Một trong hai phương pháp này sẽ đảm bảo tập lệnh của bạn sẽ chạy ở cùng tốc độ trên mọi PC, điện thoại, máy tính bảng, v.v. (tất nhiên là trong khả năng của thiết bị và trình duyệt).
requestAnimationFrame
(là loại tên gợi ý) để yêu cầu một khung hình động chỉ khi cần thiết. Giả sử bạn hiển thị một khung màu đen tĩnh, bạn sẽ nhận được 0 khung hình / giây vì không cần khung mới. Nhưng nếu bạn đang hiển thị một hình ảnh động yêu cầu 60fps, bạn cũng sẽ nhận được điều đó.rAF
chỉ cho phép "bỏ qua" các khung vô dụng và sau đó lưu CPU.