利用HTML5進(jìn)行游戲開(kāi)發(fā),相比于其他語(yǔ)言例如Java、C++等,有很多不同,其中一個(gè)就是資源加載。本文主要對(duì)HTML5游戲資源加載的問(wèn)題、原因以及解決方案,進(jìn)行一些分析,試圖解釋以下問(wèn)題:
- 如何加載不同類型的資源
- 如何進(jìn)行批量加載
- 如何顯示加載的進(jìn)度條
- 如何存放資源
在文章的最后,也會(huì)列舉一些游戲引擎的實(shí)現(xiàn)方案,供大家參考。通過(guò)此篇文章,希望可以讓讀者對(duì)于資源加載的技術(shù)有一個(gè)全面的了解。
二) 需要考慮的資源類型
一般游戲需要的資源,主要包括圖片、音頻、視頻以及二進(jìn)制數(shù)據(jù)文件。如果是3D游戲,還會(huì)需要一些模型文件,例如3dmax導(dǎo)出的obj文件。通常的情況下,這些資源文件,少則幾十兆,多則幾個(gè)G。對(duì)于很多客戶端游戲,這個(gè)并不是特別大的問(wèn)題。通常,它們可以將這些資源打在安裝包中,隨著安裝的過(guò)程,一次性的存放在本地。
但是,Web游戲面臨的情況比較復(fù)雜,主要有兩個(gè)原因:
- 因?yàn)樗械馁Y源都放在云端的服務(wù)器上。
- 瀏覽器為了優(yōu)化網(wǎng)頁(yè)的渲染,對(duì)于圖片、音頻等資源的加載,通常都是異步的。
大家可以回想一下,在打開(kāi)某些網(wǎng)頁(yè)的時(shí)候,偶然也會(huì)看到,即使在網(wǎng)頁(yè)顯示完以后,總有一兩個(gè)圖片的位置是空白的,大約幾秒鐘以后,這些圖片往往又在不經(jīng)意中顯示了出來(lái)。
除了圖片、音頻等二進(jìn)制文件,還有一類比較特殊的文件,就是Javascript文件。尤其是游戲邏輯比較龐大時(shí),Javascript文件也可能有幾百K,甚至好幾兆。如果僅是根據(jù)文件的大小,這類文件似乎可以忽略不計(jì)。但是由于瀏覽器對(duì)于Javascript文件的處理是同步的,往往這些文件會(huì)成為性能的瓶頸。
舉個(gè)例子,當(dāng)瀏覽器在解析網(wǎng)頁(yè)的過(guò)程中,碰到了<script>標(biāo)簽,它會(huì)立即轉(zhuǎn)入對(duì)<script>標(biāo)簽的解析,同時(shí)阻塞的等待解析的完成。如果<script>標(biāo)簽,帶有src屬性,瀏覽器同樣是阻塞的等待下載完成。所以,有時(shí)我們抱怨網(wǎng)絡(luò)太慢,其實(shí)是委屈了運(yùn)營(yíng)商,很多時(shí)候,是腳本執(zhí)行占用了太長(zhǎng)時(shí)間,阻塞了網(wǎng)頁(yè)的顯示。
對(duì)于Javascript腳本的加載,首先要解決下載的問(wèn)題,通常是偽裝Javascript文件成資源文件,比如將Javascript中的腳本,作為整個(gè)字符串,放入一個(gè)JSON文件,充分發(fā)揮瀏覽器異步下載的能力。其次要縮短每次腳本文件解析的時(shí)間,這個(gè)最重要的就是按需“執(zhí)行”,也就說(shuō)要將腳本模塊化。模塊化是比較容易理解的,就是模仿面向?qū)ο蟮木幊谭椒ǎ瑢⒉煌δ艿暮瘮?shù)放在不同的文件中。
但是,這樣做帶來(lái)另外一個(gè)問(wèn)題,因?yàn)镴avascript沒(méi)有提供類似于面向?qū)ο笳Z(yǔ)言中的模塊繼承功能,例如,在Java中,Java虛擬機(jī)會(huì)自動(dòng)的將該文件依賴的其他類,導(dǎo)入運(yùn)行時(shí)環(huán)境。為了實(shí)現(xiàn)模塊化,也需要為Javascript模擬一套類似的功能,幸運(yùn)的是,目前已經(jīng)有許多成熟的類庫(kù),例如RequireJS。因?yàn)镴avascript文件的加載不屬于游戲開(kāi)發(fā)的專有問(wèn)題,在本文中不做詳細(xì)介紹。
三) 如何加載不同類型的資源
2.1 通過(guò)瀏覽器內(nèi)置對(duì)象的回調(diào)接口,實(shí)現(xiàn)資源加載
對(duì)于圖片文件的加載,瀏覽器提供了方便的回調(diào)接口,比較容易實(shí)現(xiàn),如下:
- var image = new Image();
- image.addEventListener(“success”, function(e) {
- // do stuff with the image
- );
- image.src = "/some/image.png";
但是比較麻煩的是,HTML并沒(méi)有提供對(duì)等的Audio、Video對(duì)象。對(duì)于Audio,雖然Web Audio API可以提供類似的功能,但是明顯學(xué)習(xí)門(mén)檻高了一些。對(duì)于Video,目前還沒(méi)有可以有效的方式,可以模擬類似的功能。對(duì)于文本、二進(jìn)制等文件,更是比較麻煩。
2.2 通過(guò)Ajax請(qǐng)求,實(shí)現(xiàn)資源加載
利用Ajax對(duì)HTTP地址進(jìn)行請(qǐng)求的能力,相信大家沒(méi)有任何質(zhì)疑。但是,在Ajax請(qǐng)求到相關(guān)資源以后,如何將資源轉(zhuǎn)化為相應(yīng)的圖片、音頻等對(duì)象,好像又產(chǎn)生了一些困難。
但是幸運(yùn)的是,目前Ajax推出了新的標(biāo)準(zhǔn),可以支持對(duì)二進(jìn)制數(shù)據(jù)的提取。再輔助目前新的數(shù)據(jù)存儲(chǔ)方式,比如Blob、FileSystem等,可以輕松的解決這個(gè)問(wèn)題。
利用Blob將資源轉(zhuǎn)換相應(yīng)的對(duì)象,代碼片段如下,更多代碼請(qǐng)參考“New Trics in XHR”
- window.URL = window.URL || window.webkitURL; // Take care of vendor prefixes.var xhr = new XMLHttpRequest();
- xhr.open('GET', '/path/to/image.png', true);
- xhr.responseType = 'blob';
- xhr.onload = function(e) {
- if (this.status == 200) {
- var blob = this.response;
- var img = document.createElement('img');
- img.onload = function(e) {
- window.URL.revokeObjectURL(img.src); // Clean up after yourself.
- };
- img.src = window.URL.createObjectURL(blob);
- document.body.appendChild(img);
- ...
- }
- };
- xhr.send();
利用FileSystem,將資源轉(zhuǎn)換為相應(yīng)的對(duì)象,代碼片段如下,更多完成代碼,請(qǐng)參考“LOADING LARGE ASSETS IN MODERN HTML5 GAMES”
- var xhr = new XMLHttpRequest();
- xhr.open('GET', url, true);
- xhr.responseType = 'arraybuffer';
- xhr.addEventListener('load', function() {
- createDir_(root, dirname_(key).split('/'), function(dir) {
- dir.getFile(basename_(key), {create: true}, function(fileEntry) {
- fileEntry.createWriter(function(writer) {
- writer.onwrite = function(e) {
- // Save this file in the path to URL lookup table.
- lookupTable[key] = fileEntry.toURL();
- callback();
- };
- writer.onerror = failCallback;
- var bb = new BlobBuilder();
- bb.append(xhr.response);
- writer.write(bb.getBlob());
- }, failCallback);
- }, failCallback);
- });
- });
- xhr.addEventListener('error', failCallback);
- xhr.send();
上面兩種方式,都是在獲得資源后,為資源生成一個(gè)URL地址對(duì)象,在將此地址賦給相關(guān)的對(duì)象。
2.3 通過(guò)創(chuàng)建元素的方式,獲得資源
于第二種方式,相信不少讀者擔(dān)心不同瀏覽器的兼容性,畢竟里面利用了大量的HTML5新屬性,而這些屬性,很多屬于剛剛發(fā)布的特性,每個(gè)瀏覽器支持的情況不太一樣。所以,還需要一種可以兼容所有瀏覽器的方式。通過(guò)創(chuàng)建元素的方式,相對(duì)比較保險(xiǎn)。參考如下代碼:
- var res = document.createElement(“image/audio/xxx”)
- res.src = “http://www.yourdomain.com”
但是這樣的代碼,也碰到了和第一個(gè)方法同樣的問(wèn)題,不是所有的元素都提供了onload函數(shù)。對(duì)于Image,處理相對(duì)簡(jiǎn)單。但是對(duì)于Audio/Vido,只能利用canplaythrough等函數(shù)做一些大約估計(jì)。
總之,為了做好資源下載,可能不能完全依賴某一類方法,最有可能的方式是根據(jù)每種方法的優(yōu)缺點(diǎn),根據(jù)具體原因進(jìn)行選擇。在一些比較成熟的游戲引擎和類庫(kù)的實(shí)現(xiàn)中,也確實(shí)是融合了這三種不同的方法。
(未完待續(xù))
【網(wǎng)站聲明】本站除付費(fèi)源碼經(jīng)過(guò)測(cè)試外,其他素材未做測(cè)試,不保證完整性,網(wǎng)站上部分源碼僅限學(xué)習(xí)交流,請(qǐng)勿用于商業(yè)用途。如損害你的權(quán)益請(qǐng)聯(lián)系客服QQ:2655101040 給予處理,謝謝支持。