学习 PixiJS — 动画精灵

5,641 阅读10分钟

说明

看完官方教程中提到的这本书 — Learn Pixi.js ,准备写写读后感了,官方教程中所说的内容,基本上就是书的前4章,所以我就从第5章开始写写吧。

动画精灵指的是按顺序使用一系列略有不同的图像,创建的精灵,之后一帧一帧的播放这些图像,就可以产生运动的幻觉。

也就是说用这种图片

在这里插入图片描述

做出这样的效果

在这里插入图片描述

要制作动画精灵我们需要用到 PixiJSAnimatedSprite 方法。

PIXI.extras.AnimatedSprite

定义:

使用纹理数组创建动画精灵的方法。

用法:

new PIXI.extras.AnimatedSprite(textures,autoUpdate)

参数 :

名称 类型 默认值 描述
textures array 用一系列略有不同的图像做的纹理数组。
autoUpdate boolean true 用来判断是否使用 PIXI.ticker.shared 自动更新动画时间。

返回值:
返回一个对象,对象会有一些属性和方法,用于控制动画精灵。

返回值对象的属性:

名称 类型 描述
animationSpeed number 动画精灵的播放速度。越高越快,越低越慢,默认值是1
currentFrame number(只读) 正在显示的当前帧编号
onComplete function loop属性为false时,一个动画精灵完成播放时调用
playing Boolean 确定当前动画精灵是否正在播放
onFrameChange function 当一个动画精灵更改要呈现的纹理时调用
loop boolean 动画精灵是否在播放后重复播放
onLoop function loop属性为true时调用的函数
textures array 用于这个动画精灵的纹理数组
totalFrames number (只读) 动画中的帧总数

返回值对象的方法:

名称 参数 描述
play 播放动画精灵
gotoAndPlay frameNumber,number类型,开始帧的索引 转到特定的帧并开始播放动画精灵
stop 停止播放动画精灵
gotoAndStop frameNumber,number类型,停止帧的索引 转到特定的帧并停止播放动画精灵

使用返回值中的这些属性和方法,我们就可以控制动画精灵了,比如播放动画精灵,设置动画的速度,设置是否循环播放等,除此之外,还要知道就是 PIXI.extras.AnimatedSprite 方法继承自 PIXI.Sprite 方法,所以动画精灵也可以用普通精灵的属性和方法,比如xywidthheightscalerotation

好的,我们开始试试这个方法。

<!doctype html>
<html lang="zn">

<head>
    <meta charset="UTF-8">
    <title>动画精灵</title>
</head>

<body>
    <div id="px-render"></div>

    <script src="https://www.kkkk1000.com/js/pixi4.8.2.js"></script>
    <script>
        // 创建一个 Pixi应用 需要的一些参数
        let option = {
            width: 400,
            height: 300,
            transparent: true,
        }
        // 创建一个 Pixi应用
        let app = new PIXI.Application(option);
        // 获取渲染器
        let renderer = app.renderer;
        let playground = document.getElementById('px-render');
        // 把 Pixi 创建的 canvas 添加到页面上
        playground.appendChild(renderer.view);

        //设置别名
        let TextureCache = PIXI.utils.TextureCache;
        let Texture = PIXI.Texture;
        let Rectangle = PIXI.Rectangle;
        let AnimatedSprite = PIXI.extras.AnimatedSprite;

        //需要加载的雪碧图的地址(该图片服务器端已做跨域处理)
        let imgURL = "https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2019/1/14/16849ce12c0e953a~tplv-t2oaga2asx-image.image";

        //加载图像,加载完成后执行setup函数 
        PIXI.loader.add(imgURL).load(setup);

        function setup() {
            //获取纹理
            let base = TextureCache[imgURL];

            //第一个纹理
            let texture0 = new Texture(base);
            texture0.frame = new Rectangle(0, 0, 80, 143);
            //第二个纹理
            let texture1 = new Texture(base);
            texture1.frame = new Rectangle(80, 0, 80, 143);
            //第三个纹理
            let texture2 = new Texture(base);
            texture2.frame = new Rectangle(160, 0, 80, 143);
            //第四个纹理
            let texture3 = new Texture(base);
            texture3.frame = new Rectangle(240, 0, 80, 143);

            //创建纹理数组
            let textures = [texture0, texture1, texture2, texture3];
            //创建动画精灵
            let pixie = new PIXI.extras.AnimatedSprite(textures);
            //设置动画精灵的速度
            pixie.animationSpeed = 0.1;

            //把动画精灵添加到舞台
            app.stage.addChild(pixie);
            //播放动画精灵
            pixie.play();
        }
    </script>
</body>

</html>

查看效果

上面这个例子中,创建纹理数组时似乎点麻烦,要解决这个问题,我们可以用名叫 SpriteUtilities 的库,该库包含许多有用的函数,用于创建Pixi精灵并使它们更易于使用。

安装:

直接用 script 标签,引入js 文件就可以

<script src="https://www.kkkk1000.com/js/spriteUtilities.js"></script>

安装好之后,我们需要创建一个新实例,代码如下

let su = new SpriteUtilities(PIXI);

之后就可以用 su 对象访问所有方法了。

我们这里需要用到的就是 su 对象的 filmstrip 方法。

定义:

filmstrip 方法可以自动将雪碧图转换为可用于制作精灵的纹理数组

用法:

su.filmstrip("anyTilesetImage.png", frameWidth, frameHeight, optionalPadding);

参数:

名称 类型 描述
anyTilesetImage string 雪碧图的路径
frameWidth number 每帧的宽度(以像素为单位)
frameHeight number 每帧的高度(以像素为单位)
optionalPadding number 每帧周围的填充量(可选值,以像素为单位)

返回值:

返回一个数组,可用于制作动画精灵的纹理数组。

现在我们使用 SpriteUtilities 来改写下刚才的示例代码。

<!doctype html>
<html lang="zn">

<head>
    <meta charset="UTF-8">
    <title>动画精灵</title>
</head>

<body>
    <div id="px-render"></div>

    <script src="https://www.kkkk1000.com/js/pixi4.8.2.js"></script>
    <script src="https://www.kkkk1000.com/js/spriteUtilities.js"></script>
    <script>
        //创建一个 Pixi应用 需要的一些参数
        let option = {
            width: 400,
            height: 300,
            transparent: true,
        }
        //创建一个 Pixi应用
        let app = new PIXI.Application(option);
        //获取渲染器
        let renderer = app.renderer;
        let playground = document.getElementById('px-render');
        //把 Pixi 创建的 canvas 添加到页面上
        playground.appendChild(renderer.view);

        let su = new SpriteUtilities(PIXI);
        //需要加载的雪碧图的地址(该图片服务器端已做跨域处理)
        let imgURL = "https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2019/1/14/16849ce12c0e953a~tplv-t2oaga2asx-image.image";
        PIXI.loader.add(imgURL).load(setup);

        function setup() {
            //创建纹理数组
            let frames = su.filmstrip(imgURL, 80, 143);
            //创建动画精灵
            let pixie = new PIXI.extras.AnimatedSprite(frames);
            //设置动画精灵的速度
            pixie.animationSpeed = 0.1;

            //把动画精灵添加到舞台
            app.stage.addChild(pixie);
            //播放动画精灵
            pixie.play();
        }
    </script>
</body>

</html>

查看效果

filmstrip 方法自动将整个雪碧图转换为可用于制作动画精灵的纹理数组。但是,如果我们只想使用雪碧图中的一部分帧呢?这时候需要用到 frames 方法了。

定义:

frames 方法使用雪碧图中的一组子帧,来创建纹理数组。

用法:

su.frames(source, coordinates, frameWidth, frameHeight)

参数:

名称 类型 描述
source string 雪碧图的路径
coordinates array 包含每帧的 x 和 y 坐标的二维数组
frameWidth number 每帧的宽度(以像素为单位)
frameHeight number 每帧和高度(以像素为单位)

返回值:
返回一个数组,可用于制作动画精灵的纹理数组。

示例代码:

<!doctype html>
<html lang="zn">

<head>
    <meta charset="UTF-8">
    <title>动画精灵</title>
</head>

<body>
    <div id="px-render"></div>

    <script src="https://www.kkkk1000.com/js/pixi4.8.2.js"></script>
    <script src="https://www.kkkk1000.com/js/spriteUtilities.js"></script>
    <script>
        //创建一个 Pixi应用 需要的一些参数
        let option = {
            width: 400,
            height: 300,
            transparent: true,
        }
        //创建一个 Pixi应用
        let app = new PIXI.Application(option);
        //获取渲染器
        let renderer = app.renderer;
        let playground = document.getElementById('px-render');
        //把 Pixi 创建的 canvas 添加到页面上
        playground.appendChild(renderer.view);

        let su = new SpriteUtilities(PIXI);
        //需要加载的雪碧图的地址(该图片服务器端已做跨域处理)
        let imgURL = "https://p1-jj.byteimg.com/tos-cn-i-t2oaga2asx/gold-user-assets/2019/1/14/16849ce12c0e953a~tplv-t2oaga2asx-image.image";

        PIXI.loader.add(imgURL).load(setup);
        function setup() {
            //创建纹理数组
            let frames = su.frames(imgURL, [[0, 0], [80, 0], [160, 0], [240, 0]], 80, 143);
            //创建动画精灵
            let pixie = new PIXI.extras.AnimatedSprite(frames);
            //设置动画精灵的速度
            pixie.animationSpeed = 0.1;

            //把动画精灵添加到舞台
            app.stage.addChild(pixie);
            //播放动画精灵
            pixie.play();
        }
    </script>
</body>

</html>

查看效果

除了上面提到的方式,还可以用纹理贴图集来创建动画精灵。

使用纹理贴图集来创建动画精灵,就是先通过json文件,加载所有纹理,然后把需要的纹理再放进一个数组中,最后把这个数组当参数,传入PIXI.extras.AnimatedSprite 方法中,来创建动画精灵。

代码:

<!doctype html>
<html lang="zn">

<head>
    <meta charset="UTF-8">
    <title>动画精灵</title>
</head>

<body>
    <div id="px-render"></div>

    <script src="https://www.kkkk1000.com/js/pixi4.8.2.js"></script>
    <script>
        //创建一个 Pixi应用 需要的一些参数
        let option = {
            width: 400,
            height: 300,
            transparent: true,
        }
        //创建一个 Pixi应用
        let app = new PIXI.Application(option);
        //获取渲染器
        let renderer = app.renderer;
        let playground = document.getElementById('px-render');
        //把 Pixi 创建的 canvas 添加到页面上
        playground.appendChild(renderer.view);

        //需要加载的纹理贴图集的地址
        let textureURL = "https://www.kkkk1000.com/images/learnPixiJS-AnimatedSprite/dnf.json";

        //加载纹理贴图集,加载完成后执行setup函数
        PIXI.loader.add(textureURL).load(setup);

        function setup() {
            let id = PIXI.loader.resources[textureURL].textures;

            //创建纹理数组
            let frames = [
                id["dnf0.png"],
                id["dnf1.png"],
                id["dnf2.png"],
                id["dnf3.png"]
            ];
            //创建动画精灵
            let pixie = new PIXI.extras.AnimatedSprite(frames);
            //设置动画精灵的速度
            pixie.animationSpeed = 0.1;

            //把动画精灵添加到舞台
            app.stage.addChild(pixie);
            //播放动画精灵
            pixie.play();
        }
    </script>
</body>

</html>

查看效果

上面的代码创建纹理数组时,是把纹理一个一个的放进数组中,如果数量比较少还好,多一点呢?假如有100个呢?一个一个的放就太麻烦了,这时候我们可以用 SpriteUtilities 库中提供的 frameSeries 方法。

定义:

frameSeries 方法可以通过已加载的纹理贴图集,使用一系列编号的帧ID来创建动画精灵。

用法:

su.frameSeries(startNumber, endNumber, baseName, extension)

参数:

名称 类型 描述
startNumber number 起始帧序列号(默认值是0)
endNumber number 结束帧序列号(默认值是1)
baseName string 可选的基本文件名
extension string 可选的文件扩展名

返回值:
返回一个数组,可用于制作动画精灵的纹理数组。

注意:
使用 frameSeries 方法时,要确保在 json 文件中,定义的每帧的名称都是按顺序来的,比如 frame0.png frame1.png frame2.png 这种。因为 frameSeries 方法的源码是这样写的

 frameSeries(startNumber = 0, endNumber = 1, baseName = "", extension = "") {
   //创建一个数组来存储帧名
   let frames = [];

   for (let i = startNumber; i < endNumber + 1; i++) {
     let frame = this.TextureCache[`${baseName + i + extension}`];
     frames.push(frame);
   }
   return frames;
 }

源码中其实是用 for 循环把帧名拼接起来的。所以要保证帧名是按顺序来的,不然就获取不到了。

下来我们就试试 frameSeries 方法吧。

<!doctype html>
<html lang="zn">

<head>
    <meta charset="UTF-8">
    <title>动画精灵</title>
</head>

<body>
    <div id="px-render"></div>

    <script src="https://www.kkkk1000.com/js/pixi4.8.2.js"></script>
    <script src="https://www.kkkk1000.com/js/spriteUtilities.js"></script>
    <script>
        //创建一个 Pixi应用 需要的一些参数
        let option = {
            width: 400,
            height: 300,
            transparent: true,
        }
        //创建一个 Pixi应用
        let app = new PIXI.Application(option);
        //获取渲染器
        let renderer = app.renderer;
        let playground = document.getElementById('px-render');
        //把 Pixi 创建的 canvas 添加到页面上
        playground.appendChild(renderer.view);

        let su = new SpriteUtilities(PIXI);
        //需要加载的纹理贴图集的地址
        let textureURL = "https://www.kkkk1000.com/images/learnPixiJS-AnimatedSprite/dnf.json";

        PIXI.loader.add(textureURL).load(setup);
        function setup() {
            //创建纹理数组
            debugger;
            let frames = su.frameSeries(0, 7, "dnf", ".png");
            //创建动画精灵
            let pixie = new PIXI.extras.AnimatedSprite(frames);
            //设置动画精灵的速度
            pixie.animationSpeed = 0.1;

            //把动画精灵添加到舞台
            app.stage.addChild(pixie);
            //播放动画精灵
            pixie.play();
        }
    </script>
</body>

</html>

查看效果

注意版本问题:
1、PIXI.extras.AnimatedSprite 这个方法原来叫PIXI.extras.MovieClip ,是在 4.2.1 版本的时候修改的,本文示例代码中用 PixiJS 的版本是 4.8.2,所以没有问题,如果你在使用过程中发现调用PIXI.extras.AnimatedSprite 这个方法有问题,可以先检查下版本是否正确。

2、 SpriteUtilities 目前支持的 PixiJS 的版本是 3.0.11,而 SpriteUtilities 中用的就是PIXI.extras.MovieClip 方法,所以你如果用了比较高的 PixiJS 的版本,需要在SpriteUtilities 中修改下方法的别名。

spriteUtilities.js 文件中需要把 renderingEngine.extras.MovieClip 改成renderingEngine.extras.AnimatedSprite,把 renderingEngine.ParticleContainer 改成 PIXI.particles.ParticleContainer

这个 spriteUtilities.js 就是修改后的。

当然你也可以使用低版本的 PixiJS,这样就不用改 spriteUtilities.js 的代码了。

总结

动画精灵就是逐帧动画,通过一帧一帧的播放图像来产生运动的幻觉。

本文就是聊了聊创建动画精灵的一些方式和如何使用动画精灵。

如果文中有错误的地方,还请小伙伴们指出,万分感谢。

下一篇 学习 PixiJS — 精灵状态