PixiJS精灵表加载后无法访问纹理,报错textures未定义
PixiJS精灵表纹理访问问题解决办法
在开发基础国际象棋游戏时,使用PixiJS的精灵表API遇到报错textures is undefined,核心原因是对app.loader的异步特性理解不足,无法在loader回调外部正确访问加载后的纹理数据。使用的棋子精灵表如下:

当前代码及问题
业务代码
const app = new PIXI.Application(); document.body.appendChild(app.view); key = ['w_king', 'w_queen', 'w_bishop', 'w_knight', 'w_castle', 'w_pawn', 'b_king', 'b_queen', 'b_bishop', 'b_knight', 'b_castle', 'b_pawn']; app.loader.add('spritesheet', 'pieces.json') .load( _=> { const textures = key.map(k => PIXI.Texture.from(k)); }); var sprite = PIXI.Sprite(textures[1]); app.stage.addChild(sprite)
对应的pieces.json内容
{"frames": { "w_king":{ "frame":{"x":0,"y":0,"w":426,"h":426}, "sourceSize":{"w":426,"h":426}, "spriteSourceSize":{"x":0,"y":0,"w":426,"h":32}}, "w_queen":{ "frame":{"x":426,"y":0,"w":426,"h":426}, "sourceSize":{"w":426,"h":426}, "spriteSourceSize":{"x":0,"y":0,"w":426,"h":426}}, "w_bishop":{ "frame":{"x":852,"y":0,"w":426,"h":426}, "sourceSize":{"w":426,"h":426}, "spriteSourceSize":{"x":0,"y":0,"w":426,"h":426}}, "w_knight":{ "frame":{"x":1278,"y":0,"w":426,"h":426}, "sourceSize":{"w":426,"h":426}, "spriteSourceSize":{"x":0,"y":0,"w":426,"h":426}}, "w_castle":{ "frame":{"x":1704,"y":0,"w":426,"h":426}, "sourceSize":{"w":426,"h":426}, "spriteSourceSize":{"x":0,"y":0,"w":426,"h":426}}, "w_pawn":{ "frame":{"x":2130,"y":0,"w":426,"h":426}, "sourceSize":{"w":426,"h":426}, "spriteSourceSize":{"x":0,"y":0,"w":426,"h":426}}, "b_king":{ "frame":{"x":0,"y":0,"w":426,"h":426}, "sourceSize":{"w":426,"h":426}, "spriteSourceSize":{"x":0,"y":0,"w":426,"h":32}}, "b_queen":{ "frame":{"x":426,"y":0,"w":426,"h":426}, "sourceSize":{"w":426,"h":426}, "spriteSourceSize":{"x":0,"y":0,"w":426,"h":426}}, "b_bishop":{ "frame":{"x":852,"y":0,"w":426,"h":426}, "sourceSize":{"w":426,"h":426}, "spriteSourceSize":{"x":0,"y":0,"w":426,"h":426}}, "b_knight":{ "frame":{"x":1278,"y":0,"w":426,"h":426}, "sourceSize":{"w":426,"h":426}, "spriteSourceSize":{"x":0,"y":0,"w":426,"h":426}}, "b_castle":{ "frame":{"x":1704,"y":0,"w":426,"h":426}, "sourceSize":{"w":426,"h":426}, "spriteSourceSize":{"x":0,"y":0,"w":426,"h":426}}, "b_pawn":{ "frame":{"x":2130,"y":0,"w":426,"h":426}, "sourceSize":{"w":426,"h":426}, "spriteSourceSize":{"x":0,"y":0,"w":426,"h":426}}}, "meta":{ "image":"spriteSheet.png", "format":"RGBA8888", "size":{"w":2560,"h":853}, "scale":1}}
问题根源
app.loader.load()是异步操作,后台加载资源时不会阻塞后续代码执行。回调内部定义的textures是局部变量,外部无法访问;更关键的是,回调还未执行时,外部代码就已尝试访问textures[1],此时textures尚未被定义,因此触发报错。
修正方案
所有依赖加载后资源的代码,必须放在load()回调内部,或使用Promise/async-await处理异步流程。
方案1:回调内处理全逻辑
把创建精灵、添加到舞台的代码移到回调函数中:
const app = new PIXI.Application(); document.body.appendChild(app.view); const key = ['w_king', 'w_queen', 'w_bishop', 'w_knight', 'w_castle', 'w_pawn', 'b_king', 'b_queen', 'b_bishop', 'b_knight', 'b_castle', 'b_pawn']; app.loader.add('spritesheet', 'pieces.json') .load(() => { const textures = key.map(k => PIXI.Texture.from(k)); const sprite = PIXI.Sprite(textures[1]); // 原纹理尺寸过大,缩小到合适比例 sprite.scale.set(0.2); app.stage.addChild(sprite); });
方案2:Promise封装加载流程
如果需要更灵活的异步控制,可将加载过程封装为Promise:
const app = new PIXI.Application(); document.body.appendChild(app.view); const key = ['w_king', 'w_queen', 'w_bishop', 'w_knight', 'w_castle', 'w_pawn', 'b_king', 'b_queen', 'b_bishop', 'b_knight', 'b_castle', 'b_pawn']; function loadSpritesheet() { return new Promise((resolve) => { app.loader.add('spritesheet', 'pieces.json') .load(() => { const textures = key.map(k => PIXI.Texture.from(k)); resolve(textures); }); }); } // 使用async-await简化异步代码 async function initGame() { const textures = await loadSpritesheet(); const sprite = PIXI.Sprite(textures[1]); sprite.scale.set(0.2); app.stage.addChild(sprite); } initGame();
额外注意事项
- JSON文件中
w_king和b_king的spriteSourceSize.h值为32,属于错误配置,应改为426,否则国王棋子会被裁剪显示。 - 原纹理尺寸为426x426,直接添加到舞台会占据过大空间,建议通过
sprite.scale.set()调整到合适大小。
内容的提问来源于stack exchange,提问作者Lyndon Alcock
相关产品推荐
相关产品推荐

