canvas序列帧动画 & pixi.js

方法一:基于canvas实现多个人物序列帧切换 (原生写法)

class cavasAnimate {
    constructor(id, activeRw) {
        this.id = id;
        this.sourcesRw = {};
        this.canvas = null;
        this.ctx = null;
        this.timer = null;
        this.loadedImages = 0;
        this.numImages = 0;
        this.images = [];
        this.activeRw = activeRw;
        this.init(id)
        this.sourceImg = {}
        this.existKey = []
    }

    init(id) {
        //创建画布
        this.canvas = document.getElementById(id);
        this.canvas.width = this.activeRw.width;
        this.canvas.height = this.activeRw.height;
        this.ctx = this.canvas.getContext("2d");
        this.changeRw(this.activeRw, id);
    }

    changeRw(activeRw) {
        console.log(this.sourceImg);

        // this.timer = null;
        clearInterval(this.timer);
        this.sourcesRw = [];
        this.canvas.width = activeRw.width;
        this.canvas.height = activeRw.height;
        this.ctx.clearRect(0, 0, this.activeRw.width, this.activeRw.height);
        setTimeout(() => {
            console.log(5, Array.isArray(this.sourceImg), this.sourceImg, this.sourceImg.length)
        }, 10000)
        //执行图片预加载,加载完成后播放图片
        this.loadImg(this.sourcesRw, activeRw, (images) => {

            // console.log(1,this.sourcesRw)
            this.activeRw = activeRw;
            clearInterval(this.timer)
            this.playImg(images)
        });
    }

    loadImg(sourcesRw, activeRw, callback) {
        this.loadedImages = 0;
        this.numImages = 0;
        this.images = [];
        this.numImages = this.sourcesRw.length;
        console.log('load')
        if (this.sourceImg) {
            this.existKey = []
            for (let i in this.sourceImg) {
                console.log(i);
                this.existKey.push(i)
            }
            console.log('this.existKey', this.existKey)
        }


        if (this.existKey && this.existKey.indexOf(activeRw.key) > -1) {
            callback(this.sourceImg[activeRw.key]);
            return;
        }

        for (let i = 0; i <= activeRw.num; i++) {
            this.sourcesRw[i] = require('@/assets/images/' + activeRw.key + '/' + activeRw.key + i + '.png');
        }

        for (let i = 0, len = sourcesRw.length; i < len; i++) {
            this.images[i] = new Image();
            //当一张图片加载完成时执行
            this.images[i].onload = () => {
                //当所有图片加载完成时,执行回调函数callback
                this.loadedImages++;
                if (this.loadedImages >= this.numImages) {
                    callback(this.images);
                    this.sourceImg[activeRw.key] = this.images


                }
            };
            //把sourcesRw中的图片信息导入images数组
            this.images[i].src = this.sourcesRw[i];
        }
    }

    playImg(images) {
        let imageNum = images.length;
        let imageNow = 0;
        this.timer = setInterval(() => {
            this.ctx.clearRect(0, 0, this.activeRw.width, this.activeRw.height);
            // this.ctx.globalAlpha=0.9
            this.ctx.drawImage(images[imageNow], 0, 0, this.activeRw.width, this.activeRw.height);
            if (document.getElementById(this.id).parentElement.style.background !== "none") {
                document.getElementById(this.id).parentElement.style.background = "none";
            }

            imageNow++;
            if (imageNow >= imageNum) {
                imageNow = 0;
            }
        }, 70)
    }

    resize() {

    }
}

const animateObj = (id, rwList) => {
    return new cavasAnimate(id, rwList);
};

export default animateObj;
data() {
            return {
                canvasAniObj: null,
                activeIndex: 0,
                timer: null,
                rwArr: [
                    {
                        key: 'hu',
                         1400,
                        height: 1308,
                        num: 107
                    }, {
                        key: 'al',
                         950,
                        height: 1628,
                        num: 66
                    },
                    {
                        key: 'll',
                         1400,
                        height: 1564,
                        num: 67
                    }

                ],
                loaded: false
            };
        },
        watch: {},
        methods: {
            chooseRw(index) {
                console.log(index)
                this.activeIndex = index;
                this.canvasAniObj.changeRw(this.rwArr[index])
                let imgUrl = require('@/assets/images/' + this.rwArr[index].key + '/' + this.rwArr[index].key + '0.png');
                document.getElementById('animation_canvas').parentElement.style.backgroundImage = 'url(' + imgUrl + ')';
            }
        },
        mounted() {
            this.canvasAniObj = cavasAnimation("animation_canvas", this.rwArr[0]
        }

方法一:基于 pixi.js 实现多个人物序列帧切换

import * as PIXI from "pixi.js-legacy";

class animate {
    constructor(id, idGroup, picInfo) {
        if (window.pixiStore === undefined) {
            window.pixiStore = {
                urlList: {},
                callbackID: {
                    part1: 0,
                    part5: 0
                }
            };
        }
        this.idGroup = idGroup;
        this.picInfo = picInfo;
        this.id = id;
        this.app = new PIXI.Application({
            transparent: true,
            forceCanvas: true
        });

        this.anim = null;
        document.getElementById(this.id).innerHTML = "";
        document.getElementById(this.id).appendChild(this.app.view);
    }

    animation(type, retryTimes, callbackID) {
        this.app.stage.removeChild(this.anim);

        let imgs = [];
        let frames = [];

        for (let $i = 0; $i <= this.picInfo[type].imgnum; $i++) {
            let imgUrl = require("@/assets/rw/" +
                this.picInfo[type].folderu +
                type +
                $i +
                ".png");

            if (
                window.pixiStore.urlList[imgUrl] === undefined ||
                window.pixiStore.urlList[imgUrl] === false
            ) {
                window.pixiStore.urlList[imgUrl] = true;
                imgs.push(imgUrl);
            }
        }

        this.app.loader.reset();
        this.app.loader.add(imgs).load(() => {
            if (
                window.pixiStore.callbackID[this.idGroup[this.id]] !==
                callbackID
            ) {
                return;
            }

            let dirty = false;

            for (let $i = 0; $i <= this.picInfo[type].imgnum; $i++) {
                let imgUrl = require("@/assets/rw/" +
                        this.picInfo[type].folderu +
                        type +
                        $i +
                        ".png"),
                    textrue = PIXI.Texture.from(imgUrl);
                if (textrue.orig.width === 1) {
                    window.pixiStore.urlList[imgUrl] = false;
                    PIXI.Texture.removeFromCache(imgUrl);
                    if (dirty === false) {
                        dirty = true;
                    }
                }

                frames.push(textrue);
            }

            if (dirty && retryTimes < 1) {
                retryTimes++;
                this.animation(type, retryTimes, callbackID);
                return;
            } else if (dirty && retryTimes >= 1) {
                return;
            }

            this.app.stage.removeChild(this.anim);
            this.resize(type);

            document.getElementById(this.id).style.background = "none";

            this.anim = new PIXI.AnimatedSprite(frames);
            this.anim.animationSpeed = 20 / 60;
            this.app.stage.addChild(this.anim);
            this.anim.play();
        });
    }

    render(type) {
        document.getElementById(this.id).style.background = "";
        let retryTimes = 0;
        window.pixiStore.callbackID[this.idGroup[this.id]]++;
        this.animation(
            type,
            retryTimes,
            window.pixiStore.callbackID[this.idGroup[this.id]]
        );
    }

    resize(type) {
        let width = document.getElementById(this.id).offsetWidth;
        let height = document.getElementById(this.id).offsetHeight;

        this.app.renderer.resize(width, height);
        this.app.stage.scale.x =
            this.app.renderer.width / this.picInfo[type].width;
        this.app.stage.scale.y =
            this.app.renderer.height / this.picInfo[type].height;
    }
}

const animateObj = (id, idGroup, picInfo) => {
    return new animate(id, idGroup, picInfo);
};

export default animateObj;

mofeiList: [
{
key: "mofei_1",
key2: "hu",
name: "阿狐",
txt:
"澈底的及時享樂主義者,中意一切「風流」的東西:月、酒、花與刀。<br/> 最喜歡的是在盛放中飄散的櫻花。"
},
{
key: "mofei_2",
key2: "al",
name: "埃里克",
txt:
"高能,冰冷、嚴厲、無情的終極兵器機械少女。不過, 倘若這些只是自我掩飾的面具……?"
},
{
key: "mofei_3",
name: "芬德爾",
key2: "fd",
txt:
"濕噠噠黏糊糊的奇異生物。將自己的身體設定成了人類的少女形態,對此非常自得。"
},
},
idGroup: {
"part1-ani": "part1",
part5rw: "part5",
part52rw: "part5"
},

picInfo: {
hu: {
1400,
height: 1308,
folderu: "hu/",
imgnum: 107
},
al: {
950,
height: 1628,
folderu: "al/",
imgnum: 65
},

fd: {
850,
height: 1460,
folderu: "fd/",
imgnum: 83
}
},

methods: { chooseTab(tab) { this.activeTab = tab; this.showAni = false; setTimeout(() => { this.showAni = true; }, 50); if (tab == "buxia") { this.rwList = this.buxiaList; } else { this.rwList = this.mofeiList; } this.$nextTick(() => { this.animateObj.render(this.animateType.key2); }); }, chooseRw(idx) { this.currentRwIndex = idx; this.showAni = false; setTimeout(() => { this.showAni = true; }, 50); this.$nextTick(() => { this.animateObj.render(this.animateType.key2); }); } }, created() { this.rwList = this.mofeiList; }, mounted() { console.log(this.animateType); this.$nextTick(() => { this.animateObj = animate("part5rw", this.idGroup, this.picInfo); this.animateObj.render(this.animateType.key2); }); }
原文地址:https://www.cnblogs.com/catherLee/p/13278292.html