我正在参与「码上挑战赛」概略请看:码上挑战赛来了!

介绍

本期将用 pixi.js 来完结一个水波交互动画,里面包含了水体曲解和点击水波分散的效果,主要利用了 pixi.js 库以及关于它的 filters 滤镜的运用。

演示

正文

基础建立

安装 pixi.js 库:

# NPM
npm i pixi.js -S
# Yarn 
yarn add pixi.js

引进并初始化

import * as PIXI from "pixi.js"
const GAME_WIDTH = 1920;
const GAME_HEIGHT = 1080;
export default class Game {
    constructor(el) {
        return this.init(el)
    }
    init(el) {
        // 初始化
        this.app = new PIXI.Application({
            width: GAME_WIDTH,
            height: GAME_HEIGHT,
        });
        el.appendChild(this.app.view);
        this.loader = new PIXI.Loader();
        this.loader
            .add("bg", "assets/waterwave_0.jpg")
            .add("wave", "assets/waterwave_1.jpg")
            .load(this.render.bind(this))
        return this;
    }
    render(loader, resources) {
        // 烘托
    }
}

初始化便是创立 pixi.js 运用,然后把生成后的视图追加到要传入的 el 元素节点上。这儿我们还要先加载两张图片,一张为水体布景,另一张为水体曲解的错位图。加载完这两种图后,我们才会实行 render 方法进行烘托。

幽默又逼真的水波交互动画

水体曲解

import * as PIXI from "pixi.js"
const GAME_WIDTH = 1920;
const GAME_HEIGHT = 1080;
export default class Game {
    // ...
    render(loader, resources) {
        // 烘托
        this.resources = resources;
        const bg = PIXI.Sprite.from(resources.bg.texture);
        bg.anchor.set(0.5);
        bg.position.set(GAME_WIDTH / 2, GAME_HEIGHT / 2)
        bg.scale.set(.5, .5)
        this.container = new PIXI.Container();
        this.container.interactive = true;
        this.container.buttonMode = true;
        this.container.addChild(bg);
        this.app.stage.addChild(this.container);
    }
}

当然在做曲解效果之前,我们先要把刚才加载好的水体布景制作到界面上。

幽默又逼真的水波交互动画

export default class Game {
    // ...
    render(loader, resources) {
        // ...
        this.container.filters = []
        this.displacementSprite = new PIXI.Sprite.from(resources.wave.texture)
        this.displacementSprite.texture.baseTexture.wrapMode = PIXI.WRAP_MODES.REPEAT;
        this.displacementSprite.scale.set(1);
        const displacementFilter = new PIXI.filters.DisplacementFilter(this.displacementSprite);
        this.container.addChild(this.displacementSprite);
        this.container.filters.push(displacementFilter)
        this.app.ticker.add(this.step.bind(this));
    }
    step() {
        const { displacementSprite } = this;
        displacementSprite.x += 1.7;
        if (displacementSprite.x >= displacementSprite.width) {
            displacementSprite.x = 0;
        }
    }
}

这儿我们用了 pixi.js 内置的过滤器类 DisplacementFilter ,它的效果是做贴图置换,做纹理偏移。

先实例化一个 DisplacementFilter 类,把纹理错位图传入进去,然后把这个过滤器实例添加到 filters 数组里面,最终实行 tickerstep 方法里会接二连三的实行, 经过不断改动 x 轴坐标,来完结纹理偏移水体曲解的效果。

幽默又逼真的水波交互动画

水波动画

我们还要再引进一个 pixi.js 的一个插件库 pixi-filters.js ,它可以处理很多的过滤器效果,水波便是其间一个。

import "./pixi-filters"
export default class Game {
    // ...
    render(loader, resources) {
        // ...
        this.shockwaveFilters = []
        this.container.on('pointerdown', (e) => {
            const { x, y } = e.data.global
            const shockwaveFilter = new PIXI.filters.ShockwaveFilter(
                [x, y],
                {
                    amplitude: 20 + 20 * Math.random(),  // 振幅
                    wavelength: 30 + 10 * Math.random(), // 波长
                    speed: 100 + 100 * Math.random(),    // 速度
                    radius: 80 * Math.random() + 120,    // 半径
                },
                0
            )
            this.shockwaveFilters.push(shockwaveFilter)
            this.container.filters.push(shockwaveFilter)
        });
    }
    step() {
        // ...
        const { shockwaveFilters } = this;
        for (let i = 0; i < shockwaveFilters.length; i++) {
            const filter = shockwaveFilters[i];
            filter.time += .008;
            if (filter.time >= 2) {
                shockwaveFilters.splice(i, 1)
                i--
            }
        }
    }
}

引进 pixi-filters.js 库后,我们就可以用它实例化一个 ShockwaveFilter 类来完结波纹效果,具体来说,便是在点击屏幕容器的时分,会实例化ShockwaveFilter 类,其间可以随机传入振幅、波长、速度、半径等参数,目的是为了让每次点击水波效果都有些许差异。再将这个过滤器添加一个单独的数组中保存,一同还要添加到 filters 中,在 step 方法不断实行的时分,我们就要遍历这个 shockwaveFilters 数组,将它的 time 特点累加就会发生水波效果动画了。可是别忘了,它实行完之后还要记住移除掉,防止占用内存空间。

幽默又逼真的水波交互动画