除非是全局的,否则不会呈现Javascript图像

除非是全局的,否则不会呈现Javascript图像,javascript,canvas,Javascript,Canvas,我正在尝试使用JS渲染来自sprite工作表的图像。奇怪的是,除非进行渲染的对象是全局对象,否则它不会工作(请参见代码和注释)。FF和Chrome的行为都是相同的 resetGame()在页面加载时执行 var TILE_SIZE = 24; function CharacterImage(imageSource) { var tile_x = 0; var tile_y = 0; var img = new Image(); img.src = imageS

我正在尝试使用JS渲染来自sprite工作表的图像。奇怪的是,除非进行渲染的对象是全局对象,否则它不会工作(请参见代码和注释)。FF和Chrome的行为都是相同的

resetGame()
在页面加载时执行

var TILE_SIZE = 24;

function CharacterImage(imageSource)
{
    var tile_x = 0;
    var tile_y = 0;

    var img = new Image();
    img.src = imageSource;

    this.render = function(ctx, x, y)
    {
        ctx.drawImage(img, tile_x, tile_y, TILE_SIZE, TILE_SIZE, 
                x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);
    }
}

function Hero(canvas, image)
{
    var ctx = canvas.getContext("2d");
    var img = image;

    this.render = function()
    {
        var x = 1;
        var y = 1;
        img.render(ctx, x, y);
    }
}

// If the heroImage is constructed here, instead of within the function below,
// the image is rendered as expected.
var heroImage = new CharacterImage("img/sf2-characters.png");

function resetGame()
{
    var heroCanvas = document.getElementById("heroLayer");

    // On the otherhand, if the object is constructed here, instead of
    // globally, the rendering doesn't work.
    var heroImage = new CharacterImage("img/sf2-characters.png");
    var hero = new Hero(heroCanvas, heroImage);
    hero.render();
}

等等,我想我知道发生了什么。加载映像需要时间,因此您应该以某种方式将事件绑定到映像的加载。可以这样做,例如:

var TILE_SIZE = 24;

function CharacterImage(imageSource)
{
    var tile_x = 0;
    var tile_y = 0;

    var img = new Image();
    img.src = imageSource;

    this.render = function(ctx, x, y)
    {
        ctx.drawImage(img, tile_x, tile_y, TILE_SIZE, TILE_SIZE, 
                x * TILE_SIZE, y * TILE_SIZE, TILE_SIZE, TILE_SIZE);
    }
    // Set up a "load" event for the img
    this.loaded = function(callback) {
        img.addEventListener('load', callback);
    }
}

function resetGame()
{
    var heroCanvas = document.getElementById("heroLayer");

    var heroImage = new CharacterImage("img/sf2-characters.png");
    var hero;
    // Initiate the "load" event
    heroImage.loaded(function() {
        hero = new Hero(heroCanvas, heroImage);
        hero.render();
    };
}
不过,您可能需要的是某种预加载程序“class”/事件,它在您实际继续渲染之前跟踪正在加载的所有内容。它可能看起来像这样

var TILE\u SIZE=60;
函数精灵(图像源)
{
this.img=新图像();
this.img.src=图像源;
this.position={x:0,y:0};
}
Sprite.prototype={
isLoaded:函数(){
返回此.img.complete;
},
onLoad:函数(回调){
if(typeof callback!=“function”)返回;
if(this.isLoaded()){
回调();
}
否则{
this.img.removeEventListener('load',callback);
this.img.addEventListener('load',callback);
}
},
moveBy:函数(x,y){
此.position.x+=x;
此.position.y+=y;
},
渲染:函数(ctx){
如果(!this.isLoaded())返回;
ctx.drawImage(this.img,this.position.x*平铺尺寸,this.position.y*平铺尺寸,平铺尺寸,平铺尺寸);
}
};
函数SpriteList()
{
this.list={};
}
SpriteList.prototype={
isLoaded:函数(){
for(此.list中的变量i){
如果(!this.list[i].isload()){
返回false;
}
}
返回true;
},
_onLoadFunc:null,
onLoad:函数(回调){
这是。_onLoadFunc=回调;
这个.onImageLoaded();
},
onImageLoaded:函数(){
if(this.isLoaded()&&typeof this.\u onLoadFunc==“函数”){
这是。_onLoadFunc();
} 
},
添加:函数(名称、精灵){
this.list[name]=sprite;
sprite.onLoad(this.onImageLoaded.bind(this));
},
get:函数(名称){
返回此.列表[名称];
}
};
var sprites=新的SpriteList();
精灵。添加(“玩家”,新精灵(“http://www.fillmurray.com/200/200"));
精灵。添加(“敌人”,新精灵(“http://www.fillmurray.com/100/100"));
雪碧。添加(“拾取”,新雪碧(“http://www.fillmurray.com/60/60"));
精灵。获取(“拾取”)。移动(1,2);
精灵。获取(“敌人”)。移动(2,0);
sprites.onLoad(函数(){
document.getElementById(“加载”).innerHTML=“加载!”;
var c=document.getElementById(“ctx”);
var ctx=c.getContext(“2d”);
精灵。获取(“玩家”)。渲染(ctx);
精灵。获取(“敌人”)。渲染(ctx);
精灵。获取(“拾取”)。渲染(ctx);
});
正在加载。。。

你在哪里调用
resetGame()
?在页面加载时,就像他在问题中说的,“不工作”是什么意思?你收到错误信息了吗,什么都没发生,什么?谢谢。这看起来很有希望。我正在做游戏的另一部分,所以一旦我有机会尝试你的建议,我会选择这个作为答案,如果它奏效的话。