HTML5 游戏的简单资源管理

发布于 2023-05-13 11:51:20 字数 7227 浏览 71 评论 0

HTML5 提供了许多有用的 API,用于在浏览器中构建现代、响应迅速且功能强大的 Web 应用程序。这很棒,但你真的想构建和玩游戏!幸运的是,HTML5也开创了游戏开发的新时代,它使用 Canvas 等 API 和强大的 JavaScript 引擎将游戏直接传送到您的浏览器,而无需插件。

本文将引导您为 HTML5 游戏构建一个简单的资产管理组件。如果没有资源管理器,您的游戏将很难补偿未知的下载时间和异步图像加载。请继续查看适用于您的 HTML5 游戏的简单资源管理器示例。

问题所在

HTML5 游戏不能假设其资产(如图像或音频)将位于玩家的本地计算机上,因为 HTML5 游戏意味着在 Web 浏览器中播放,并通过 HTTP 下载资产。由于涉及网络,浏览器不确定何时下载和提供游戏的资产。

在 Web 浏览器中以编程方式加载图像的基本方法是以下代码:

var image = new Image();
image.addEventListener(“success”, function(e) {
  // do stuff with the image
});
image.src = "/some/image.png";

现在想象一下,在游戏启动时需要加载和显示一百张图像。您如何知道所有 100 张图像何时准备就绪?它们都成功加载了吗?游戏应该什么时候真正开始?

解决方案

让资产管理者处理资产排队,并在一切准备就绪后向游戏报告。资产管理器概括了通过网络加载资产的逻辑,并提供了一种检查状态的简单方法。

我们的简单资产管理人有以下要求:

  • 排队下载
  • 开始下载
  • 跟踪成功和失败
  • 一切完成后发出信号
  • 轻松检索资产

排队

第一个要求是将下载排队。此设计允许您声明所需的资产,而无需实际下载它们。例如,如果要在配置文件中声明游戏关卡的所有资产,这会很有用。

构造函数和队列的代码如下所示:

function AssetManager() {
  this.downloadQueue = [];
}

AssetManager.prototype.queueDownload = function(path) {
    this.downloadQueue.push(path);
}

开始下载

将所有要下载的资产排队后,您可以要求资源管理器开始下载所有内容。

幸运的是,Web 浏览器可以并行下载 - 通常每个主机最多 4 个连接。加快资产下载速度的一种方法是使用一系列域名进行资产托管。例如,尝试使用 assets1.example.com、assets2.example.com、assets3.example.com 等,而不是提供 assets.example.com 中的所有内容。即使这些域名中的每一个都只是同一 Web 服务器的 CNAME,Web 浏览器也会将它们视为单独的服务器,并增加用于资产下载的连接数。有关此技术的详细信息,请参阅 跨域拆分组件 中的 加快网站速度的最佳做法

我们的下载初始化方法称为 downloadAll(),我们会随着时间的推移建立它。现在,这是开始下载的第一个逻辑。

AssetManager.prototype.downloadAll = function() {
    for (var i = 0; i < this.downloadQueue.length; i++) {
        var path = this.downloadQueue[i];
        var img = new Image();
        var that = this;
        img.addEventListener("load", function() {
            // coming soon
        }, false);
        img.src = path;
    }
}

正如您在上面的代码中看到的, downloadAll() 只需遍历 downloadQueue 并创建一个新的 Image 对象。添加 load 事件的事件侦听器并设置映像的 src,从而触发实际下载。

使用此方法,您可以开始下载。

跟踪成功和失败

另一个要求是跟踪成功和失败,因为不幸的是,并非一切都能完美地进行。到目前为止,代码仅跟踪成功下载的资产。通过为错误事件添加事件侦听器,您将能够捕获成功和失败方案。

AssetManager.prototype.downloadAll = function(downloadCallback) {
  for (var i = 0; i < this.downloadQueue.length; i++) {
    var path = this.downloadQueue[i];
    var img = new Image();
    var that = this;
    img.addEventListener("load", function() {
        // coming soon
    }, false);
    img.addEventListener("error", function() {
        // coming soon
    }, false);
    img.src = path;
  }
}

我们的资产管理人需要知道我们遇到了多少成功和失败,否则它永远不会知道游戏何时可以开始。

首先,我们将计数器添加到构造函数中的对象,现在如下所示:

function AssetManager() {
    this.successCount = 0;
    this.errorCount = 0;
    this.downloadQueue = [];
}

接下来,递增事件侦听器中的计数器,现在如下所示:

img.addEventListener("load", function() {
    that.successCount += 1;
}, false);
img.addEventListener("error", function() {
    that.errorCount += 1;
}, false);

资产管理器现在正在跟踪成功加载和失败的资产。

完成后发出信号

在游戏将其资产排队等待下载并要求资源管理器下载所有资产后,需要告知游戏何时下载所有资产。与游戏一遍又一遍地询问资产是否已下载不同,资产管理者可以向游戏发出信号。

资产管理者需要首先知道每项资产何时完成。我们现在将添加一个 isDone 方法:

AssetManager.prototype.isDone = function() {
    return (this.downloadQueue.length == this.successCount + this.errorCount);
}

通过将 successCount + errorCount 与 downloadQueue 的大小进行比较,资产管理器知道每个资产是否成功完成或出现某种错误。

当然,知道它是否完成只是成功的一半;资产管理者也需要检查这种方法。我们将在两个事件处理程序中添加此检查,如下面的代码所示:

img.addEventListener("load", function() {
    console.log(this.src + ' is loaded');
    that.successCount += 1;
    if (that.isDone()) {
        // ???
    }
}, false);
img.addEventListener("error", function() {
    that.errorCount += 1;
    if (that.isDone()) {
        // ???
    }
}, false);

计数器递增后,我们将查看这是否是队列中的最后一个资产。如果资产管理者确实完成了下载,我们到底应该怎么做?

如果资产管理者下载完所有资产,我们当然会调用回调方法!让我们改变 downloadAll() 并为回调添加参数:


AssetManager.prototype.downloadAll = function(downloadCallback) {
    ...

我们将在事件侦听器中调用 downloadCallback 方法:

img.addEventListener("load", function() {
    that.successCount += 1;
    if (that.isDone()) {
        downloadCallback();
    }
}, false);
img.addEventListener("error", function() {
    that.errorCount += 1;
    if (that.isDone()) {
        downloadCallback();
    }
}, false);

资产管理者终于准备好满足最后一个要求了。

轻松检索资产

一旦游戏收到可以启动的信号,游戏将开始渲染图像。资产管理者不仅负责下载和跟踪资产,还负责将其提供给游戏。

我们的最终要求意味着某种 getAsset 方法,所以我们现在添加它:

AssetManager.prototype.getAsset = function(path) {
    return this.cache[path];
}

此缓存对象在构造函数中初始化,现在如下所示:

function AssetManager() {
    this.successCount = 0;
    this.errorCount = 0;
    this.cache = {};
    this.downloadQueue = [];
}

缓存在 downloadAll(),如下所示:

AssetManager.prototype.downloadAll = function(downloadCallback) {
  ...
      img.addEventListener("error", function() {
          that.errorCount += 1;
          if (that.isDone()) {
              downloadCallback();
          }
      }, false);
      img.src = path;
      this.cache[path] = img;
  }
}

奖励:错误修复

你发现这个错误了吗?如上所述,仅当触发加载或错误事件时,才会调用 isDone 方法。但是,如果资产管理者没有任何资产排队等待下载怎么办?isDone 方法永远不会触发,游戏也永远不会开始。

可以通过将以下代码添加到 downloadAll()

AssetManager.prototype.downloadAll = function(downloadCallback) {
  if (this.downloadQueue.length === 0) {
      downloadCallback();
  }
 ...

如果没有资产排队,则立即调用回调。错误已修复!

示例用法

在您的HTML5游戏中使用此资源管理器非常简单。以下是使用该库的最基本方法:

var ASSET_MANAGER = new AssetManager();

ASSET_MANAGER.queueDownload('img/earth.png');

ASSET_MANAGER.downloadAll(function() {
    var sprite = ASSET_MANAGER.getAsset('img/earth.png');
    ctx.drawImage(sprite, x - sprite.width/2, y - sprite.height/2);
});

上面的代码说明:

  1. 创建新的资产管理器
  2. 排队待下载的资产
  3. 开始下载 downloadAll()
  4. 通过调用回调函数在资产准备就绪时发出信号
  5. 使用 检索资产 getAsset()

需要改进的领域

毫无疑问,当你构建你的游戏时,你会超越这个简单的资产管理,尽管我希望它提供了一个基本的开始。未来的功能可能包括:

  • 指示哪个资产出错
  • 指示进度的回调
  • 从文件系统 API 检索资产

请在下面的评论中发布改进、复刻和代码链接。

完整来源

这个资产管理器的来源,以及它从中抽象出来的游戏,是Apache许可证下的开源软件,可以在 Bad Aliens GitHub帐户 中找到。 坏外星人游戏 可以在与HTML5兼容的浏览器中播放。这个游戏是我的Google IO演讲的主题,题为Super Browser 2 Turbo HD Remix:HTML5游戏开发简介( 幻灯片 视频 )。

总结

大多数游戏都有某种资产管理器,但HTML5游戏需要一个资产管理器,通过网络加载资产并处理故障。本文概述了一个简单的资源管理器,它应该易于您使用和适应您的下一个 HTML5 游戏。玩得开心,请在下面的评论中告诉我们您的想法。谢谢!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据

关于作者

永不分离

暂无简介

0 文章
0 评论
831 人气
更多

推荐作者

yili302

文章 0 评论 0

晚霞

文章 0 评论 0

LLFFCC

文章 0 评论 0

陌路黄昏

文章 0 评论 0

xiaohuihui

文章 0 评论 0

你与昨日

文章 0 评论 0

    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文