Javascript Canvas/JS存储矢量/位图对象

Javascript Canvas/JS存储矢量/位图对象,javascript,canvas,Javascript,Canvas,在我的画布项目中,我有两种类型的精灵对象,一种是用矢量图形绘制的,另一种是在画布上绘制位图图像的 draw function(context){ ... context.lineTo(some place) context.lineTo(some other place) etc. } 另一种类型的精灵是位图图像,此时它们是占位符资源,因此足够小,不需要onload事件处理程序,但实际资源将更大,因此需要一个 bitmap loadImage function(){ this.

在我的画布项目中,我有两种类型的精灵对象,一种是用矢量图形绘制的,另一种是在画布上绘制位图图像的

draw function(context){
 ...
 context.lineTo(some place)
 context.lineTo(some other place)
 etc.
}
另一种类型的精灵是位图图像,此时它们是占位符资源,因此足够小,不需要onload事件处理程序,但实际资源将更大,因此需要一个

bitmap loadImage function(){

   this.image = new Image(); 
   //Currently my images are too small to warrant an onload eventHandler as they're placeholders
   this.image.src = "some path";
} 
目前,我将所有精灵存储在同一个容器中,并通过一个简单的循环执行绘图。这项功能目前可以使用,因为位图精灵没有onload功能

for each sprite {

 sprite.draw(context);
 }
一旦我用spritesheets替换了占位符资源,它们将需要一个分配给onload事件的函数——这将阻止我的设计

有人能告诉我如何将所有精灵存储在同一个容器中,并通过迭代该集合调用draw吗

注意:使用onload事件处理程序添加了位图绘制,但是(显然)在加载图像之前在位图精灵上调用draw时出现错误。

请注意,因为它是异步的,所以您需要某种“状态机”或指示器来指示资产已完成加载。与桌面游戏不同的是,加载“阻止”了其余的执行,当图像加载到后台时,你仍然可以做一些事情。因此,您可能可以调用像
start
这样的函数来绘制图像

像这样:

function start() {
 context.drawImage(image1, 69, 50);
 context.drawImage(image2, 150, 150);
}

  var canvas = document.getElementById('myCanvas');
  var context = canvas.getContext('2d');
  var image1 = new Image();
  var image2 = new Image();

  var Image = {
    count: 0,
    Load: function(asset, url) {
      asset.src = url;
      asset.onload = function() {
        Image.count--;
        if (Image.count == 0)
        {
          console.log("Done loading everything.");
          start();
        }
      }
      Image.count++;
    }
  };

  Image.Load(image1, 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg');
  Image.Load(image2, 'http://www.html5canvastutorials.com/demos/assets/darth-vader.jpg');

我制作了这个加载程序,它允许您将所有图像URL添加到它,然后调用
load()
来启动加载

您可以使用这种加载程序来支持进度回调,以便向用户显示当前进度

如果您需要跨原点图像,您可以通过添加一个标志来添加对此的支持,该标志告诉加载的用户为图像设置跨原点类型。下面的示例为所有图像设置此选项,但可以对其进行扩展以支持单个图像

加载器:

/// callback - function to call when finished (mandatory)
/// progress - function to call for each image loaded (optional)
/// progress contains an argument with an "event" containing properties
/// img (the image loaded), url, current (integer) and total (integer)
function imageLoader(callback, progress, error) {

    if (typeof callback !== 'function') throw 'Need a function for callback!';

    var lst = [],
        crossOrigin = false;

    this.crossOrigin = function (state) {
        if (typeof state !== 'bool') return crossOrigin;
        crossOrigin = state;
        return this;
    }
    this.add = function (url) {
        lst.push(url);
        return this;
    }

    this.load = function () {
        if (lst.length > 0) {
            startLoading();
        }
        return this;
    }

    function startLoading() {

        var i = 0,
            url,
            count = lst.length,
            images = [];

        for (; url = lst[i]; i++) {
            var img = document.createElement('img');
            images.push(img);

            img.onload = function () {
                _handler(url, this)
            };
            img.onerror = function (e) {
                _handlerError(url, e)
            };

            if (crossOrigin === true) img.crossOrigin = 'anonymous';

            img.src = url;
        }

        function _handler(url, img) {

            count--;

            if (typeof progress === 'function') progress({
                current: lst.length - count,
                total: lst.length,
                url: url,
                img: img
            });

            if (count === 0) callback({
                images: images,
                urls: lst
            });
        }

        function _handlerError(url, e) {
            if (typeof error === 'function') error({
                url: url,
                error: e
            });

            console.warn('WARNING: Could not load image:', url);
            _handler();
        }
    }

    return this;
}
var loader = new imageLoader(done, progress);

/// methods can be chained:
loader.add(url1)
      .add(url2)
      .add(url3)

      .load();
用法:

/// callback - function to call when finished (mandatory)
/// progress - function to call for each image loaded (optional)
/// progress contains an argument with an "event" containing properties
/// img (the image loaded), url, current (integer) and total (integer)
function imageLoader(callback, progress, error) {

    if (typeof callback !== 'function') throw 'Need a function for callback!';

    var lst = [],
        crossOrigin = false;

    this.crossOrigin = function (state) {
        if (typeof state !== 'bool') return crossOrigin;
        crossOrigin = state;
        return this;
    }
    this.add = function (url) {
        lst.push(url);
        return this;
    }

    this.load = function () {
        if (lst.length > 0) {
            startLoading();
        }
        return this;
    }

    function startLoading() {

        var i = 0,
            url,
            count = lst.length,
            images = [];

        for (; url = lst[i]; i++) {
            var img = document.createElement('img');
            images.push(img);

            img.onload = function () {
                _handler(url, this)
            };
            img.onerror = function (e) {
                _handlerError(url, e)
            };

            if (crossOrigin === true) img.crossOrigin = 'anonymous';

            img.src = url;
        }

        function _handler(url, img) {

            count--;

            if (typeof progress === 'function') progress({
                current: lst.length - count,
                total: lst.length,
                url: url,
                img: img
            });

            if (count === 0) callback({
                images: images,
                urls: lst
            });
        }

        function _handlerError(url, e) {
            if (typeof error === 'function') error({
                url: url,
                error: e
            });

            console.warn('WARNING: Could not load image:', url);
            _handler();
        }
    }

    return this;
}
var loader = new imageLoader(done, progress);

/// methods can be chained:
loader.add(url1)
      .add(url2)
      .add(url3)

      .load();
(有关完整示例,请参见演示)

然后,处理程序可以执行以下操作:

function done(e) {

    for (i = 0; i < e.images.length; i++) {

        /// draw the image
        ctx.drawImage(e.images[i], i * 20, i * 20, 40, 40);
    }
}

function progress(e) {

    ///progress bar
    status.style.width = ((e.current / e.total) * 100).toFixed(0) + '%';

    /// current loaded image
    ctx.drawImage(e.img, 0, 340, 60, 60);
}
功能完成(e){
对于(i=0;i
onload应该只触发一次,您可以在处理程序中调用代码的下一步。另外:“目前我的图像太小,无法保证使用onload eventHandler…”这不是保证的大小,但事实上,加载是异步的,并且存在网络延迟,这会延迟加载,无论映像本身有多大或多小。也许可以编写一些类似于
image.Load的管理器,它会在所有资源加载完毕时通知您。是的,我试着使用bool开关,直到所有的精灵都准备好了,但在我尝试时似乎不是最好的解决方案。干杯@Fendorio可以自由编辑问题的解决方案,这样我们就可以看到你的方法有什么问题。