2011-12-27 11 views
25

Tôi đang phát triển trò chơi bằng JavaScript và canvas. Khi trò chơi tải, tất cả hình ảnh sẽ được sử dụng đang được lưu vào bộ nhớ cache.Đợi tải hình ảnh trước khi tiếp tục

Quan sát timeline tài nguyên, tôi thấy rằng đoạn mã sau gây nên một yêu cầu không đồng bộ:

var sprite = new Image(); 
sprite.src = "sprites/sheet1.png"; 

Động cơ sẽ tiếp tục thực hiện, cuối cùng bắt đầu vẽ và chơi các cấp độ. Hình ảnh được tải sau khi khung hình đầu tiên được sơn có thể không bao giờ xuất hiện do cắt (ví dụ: không bị "bẩn").

Vì vậy, tôi đã thử nghiệm sau đây:

console.log("begin"); 
var sprite = new Image(); 
sprite.onload = function() { console.log('loaded!'); }; 
sprite.src = "sprites/sheet1.png"; 
console.log("end"); 

Các kết quả đầu ra giao diện điều khiển theo thứ tự chúng xuất hiện là:

  • begin
  • end
  • loaded!

Tôi đang tìm cách tương tự như $.ajax với async: false để thực hiện tải. Không thể tìm ra cách ... cảm ơn trước sự giúp đỡ của bạn! J.

Trả lời

55

Bạn không nên thực hiện bất cứ điều gì đồng bộ (thậm chí không AJAX) các cuộc gọi mà thay vào đó chỉ cần đặt mã của bạn trong khi gọi lại thích hợp:

function loadSprite(src, callback) { 
    var sprite = new Image(); 
    sprite.onload = callback; 
    sprite.src = src; 
} 

Sau đó sử dụng nó như thế này:

loadSprite('sprites/sheet1.png', function() { 
    // code to be executed later 
}); 

Nếu bạn muốn chuyển các đối số bổ sung, bạn có thể thực hiện như sau:

sprite.onload = function() { 
    callback(whatever, args, you, have); 
}; 

Nếu bạn muốn tải nhiều yếu tố và cần phải chờ đợi cho tất cả chúng để kết thúc, hãy xem xét sử dụng các đối tượng jQuery deferred:

function loadSprite(src) { 
    var deferred = $.Deferred(); 
    var sprite = new Image(); 
    sprite.onload = function() { 
     deferred.resolve(); 
    }; 
    sprite.src = src; 
    return deferred.promise(); 
} 

Trong chức năng tải các sprites, bạn làm điều gì đó như thế này:

var loaders = []; 
loaders.push(loadSprite('1.png')); 
loaders.push(loadSprite('2.png')); 
loaders.push(loadSprite('3.png')); 
$.when.apply(null, loaders).done(function() { 
    // callback when everything was loaded 
}); 

http://api.jquery.com/jQuery.when/

+0

Cảm ơn trả lời của bạn. Tôi quên đề cập đến, mã này là một phần của một tên hàm "loadSprite (name)" được gọi bởi một phụ huynh. Đó là cha mẹ gọi nó từ một vòng lặp như "cho mỗi sprite loadSprite (tên)". Tôi cần để có thể làm gián đoạn quá trình xử lý, khiến phương thức chỉ trả lại khi hình ảnh được tải. Bất kỳ ý tưởng? – Jem

+0

Bạn không thể thực hiện việc này mà không đóng băng trình duyệt. Tôi sẽ cập nhật câu trả lời của mình để hiển thị giải pháp thích hợp(). – ThiefMaster

+0

Xin cảm ơn, nó rất thú vị. Tôi hoàn toàn không biết gì về vật thể trì hoãn đó! – Jem

2

câu hỏi này là cũ, nhưng có một cách để làm điều này mà không cần jquery, HOẶC freezin g trình duyệt.

Trong image1.onLoad, hãy tải hình ảnh2.
Trong image2.onLoad, hãy tải hình ảnh3.
Trong image3.onLoad, hãy tải hình ảnh4.
....
Trong hình ảnh n .onLoad làm cho nó tải chức năng chính của bạn.

Tôi không chắc đây có phải là cách hoàn hảo nhất để làm điều đó hay không, nhưng tốt nhất là đóng trình duyệt ít nhất.
Bạn cũng có thể tải tất cả các tệp âm thanh của mình hoặc bất kỳ tài nguyên nào khác bạn cần hoặc bất kỳ javascript nào khác bạn cần chạy.

đóng băng trình duyệt không cần

+1

Đây là cách tôi hiện đang làm nó (đêm đầu tiên sử dụng Canvas) nhưng có vẻ lộn xộn. Có cách nào tốt hơn để làm điều đó? Tôi đã cố gắng thiết lập đúng/sai cờ cho các nguồn lực được nạp và sử dụng do/while vòng nhưng tôi không thể nhận được bất cứ điều gì làm việc khác hơn phương pháp này. – BenM

+1

Không chắc chắn. Tôi chỉ cần một hoặc hai tài nguyên cho dự án của mình, vì vậy tôi chưa bao giờ tham gia vào toàn bộ khung tải tài nguyên. Tôi chắc chắn có những cách tốt hơn để thực hiện việc này. Tốt nhất của may mắn cho ya! :) – Interpolate

+0

Tôi đã kết thúc xây dựng một phương thức gọi lại tùy chỉnh tăng bộ đếm tài nguyên (và so sánh nó với độ dài của một mảng tài nguyên) và không làm gì nếu chúng là các giá trị khác nhau hoặc bắt đầu vẽ lên canvas nếu các giá trị khớp với nhau có nghĩa là tất cả các tài nguyên đã được tải). – BenM

0

tôi đã vấn đề này với vải tôi đã cố gắng giải pháp của bạn, nhưng một cách tốt nhất và đơn giản mà làm việc là:

function COLPOinitCanvas(imagesfile) { 
    COLPOcanvas = document.getElementById("COLPOcanvas"); 
    COLPOctx = COLPOcanvas.getContext("2d"); 
    var imageObj = new Image(); 
    imageObj.src = imagesfile; 
    imageObj.onload = function() { 
     COLPOctx.drawImage(imageObj, 0, 0, COLPOcanvas.width, COLPOcanvas.height); 
    }; 
}