pixijs H5游戏开发入门(四)图片资源加载并显示进度条

本系列文章

本文编写时 pixijs 版本: v7.3.2

效果

本例中使用的静态资源图片:

图片资源来源:http://pixijs.huashengweilai.com/guide/start/8.make-sprite-from-a-tileset-sub-image.html

png 图片:

webp图片:

实际效果:

完整代码在文章最后。

PIXI Assets 加载器

Assets 加载器能加载资源包含:

  • 纹理[textures] (avif, webp, png, jpg, gif, svg)
  • 精灵表[sprite sheets] (json) 有关精灵表的说明可参考:PIXI 精灵表和精灵动画
  • 位图字体[bitmap fonts] (xml, fnt, txt)
  • Web 字体[web fonts] (ttf, woff, woff2)
  • JSON 文件[json files] (json)
  • 文本文件[text files] (txt)

更多复杂用法参考官方文档:https://pixijs.download/v7.3.2/docs/PIXI.Assets.html

使用 Assets 加载图片

可以直接使用文件路径加载图片,获取资源时也需要使用与文件路径相同的字符串。

1
2
3
4
5
6
7
8
9
10
11
// 使用路径加载图片资源
PIXI.Assets.load(['./img/sprite.png'], function(progress) {
// 获取加载进度
console.log(progress);
}).then(res => {
let texture = PIXI.Assets.get("./img/sprite.png"); // 等价于 PIXI.utils.TextureCache["./img/sprite.png"];
let sprite = new PIXI.Sprite(texture);
sprite.x = 10;
sprite.y = 10;
app.stage.addChild(sprite);
});

使用别名加载图片资源

PIXI 中对于一个资源,可以拥有多个别名,但是资源加载只会出发一次。

1
2
3
4
5
6
PIXI.Assets.add({alias: ['burger', 'chicken'], src: './img/sprite.png'});

// PIXI 针对同一个资源永远只会加载一次
let bunny = await PIXI.Assets.load('burger');
let bunny2 = await PIXI.Assets.load('chicken');
// bunny === bunny2 两个资源完全相同 true

同一个资源可使用不同文件格式

同一个图片资源,允许拥有多种图片格式,比如 png 和 webp,如果运行环境支持 webp 格式,那么 Assets 加载器优先加载 webp 资源。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
// 同一个资源可使用不同文件格式
PIXI.Assets.add({alias: 'bunnyBooBoo', src: './img/sprite.{png,webp}'});
// 上面一行代码等价于下面注释代码
/* PIXI.Assets.add({
alias: 'bunnyBooBoo',
src: [
'./img/sprite.webp',
'./img/sprite.png',
],
}); */

let bunnyBooBoo = await PIXI.Assets.load('bunnyBooBoo'); // 如果WebP格式的图片可用,将尝试加载WebP
let sprite2 = new PIXI.Sprite(bunnyBooBoo);
sprite2.x = 10 * 2 + 192;
sprite2.y = 10;
app.stage.addChild(sprite2);

同时加载多个带有别名的资源

可以使用 PIXI.Assets.add 方法将多个资源预先添加到加载器,在使用 PIXI.Assets.load 同时加载多个资源

1
2
3
4
5
6
7
8
9
10
11
12
PIXI.Assets.add({alias: 'pngAlias', src: './img/sprite.png'});
PIXI.Assets.add({alias: 'webpAlias', src: './img/sprite.webp'});
// 同时加载两个带有别名资源
await PIXI.Assets.load(['pngAlias', 'webpAlias'], function (progress) {
console.log('进度条', progress);
});

let texture = PIXI.Assets.get("pngAlias"); // 等价于 PIXI.utils.TextureCache["pngAlias"];
let sprite3 = new PIXI.Sprite(texture);
sprite3.x = 10;
sprite3.y = 10 * 2 + 192;
app.stage.addChild(sprite3);

使用一个纹理绘制不同的精灵

使用一个纹理绘制不同的精灵时,需要先调用纹理的 clone 方法,复制一个新的纹理出来,否则创建精灵的纹理会相互影响!!

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
await PIXI.Assets.load([{alias: 'baseTexture', src: './img/sprite.png'}]);
// 需要调用 clone 方法复制一个纹理,否则 Rectangle 会影响到其他纹理
let texture4 = PIXI.Assets.get('baseTexture').clone(); // 等价于 PIXI.utils.TextureCache['baseTexture'];
let rectangle1 = new PIXI.Rectangle(96, 64, 32, 32); // new PIXI.Rectangle(x, y, width, height);
texture4.frame = rectangle1;
let sprite4 = new PIXI.Sprite(texture4);
sprite4.x = 10 * 2 + 192;
sprite4.y = 10 * 2 + 192;
app.stage.addChild(sprite4);

// 需要调用 clone 方法复制一个纹理,否则 Rectangle 会影响到其他纹理
let texture5 = PIXI.Assets.get('baseTexture').clone(); // 等价于 PIXI.utils.TextureCache['baseTexture'];
let rectangle2 = new PIXI.Rectangle(96, 96, 32, 32); // new PIXI.Rectangle(x, y, width, height);
texture5.frame = rectangle2;
let sprite5 = new PIXI.Sprite(texture5);
sprite5.x = 10 * 2 + 192 + 42;
sprite5.y = 10 * 2 + 192 + 42;
app.stage.addChild(sprite5);

资源分组

资源分组的使用场景:比如有部分资源需要在页面载入时就需要加载,而另一部分资源可以等到游戏进行中再加载。

1
2
3
4
5
6
7
8
9
10
11
12
13
// 资源分组
const group0 = {
'sprite1': './img/sprite.png',
}
const group1 = {
'sprite2': './img/sprite.webp',
}
PIXI.Assets.addBundle('group0', group0)
PIXI.Assets.addBundle('group1', group1)

// 先加载 group0
await PIXI.Assets.loadBundle('group0');
let texture6 = PIXI.Assets.get('sprite1');

文件加载出错异常处理

  • 文件加载出错会报错:

Uncaught (in promise) Error: [Loader.load] Failed to load http://localhost/pixi/img/sprite2.webp.
Error: [WorkerManager.loadImageBitmap] Failed to fetch http://localhost/pixi/img/sprite2.webp: 404 Not Found

可使用 try catch 捕获异常进行异常提示:

1
2
3
4
5
6
7
8
9
10
11
try {
PIXI.Assets.add({alias: 'sprite3', src: './img/sprite.png'});
PIXI.Assets.add({alias: 'sprite4', src: './img/sprite2.png'});
await PIXI.Assets.load(['sprite3', 'sprite4'], function (progress) {
// sprite4 加载失败, progress 永远到不了 1
console.log(progress);
});
} catch (error) {
console.error(error);
alert('网络异常,文件加载失败了');
}

如果文件有部分加载失败,那么本次加载方法的 progress 永远无法到 100% ,所以开发时需要谨慎处理网络异常加载失败的情况。

注: addEventListener 注册 error 事件在新版本中已无法使用。

  • 如果资源别名冲突

PIXI 使用 PIXI.Assets.add 在别名冲突时会在控制台提示:

[Resolver] already has key: sprite1 overwriting

如果使用 await PIXI.Assets.load([{alias: 'baseTexture', src: './img/sprite.png'}]); 加载一个别名冲突文件,则不会给出任何提示。如果文件已加载,则直接返回文件,包括加载一个不存在的文件也会返回先前成功加载的文件。

示例中的完整代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>pixijs入门示例04</title>
<script src="https://pixijs.download/v7.3.2/pixi.js"></script>
<style>
* {margin:0;padding:0}
</style>
</head>
<body>
<script>
async function init() {
// 创建一个 pixi 实例
let app = new PIXI.Application({
antialias: true, // 消除锯齿
width: 414,
height: 414
});

// 插入到 body 中
document.body.appendChild(app.view);

// 使用路径加载图片资源
PIXI.Assets.load(['./img/sprite.png'], function(progress) {
// 获取加载进度
console.log(progress);
}).then(res => {
let texture = PIXI.Assets.get("./img/sprite.png"); // 等价于 PIXI.utils.TextureCache["./img/sprite.png"];
let sprite = new PIXI.Sprite(texture);
sprite.x = 10;
sprite.y = 10;
app.stage.addChild(sprite);
});

// 使用别名加载图片资源
// 同一个资源可以拥有多个别名
PIXI.Assets.add({alias: ['burger', 'chicken'], src: './img/sprite.png'});

let bunny = await PIXI.Assets.load('burger');
let bunny2 = await PIXI.Assets.load('chicken');
// bunny === bunny2 两个资源完全相同 true

// 同一个资源可使用不同文件格式
PIXI.Assets.add({alias: 'bunnyBooBoo', src: './img/sprite.{png,webp}'});
// 上面一行代码等价于下面注释代码
/* PIXI.Assets.add({
alias: 'bunnyBooBoo',
src: [
'./img/sprite.webp',
'./img/sprite.png',
],
}); */

let bunnyBooBoo = await PIXI.Assets.load('bunnyBooBoo'); // 如果WebP格式的图片可用,将尝试加载WebP
let sprite2 = new PIXI.Sprite(bunnyBooBoo);
sprite2.x = 10 * 2 + 192;
sprite2.y = 10;
app.stage.addChild(sprite2);

PIXI.Assets.add({alias: 'pngAlias', src: './img/sprite.png'});
PIXI.Assets.add({alias: 'webpAlias', src: './img/sprite.webp'});
// 同时加载两个带有别名资源
await PIXI.Assets.load(['pngAlias', 'webpAlias'], function (progress) {
console.log('进度条', progress);
});

let texture = PIXI.Assets.get("pngAlias"); // 等价于 PIXI.utils.TextureCache["pngAlias"];
let sprite3 = new PIXI.Sprite(texture);
sprite3.x = 10;
sprite3.y = 10 * 2 + 192;
app.stage.addChild(sprite3);

await PIXI.Assets.load([{alias: 'baseTexture', src: './img/sprite.png'}]);
// 需要调用 clone 方法复制一个纹理,否则 Rectangle 会影响到其他纹理
let texture4 = PIXI.Assets.get('baseTexture').clone(); // 等价于 PIXI.utils.TextureCache['baseTexture'];
let rectangle1 = new PIXI.Rectangle(96, 64, 32, 32); // new PIXI.Rectangle(x, y, width, height);
texture4.frame = rectangle1;
let sprite4 = new PIXI.Sprite(texture4);
sprite4.x = 10 * 2 + 192;
sprite4.y = 10 * 2 + 192;
app.stage.addChild(sprite4);

// 需要调用 clone 方法复制一个纹理,否则 Rectangle 会影响到其他纹理
let texture5 = PIXI.Assets.get('baseTexture').clone(); // 等价于 PIXI.utils.TextureCache['baseTexture'];
let rectangle2 = new PIXI.Rectangle(96, 96, 32, 32); // new PIXI.Rectangle(x, y, width, height);
texture5.frame = rectangle2;
let sprite5 = new PIXI.Sprite(texture5);
sprite5.x = 10 * 2 + 192 + 42;
sprite5.y = 10 * 2 + 192 + 42;
app.stage.addChild(sprite5);

// 资源分组
const group0 = {
'sprite1': './img/sprite.png',
}
const group1 = {
'sprite2': './img/sprite.webp',
}
PIXI.Assets.addBundle('group0', group0)
PIXI.Assets.addBundle('group1', group1)

// 先加载 group0
await PIXI.Assets.loadBundle('group0');
let texture6 = PIXI.Assets.get('sprite1');

/*
Uncaught (in promise) Error: [Loader.load] Failed to load http://localhost/pixi/img/sprite2.webp.
Error: [WorkerManager.loadImageBitmap] Failed to fetch http://localhost/pixi/img/sprite2.webp: 404 Not Found
*/
try {
PIXI.Assets.add({alias: 'sprite3', src: './img/sprite.png'});
PIXI.Assets.add({alias: 'sprite4', src: './img/sprite2.png'});
await PIXI.Assets.load(['sprite3', 'sprite4'], function (progress) {
// sprite4 加载失败, progress 永远到不了 1
console.log(progress);
});
} catch (error) {
console.error(error);
// alert('网络异常,文件加载失败了');
}

}

init();

</script>
</body>
</html>
本文由 linx(544819896@qq.com) 创作,采用 CC BY 4.0 CN协议 进行许可。 可自由转载、引用,但需署名作者且注明文章出处。本文链接为: https://blog.jijian.link/2023-11-24/js-pixi-image/

如果您觉得文章不错,可以点击文章中的广告支持一下!