const { ccclass, property, executeInEditMode, playOnFocus } = cc._decorator; /** * 帧动画播放组件 * ### 开放的接口; * #### play 播放 * #### stop 停止播放 * #### gotoAndPlay 跳转到某帧并播放 * #### gotoAndStop 跳转到某帧并停止播放 * #### isPlayEnd 是否播放结束 * ### 开放的事件 * #### completeTimes 单次播完完成事件 * #### complete 全部次数完成事件 * @author 薛鸿潇 */ @ccclass @executeInEditMode() @playOnFocus() export default class FrameAnimation extends cc.Component { @property({ displayName: '精灵纹理', type: cc.SpriteFrame }) private images: cc.SpriteFrame[] = []; @property({ displayName: '每帧间隔' }) private frameTime: number = 0.1; @property({ displayName: '播放次数' }) private playTimes: number = 0; @property({ displayName: "是否倒播", tooltip: "勾选,倒着播放,不钩,顺序播放" }) private reverse: boolean = false; @property({ displayName: '自动播放' }) private autoPlayOnLoad: boolean = true; @property({ displayName: "自动销毁", tooltip: '播完自动销毁' }) private autoDestroy: boolean = false; @property({ displayName: "每帧回调", type: cc.Component.EventHandler }) onFrameCall: cc.Component.EventHandler = new cc.Component.EventHandler(); @property({ displayName: "结束回调", type: cc.Component.EventHandler }) onCompleteCall: cc.Component.EventHandler = new cc.Component.EventHandler(); /** 编辑器预览 */ private _edit_play: boolean = false; @property({ displayName: '编辑器预览' }) get edit_play(): boolean { if (this._edit_play && !this.edit_playing) { this.edit_playing = true; this.play(); } this.running = this._edit_play; return this._edit_play; } set edit_play(v: boolean) { this._edit_play = v; } /** 编辑器是否正在播放 */ private edit_playing = false; /** 动画帧数量 */ public frameNum: number = 0; /** 当前帧下标 */ public frameIndex: number = 0; /** 下一帧下标 */ public nextFrameIndex: number = 0; /** 是否允许播放 */ public running: boolean = true; /** 精灵组件 */ private comp_spr: cc.Sprite; /** 播放下一帧的倒计时 */ private time: number = 0; /** 每完成一轮的回调 */ public completeTimesCallback: Function; /** 全部播完回调 */ public completeCallback: Function; /** 每帧回调 */ public frameCallback: Function; /** 当前轮播次数 */ private currentTimes: number = 0; onLoad() { this.comp_spr = this.getComponent(cc.Sprite); } start() { if (this.images.length != 0) { this.frameNum = this.images.length; } if (this.reverse) { this.frameIndex = this.frameNum - 1; this.nextFrameIndex = this.frameNum - 1; } if (CC_EDITOR) { this.running = this.edit_playing; } else { this.running = this.autoPlayOnLoad; } } update(dt) { if (!this.running) return; if (this.images.length == 0) return; if (this.playTimes != 0 && this.currentTimes > this.playTimes) { this.running = false; return; } this.time -= dt; if (this.time <= 0) { this.time = this.frameTime; if (!this.reverse) { this.frameIndex = this.nextFrameIndex % this.frameNum; this.nextFrameIndex = this.frameIndex + 1; } else { this.frameIndex = (this.nextFrameIndex + this.frameNum) % this.frameNum; this.nextFrameIndex = this.frameIndex - 1; } this.playing(); if (this.frameIndex == 0) { this.playEnd(); } } } /** 播放中 */ private playing() { this.comp_spr.spriteFrame = this.images[this.frameIndex]; if (this.comp_spr.spriteFrame) { var rect: cc.Rect = this.comp_spr.spriteFrame.getRect(); this.node.width = rect.width; this.node.height = rect.height; } // 事件回调 this.onFrameCall.emit([]); if (this.frameCallback != null) { this.frameCallback(this.frameIndex); } } /** 播放结束 */ private playEnd() { this.currentTimes++; // 完成一次 this.node.emit("completeTimes", this.currentTimes); if (this.completeTimesCallback != null) { this.completeTimesCallback(this.currentTimes); } // 全部完成 if (this.playTimes != 0 && this.currentTimes > this.playTimes) { // 事件回调 this.node.emit("complete"); this.onCompleteCall.emit([]); if (this.completeCallback != null) { this.completeCallback(); } if (this.autoDestroy && !CC_EDITOR) { this.node.destroy(); } // this.edit_play = false; this._edit_play = false; this.edit_playing = false; } } /** * 开始播放 * @param frameCallback * @param completeCallback */ public play(frameCallback: Function = null, completeCallback: Function = null) { this.frameCallback = frameCallback; this.completeCallback = completeCallback; this.running = true; this.frameIndex = 0; this.currentTimes = 0; this.time = this.frameTime; if (this.images.length != 0) { this.frameNum = this.images.length; if (this.reverse) { this.frameIndex = this.frameNum - 1; this.nextFrameIndex = this.frameNum - 1; } } if (!this.comp_spr) { this.comp_spr = this.getComponent(cc.Sprite); } if (this.comp_spr) this.comp_spr.spriteFrame = this.images[0]; if (this.comp_spr.spriteFrame) { var rect: cc.Rect = this.comp_spr.spriteFrame.getRect(); this.node.width = rect.width; this.node.height = rect.height; } } /** * 跳转到某帧并开始播放 * @param frameIndex 帧下标 */ public gotoAndPlay(frameIndex: number) { if (!this.comp_spr) { this.comp_spr = this.getComponent(cc.Sprite); } this.running = true; this.frameIndex = frameIndex; this.nextFrameIndex = frameIndex; this.currentTimes = 0; } /** 停止 */ public stop() { this.running = false; } /** * 跳转到某帧并停止播放 * @param frameIndex 帧下标 */ public gotoAndStop(frameIndex: number) { this.frameIndex = frameIndex; if (this.frameIndex < 0) this.frameIndex = 0; if (this.frameIndex > this.images.length - 1) this.frameIndex = this.images.length - 1; if (!this.comp_spr) { this.comp_spr = this.getComponent(cc.Sprite); } this.comp_spr.spriteFrame = this.images[this.frameIndex]; if (this.comp_spr.spriteFrame) { var rect: cc.Rect = this.comp_spr.spriteFrame.getRect(); this.node.width = rect.width; this.node.height = rect.height; } this.running = false; } /** * 是否播放结束 * @returns */ public isPlayEnd(): boolean { return this.frameIndex == this.frameNum; } }