【问题标题】:HTML5 Game - caching whole game locallyHTML5 游戏 - 在本地缓存整个游戏
【发布时间】:2014-08-26 19:57:12
【问题描述】:

我正在创建一个 HTML5 2D 游戏,我只想请求每个资产一次,然后将它们存储在用户的文件系统中,我正在使用 localStorage 来完成此任务,但是 AFAIK 每个源的限制为 5mb,(我的整个游戏将不止于此),并且我想知道如何将我的游戏资产存储在用户的机器中而不受限制,这是我到目前为止所做的:

items.js:

/**
 * Copyright 2014 - Edgar Alexander Franco.
 *
 * @author Edgar Alexander Franco
 * @version 1.0.0
 */

var items = [
  {
    name : 'characters_scott', 
    url : './img/game/characters/scott', 
    type : 'png'
  }, 
  {
    name : 'map_1', 
    url : './img/game/map/1', 
    type : 'jpg'
  }, 
  {
    name : 'map_2', 
    url : './img/game/map/2', 
    type : 'jpg'
  }
];

资源.js

/**
 * Copyright 2014 - Edgar Alexander Franco.
 *
 * @author Edgar Alexander Franco
 * @version 1.0.0
 */

var Resource = (function () {
  var self = {};

  self.get = {};

  self.load = function (items) {
    var xhr = (typeof XMLHttpRequest != 'undefined') ? new XMLHttpRequest() : new ActiveXObject('Microsoft.XMLHTTP') ;
    var item, content, mime;

    for (var i in items) {
      item = items[ i ];
      content = localStorage.getItem(item.url);

      if (content == null) {
        xhr.open('GET', item.url, false);
        xhr.send();
        content = xhr.responseText;
        localStorage.setItem(item.url, content);
      }

      if (item.type != 'audio') {
        mime = (item.type == 'jpg') ? 'image/jpeg' : 'image/png' ;
        self.get[ item.name ] = new Image();
        self.get[ item.name ].src = 'data:' + mime + ';base64,' + content;
      } else {
        // Not yet...
      }
    }
  }

  return self;
})();

上面的代码效果很好,但不能满足我的需求,正如你所看到的,我正在使用 localStore,它有它的局限性,我想调整相同的代码,但为了无限存储,有什么想法吗?

【问题讨论】:

    标签: html caching local-storage assets html5-appcache


    【解决方案1】:

    我建议您使用 Mozilla[1] 的 localForage。它提供与 localStorage 相同的简单 API,但由 IndexedDB 支持(我认为带有 WebSQL / localStorage 后备)。

    另一种方法是,如果所有播放器的资产 URL 都相同,则可以使用 applicationCache。我建议您使用 appCacheNanny[2] 之类的 appCache 包装器库(免责声明:我创建了它。)

    [1]https://github.com/mozilla/localForage
    [2]https://github.com/gr2m/appcache-nanny

    【讨论】:

      【解决方案2】:

      经过长时间的研究,我得出结论,IndexedDB 可能是我们能找到的最强大的本地存储,因此,我重新设计了我的代码,现在这是完整的类:

      /**
       * Copyright 2014 - Edgar Alexander Franco.
       *
       * @author Edgar Alexander Franco
       * @version 1.0.0
       */
      
      var Resources = (function () {
        var self = {};
      
        self.get = {};
      
        self.DOWNLOADED = 1;
        self.LOADED = 2;
      
        var DB_NAME = 'evilition';
        var TABLE_NAME = 'resources';
      
        self.audioType = (document.createElement('audio').canPlayType('audio/mp3') == '') ? '.ogg' : '.mp3' ;
      
        /**
         * Load the assets from the server / filesystem depending if each is cached or not.
         *
         * @param {object} resources Resources of the game.
         * @param {function} callback1 Function to be called on progress.
         * @param {function} callback2 Function to be called on error.
         * @param {function} callback3 Function to be called once the resources are loaded.
         */
        self.load = function (resources, callback1, callback2, callback3) {
          var request = indexedDB.open(DB_NAME, 3);
      
          request.onerror = function (evt) {
            callback2({});
          }
      
          request.onupgradeneeded = function (evt) {
            var db = evt.target.result;
            var table = db.createObjectStore(TABLE_NAME, {
              keyPath : 'name'
            });
            table.createIndex('name', 'name', {
              unique : true
            });
          }
      
          request.onsuccess = function (evt) {
            function loadResource () {
              var resource = resources[ i ];
              var request = objectStore.get(resource.name);
      
              request.onerror = function (evt) {
                callback2(resource);
              }
      
              request.onsuccess = function (evt) {
                var progress = Math.round(((i + 1) * 100) / total);
                var content;
      
                if (typeof request.result == 'undefined') {
                  if (resource.type == 'audio') {
                    resource.path += self.audioType;
                  }
      
                  xhr.open('GET', resource.path + '.b64', false);
                  xhr.send();
      
                  if (xhr.readyState == 4 && xhr.status == 200) {
                    content = xhr.responseText;
                    objectStore.add({
                      name : resource.name, 
                      content : content
                    });
                    callback1(resource, progress, self.DOWNLOADED);
                  } else {
                    callback2(resource);
      
                    return;
                  }
                } else {
                  content = request.result.content;
                  callback1(resource, progress, self.LOADED);
                }
      
                var mime;
      
                if (resource.type != 'audio') {
                  mime = (resource.type == 'jpg') ? 'image/jpeg' : 'image/png' ;
                  self.get[ resource.name ] = new Image;
                } else {
                  mime = (self.audioType == '.mp3') ? 'audio/mp3' : 'audio/ogg' ;
                  self.get[ resource.name ] = new Audio;
                }
      
                self.get[ resource.name ].src = 'data:' + mime + ';base64,' + content;
                i++;
      
                if (i == total) {
                  db.close();
                  callback3();
                } else {
                  loadResource();
                }
              }
            }
      
            var db = evt.target.result;
            var objectStore = db.transaction(TABLE_NAME, 'readwrite').objectStore(TABLE_NAME);
            var xhr = (typeof XMLHttpRequest != 'undefined') ? new XMLHttpRequest : new ActiveXObject('Microsoft.XMLHTTP') ;
            var total = resources.length;
            var i = 0;
      
            loadResource();
          }
        }
      
        /**
         * Delete the resources database requiring the creation of a new one in the next load.
         */
        self.clearLocalCache = function () {
          indexedDB.deleteDatabase(DB_NAME);
        }
      
        return self;
      })();
      

      感谢 Gregor 的推荐 :)

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2022-01-06
        • 2018-03-26
        • 2014-03-31
        • 2012-06-16
        • 1970-01-01
        相关资源
        最近更新 更多