UNPKG

dragonbones-runtime

Version:

the tools to build dragonbones file for diffrent framework

757 lines (689 loc) 24.8 kB
////////////////////////////////////////////////////////////////////////////////////// // // Copyright (c) 2014-present, Egret Technology. // All rights reserved. // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistributions of source code must retain the above copyright // notice, this list of conditions and the following disclaimer. // * Redistributions in binary form must reproduce the above copyright // notice, this list of conditions and the following disclaimer in the // documentation and/or other materials provided with the distribution. // * Neither the name of the Egret nor the // names of its contributors may be used to endorse or promote products // derived from this software without specific prior written permission. // // THIS SOFTWARE IS PROVIDED BY EGRET AND CONTRIBUTORS "AS IS" AND ANY EXPRESS // OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES // OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. // IN NO EVENT SHALL EGRET AND CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, // INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;LOSS OF USE, DATA, // OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, // EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // ////////////////////////////////////////////////////////////////////////////////////// namespace egret { /** * @version Egret 2.4 * @platform Web,Native * @includeExample extension/game/display/MovieClip.ts * @language en_US */ /** * 影片剪辑,可以通过影片剪辑播放序列帧动画。MovieClip 类从以下类继承而来:DisplayObject 和 EventDispatcher。不同于 DisplayObject 对象,MovieClip 对象拥有一个时间轴。 * @extends egret.DisplayObject * @event egret.Event.COMPLETE 动画播放完成。 * @event egret.Event.LOOP_COMPLETE 动画循环播放完成。循环最后一次只派发 COMPLETE 事件,不派发 LOOP_COMPLETE 事件。 * @see http://edn.egret.com/cn/docs/page/596 MovieClip序列帧动画 * @version Egret 2.4 * @platform Web,Native * @includeExample extension/game/display/MovieClip.ts * @language zh_CN */ export class MovieClip extends DisplayObject { //Render Property $bitmapData: Texture = null; //Render Property private offsetPoint: Point = Point.create(0, 0); //Data Property $movieClipData: MovieClipData = null; /** * @private */ private frames: any[] = null; /** * @private */ $totalFrames: number = 0; /** * @version Egret 2.4 * @platform Web,Native * @private */ public frameLabels: any[] = null; /** * @private */ $frameLabelStart: number = 0; /** * @private */ $frameLabelEnd: number = 0; /** * @version Egret 2.4 * @platform Web,Native * @private */ public frameEvents: any[] = null; /** * @private */ private frameIntervalTime: number = 0; /** * @private */ $eventPool: string[] = null; //Animation Property $isPlaying: boolean = false; /** * @private */ private isStopped: boolean = true; /** * @private */ private playTimes: number = 0; /** * @private */ $currentFrameNum: number = 0; /** * @private */ $nextFrameNum: number = 1; /** * @private */ private displayedKeyFrameNum: number = 0; /** * @private */ private passedTime: number = 0; /** * @private */ private $frameRate: number = NaN; //Construct Function /** * 创建新的 MovieClip 实例。创建 MovieClip 之后,调用舞台上的显示对象容器的addElement方法。 * @param movieClipData {movieClipData} 被引用的 movieClipData 对象 * @version Egret 2.4 * @platform Web,Native */ constructor(movieClipData?: MovieClipData) { super(); this.$smoothing = Bitmap.defaultSmoothing; this.$renderNode = new sys.NormalBitmapNode(); this.setMovieClipData(movieClipData); } /** * @private */ $smoothing: boolean; /** * Whether or not is smoothed when scaled. * @version Egret 3.0 * @platform Web * @language en_US */ /** * 控制在缩放时是否进行平滑处理。 * @version Egret 3.0 * @platform Web * @language zh_CN */ public get smoothing(): boolean { return this.$smoothing; } public set smoothing(value: boolean) { value = !!value; if (value == this.$smoothing) { return; } this.$smoothing = value; } /** * @private * */ $init() { this.$reset(); let movieClipData: MovieClipData = this.$movieClipData; if (movieClipData && movieClipData.$isDataValid()) { this.frames = movieClipData.frames; this.$totalFrames = movieClipData.numFrames; this.frameLabels = movieClipData.labels; this.frameEvents = movieClipData.events; this.$frameRate = movieClipData.frameRate; this.frameIntervalTime = 1000 / this.$frameRate; this._initFrame(); } } /** * @private * */ $reset(): void { this.frames = null; this.playTimes = 0; this.$isPlaying = false; this.setIsStopped(true); this.$currentFrameNum = 0; this.$nextFrameNum = 1; this.displayedKeyFrameNum = 0; this.passedTime = 0; this.$eventPool = []; } /** * @private * */ private _initFrame(): void { if (this.$movieClipData.$isTextureValid()) { this.advanceFrame(); this.constructFrame(); } } /** * @private */ $updateRenderNode(): void { let texture = this.$bitmapData; if (texture) { let offsetX: number = Math.round(this.offsetPoint.x); let offsetY: number = Math.round(this.offsetPoint.y); let bitmapWidth: number = texture.$bitmapWidth; let bitmapHeight: number = texture.$bitmapHeight; let textureWidth: number = texture.$getTextureWidth(); let textureHeight: number = texture.$getTextureHeight(); let destW: number = Math.round(texture.$getScaleBitmapWidth()); let destH: number = Math.round(texture.$getScaleBitmapHeight()); let sourceWidth: number = texture.$sourceWidth; let sourceHeight: number = texture.$sourceHeight; sys.BitmapNode.$updateTextureData(<sys.NormalBitmapNode>this.$renderNode, texture.$bitmapData, texture.$bitmapX, texture.$bitmapY, bitmapWidth, bitmapHeight, offsetX, offsetY, textureWidth, textureHeight, destW, destH, sourceWidth, sourceHeight, egret.BitmapFillMode.SCALE, this.$smoothing); } } /** * @private */ $measureContentBounds(bounds: Rectangle): void { let texture = this.$bitmapData; if (texture) { let x: number = this.offsetPoint.x; let y: number = this.offsetPoint.y; let w: number = texture.$getTextureWidth(); let h: number = texture.$getTextureHeight(); bounds.setTo(x, y, w, h); } else { bounds.setEmpty(); } } /** * @private * * @param stage * @param nestLevel */ $onAddToStage(stage: Stage, nestLevel: number): void { super.$onAddToStage(stage, nestLevel); if (this.$isPlaying && this.$totalFrames > 1) { this.setIsStopped(false); } } /** * @private * */ $onRemoveFromStage(): void { super.$onRemoveFromStage(); this.setIsStopped(true); } //Data Function /** * @private * 返回帧标签为指定字符串的FrameLabel对象 * @param labelName {string} 帧标签名 * @param ignoreCase {boolean} 是否忽略大小写,可选参数,默认false * @returns {egret.FrameLabel} FrameLabel对象 */ private getFrameLabelByName(labelName: string, ignoreCase: boolean = false): FrameLabel { if (ignoreCase) { labelName = labelName.toLowerCase(); } let frameLabels = this.frameLabels; if (frameLabels) { let outputFramelabel: FrameLabel = null; for (let i = 0; i < frameLabels.length; i++) { outputFramelabel = frameLabels[i]; if (ignoreCase ? outputFramelabel.name.toLowerCase() == labelName : outputFramelabel.name == labelName) { return outputFramelabel; } } } return null; } /** * @private * 根据帧标签,设置开始和结束的帧数 * @param labelName {string} 帧标签名 */ private getFrameStartEnd(labelName: string): void { let frameLabels = this.frameLabels; if (frameLabels) { let outputFramelabel: FrameLabel = null; for (let i = 0; i < frameLabels.length; i++) { outputFramelabel = frameLabels[i]; if (labelName == outputFramelabel.name) { this.$frameLabelStart = outputFramelabel.frame; this.$frameLabelEnd = outputFramelabel.end; break; } } } } /** * @private * 返回指定序号的帧的FrameLabel对象 * @param frame {number} 帧序号 * @returns {egret.FrameLabel} FrameLabel对象 */ private getFrameLabelByFrame(frame: number): FrameLabel { let frameLabels = this.frameLabels; if (frameLabels) { let outputFramelabel: FrameLabel = null; for (let i = 0; i < frameLabels.length; i++) { outputFramelabel = frameLabels[i]; if (outputFramelabel.frame == frame) { return outputFramelabel; } } } return null; } /** * @private * 返回指定序号的帧对应的FrameLabel对象,如果当前帧没有标签,则返回前面最近的有标签的帧的FrameLabel对象 * @method egret.MovieClip#getFrameLabelForFrame * @param frame {number} 帧序号 * @returns {egret.FrameLabel} FrameLabel对象 */ private getFrameLabelForFrame(frame: number): FrameLabel { let outputFrameLabel: FrameLabel = null; let tempFrameLabel: FrameLabel = null; let frameLabels = this.frameLabels; if (frameLabels) { for (let i = 0; i < frameLabels.length; i++) { tempFrameLabel = frameLabels[i]; if (tempFrameLabel.frame > frame) { return outputFrameLabel; } outputFrameLabel = tempFrameLabel; } } return outputFrameLabel; } //Animation Function /** * 继续播放当前动画 * @param playTimes {number} 播放次数。 参数为整数,可选参数,>=1:设定播放次数,<0:循环播放,默认值 0:不改变播放次数(MovieClip初始播放次数设置为1), * @version Egret 2.4 * @platform Web,Native */ public play(playTimes: number = 0): void { this.$isPlaying = true; this.setPlayTimes(playTimes); if (this.$totalFrames > 1 && this.$stage) { this.setIsStopped(false); } } /** * 暂停播放动画 * @version Egret 2.4 * @platform Web,Native */ public stop(): void { this.$isPlaying = false; this.setIsStopped(true); } /** * 将播放头移到前一帧并停止 * @version Egret 2.4 * @platform Web,Native */ public prevFrame(): void { this.gotoAndStop(this.$currentFrameNum - 1); } /** * 跳到后一帧并停止 * @version Egret 2.4 * @platform Web,Native */ public nextFrame(): void { this.gotoAndStop(this.$currentFrameNum + 1); } /** * 将播放头移到指定帧并播放 * @param frame {any} 指定帧的帧号或帧标签 * @param playTimes {number} 播放次数。 参数为整数,可选参数,>=1:设定播放次数,<0:循环播放,默认值 0:不改变播放次数, * @version Egret 2.4 * @platform Web,Native */ public gotoAndPlay(frame: string | number, playTimes: number = 0): void { if (arguments.length == 0 || arguments.length > 2) { egret.$error(1022, "MovieClip.gotoAndPlay()"); } if (typeof frame === "string") { this.getFrameStartEnd(frame); } else { this.$frameLabelStart = 0; this.$frameLabelEnd = 0; } this.play(playTimes); this.gotoFrame(frame); } /** * 将播放头移到指定帧并停止 * @param frame {any} 指定帧的帧号或帧标签 * @version Egret 2.4 * @platform Web,Native */ public gotoAndStop(frame: string | number): void { if (arguments.length != 1) { egret.$error(1022, "MovieClip.gotoAndStop()"); } this.stop(); this.gotoFrame(frame); } /** * @private * * @param frame */ private gotoFrame(frame: string | number): void { let frameNum: number; if (typeof frame === "string") { frameNum = this.getFrameLabelByName(frame).frame; } else { frameNum = parseInt(frame + '', 10); if (<any>frameNum != frame) { egret.$error(1022, "Frame Label Not Found"); } } if (frameNum < 1) { frameNum = 1; } else if (frameNum > this.$totalFrames) { frameNum = this.$totalFrames; } if (frameNum == this.$nextFrameNum) { return; } this.$nextFrameNum = frameNum; this.advanceFrame(); this.constructFrame(); this.handlePendingEvent(); } /** * @private */ private lastTime: number = 0; /** * @private * * @param advancedTime * @returns */ private advanceTime(timeStamp: number): boolean { let self = this; let advancedTime: number = timeStamp - self.lastTime; self.lastTime = timeStamp; let frameIntervalTime: number = self.frameIntervalTime; let currentTime = self.passedTime + advancedTime; self.passedTime = currentTime % frameIntervalTime; let num: number = currentTime / frameIntervalTime; if (num < 1) { return false; } while (num >= 1) { num--; self.$nextFrameNum++; if (self.$nextFrameNum > self.$totalFrames || (self.$frameLabelStart > 0 && self.$nextFrameNum > self.$frameLabelEnd)) { if (self.playTimes == -1) { self.$eventPool.push(Event.LOOP_COMPLETE); self.$nextFrameNum = 1; } else { self.playTimes--; if (self.playTimes > 0) { self.$eventPool.push(Event.LOOP_COMPLETE); self.$nextFrameNum = 1; } else { self.$nextFrameNum = self.$totalFrames; self.$eventPool.push(Event.COMPLETE); self.stop(); break; } } } if (self.$currentFrameNum == self.$frameLabelEnd) { self.$nextFrameNum = self.$frameLabelStart; } self.advanceFrame(); } self.constructFrame(); self.handlePendingEvent(); return false; } /** * @private * */ private advanceFrame(): void { this.$currentFrameNum = this.$nextFrameNum; let event = this.frameEvents[this.$nextFrameNum]; if (event && event != "") { MovieClipEvent.dispatchMovieClipEvent(this, MovieClipEvent.FRAME_LABEL, event); } } /** * @private * */ private constructFrame() { let self = this; let currentFrameNum: number = self.$currentFrameNum; if (self.displayedKeyFrameNum == currentFrameNum) { return; } self.$bitmapData = self.$movieClipData.getTextureByFrame(currentFrameNum); self.$movieClipData.$getOffsetByFrame(currentFrameNum, self.offsetPoint); self.displayedKeyFrameNum = currentFrameNum; self.$renderDirty = true; let p = self.$parent; if (p && !p.$cacheDirty) { p.$cacheDirty = true; p.$cacheDirtyUp(); } let maskedObject = self.$maskedObject; if (maskedObject && !maskedObject.$cacheDirty) { maskedObject.$cacheDirty = true; maskedObject.$cacheDirtyUp(); } } /** * @private * */ public $renderFrame(): void { let self = this; self.$bitmapData = self.$movieClipData.getTextureByFrame(self.$currentFrameNum); self.$renderDirty = true; let p = self.$parent; if (p && !p.$cacheDirty) { p.$cacheDirty = true; p.$cacheDirtyUp(); } let maskedObject = self.$maskedObject; if (maskedObject && !maskedObject.$cacheDirty) { maskedObject.$cacheDirty = true; maskedObject.$cacheDirtyUp(); } } /** * @private * */ private handlePendingEvent(): void { if (this.$eventPool.length != 0) { this.$eventPool.reverse(); let eventPool = this.$eventPool; let length = eventPool.length; let isComplete = false; let isLoopComplete = false; for (let i = 0; i < length; i++) { let event: string = eventPool.pop(); if (event == Event.LOOP_COMPLETE) { isLoopComplete = true; } else if (event == Event.COMPLETE) { isComplete = true; } else { this.dispatchEventWith(event); } } if (isLoopComplete) { this.dispatchEventWith(Event.LOOP_COMPLETE); } if (isComplete) { this.dispatchEventWith(Event.COMPLETE); } } } //Properties /** * MovieClip 实例中帧的总数 * @version Egret 2.4 * @platform Web,Native */ public get totalFrames(): number { return this.$totalFrames; } /** * MovieClip 实例当前播放的帧的序号 * @version Egret 2.4 * @platform Web,Native */ public get currentFrame(): number { return this.$currentFrameNum; } /** * MovieClip 实例当前播放的帧的标签。如果当前帧没有标签,则 currentFrameLabel返回null。 * @version Egret 2.4 * @platform Web,Native */ public get currentFrameLabel(): string { let label = this.getFrameLabelByFrame(this.$currentFrameNum); return label && label.name; } /** * 当前播放的帧对应的标签,如果当前帧没有标签,则currentLabel返回包含标签的先前帧的标签。如果当前帧和先前帧都不包含标签,currentLabel返回null。 * @version Egret 2.4 * @platform Web,Native */ public get currentLabel(): string { let label: FrameLabel = this.getFrameLabelForFrame(this.$currentFrameNum); return label ? label.name : null; } /** * MovieClip 实例的帧频 * @version Egret 2.4 * @platform Web,Native */ public get frameRate(): number { return this.$frameRate; } public set frameRate(value: number) { if (value == this.$frameRate) { return; } this.$frameRate = value; this.frameIntervalTime = 1000 / this.$frameRate; } /** * MovieClip 实例当前是否正在播放 * @version Egret 2.4 * @platform Web,Native */ public get isPlaying(): boolean { return this.$isPlaying; } /** * MovieClip数据源 */ public set movieClipData(value: MovieClipData) { this.setMovieClipData(value); } /** * @version Egret 2.4 * @platform Web,Native */ public get movieClipData(): MovieClipData { return this.$movieClipData; } /** * @private * * @param value */ private setMovieClipData(value: MovieClipData) { if (this.$movieClipData == value) { return; } this.$movieClipData = value; this.$init(); } /** * @private * * @param value */ private setPlayTimes(value: number) { if (value < 0 || value >= 1) { this.playTimes = value < 0 ? -1 : Math.floor(value); } } /** * @private * * @param value */ private setIsStopped(value: boolean) { if (this.isStopped == value) { return; } this.isStopped = value; if (value) { ticker.$stopTick(this.advanceTime, this); } else { this.playTimes = this.playTimes == 0 ? 1 : this.playTimes; this.lastTime = egret.getTimer(); ticker.$startTick(this.advanceTime, this); } } } }