const { ccclass, property, requireComponent, menu } = cc._decorator; @ccclass("State_AnimationRandomPlay") export class State_AnimationRandomPlay { @property({ displayName: "最少時間", type: cc.Float }) public mintime: number = 0; @property({ displayName: "最多時間", type: cc.Float }) public maxtime: number = 0; @property({ displayName: "權重", type: cc.Integer }) public weight: number = 0; @property({ displayName: "動畫", type: cc.AnimationClip }) public clip: cc.AnimationClip = null; } @ccclass @menu("Plug-in/Animation/AnimationRandomPlay") @requireComponent(cc.Animation) /** 可以根據權重決定多久後隨機播放甚麼動畫 */ export class AnimationRandomPlay extends cc.Component { //#region public 外調參數 @property({ type: State_AnimationRandomPlay }) public states: State_AnimationRandomPlay[] = []; //#endregion //#region public 屬性 public nowPlayName: string = ""; public nextPlayName: string = ""; public nextPlayTime: number = null; //#endregion //#region private 屬性 private _animation: cc.Animation = null; private _weightAll: number[] = []; private _weightAllNum: number = 0; //#endregion //#region get set get animation(): cc.Animation { if (this._animation == null) { this._animation = this.node.getComponent(cc.Animation); } return this._animation; } //#endregion //#region Lifecycle onLoad(): void { let self: this = this; let weight: number = 0; for (let i: number = 0; i < this.states.length; i++) { weight += this.states[i].weight; this._weightAll.push(weight); this._weightAllNum += this.states[i].weight; } // 一般動畫 this.animation.on("finished", () => { self.GetNextAnim(); }, this); // 不一般動畫 (X // Loop動畫 this.animation.on("lastframe", () => { self.animation.setCurrentTime(0); self.animation.stop(); self.GetNextAnim(); }, this); } onEnable(): void { this.GetNextAnim(); } onDisable(): void { this.nextPlayName = ""; this.nextPlayTime = null; this.animation.setCurrentTime(0); this.animation.stop(); } onDestroy(): void { this.animation.targetOff(this); // let self: this = this; // this.animation.off("finished", () => { // self.GetNextAnim(); // }, this); // this.animation.off("lastframe", () => { // self.animation.setCurrentTime(0); // self.animation.stop(); // self.GetNextAnim(); // }, this); } update(dt: number): void { let time: number = Date.now(); if (this.nextPlayTime && time >= this.nextPlayTime) { this.nowPlayName = this.nextPlayName; if (this.animation.getAnimationState(this.nextPlayName)) { this.animation.play(this.nextPlayName); } else { console.error(`this node(${this.node.name}) not has animation(${this.nextPlayName})`); this.animation.addClip(this.GetClip_From_states(this.nextPlayName)); if (this.animation.getAnimationState(this.nextPlayName)) { console.warn(`this node(${this.node.name}) add animation(${this.nextPlayName})`); this.animation.play(this.nextPlayName); } } this.nextPlayName = ""; this.nextPlayTime = null; } } //#endregion //#region Custom Function /** 取得下一隻動畫的時間&名稱 */ GetNextAnim(): void { let random: number = Math.floor(Math.random() * this._weightAllNum) + 1; for (let i: number = 0; i < this._weightAll.length; i++) { if (random <= this._weightAll[i]) { let time: number = Math.floor(Math.random() * (this.states[i].maxtime - this.states[i].mintime + 1)) + this.states[i].mintime; this.nextPlayTime = Date.now() + (time * 1000); this.nextPlayName = this.states[i].clip.name; // if (CC_DEBUG) { // let date: Date = new Date(this.nextPlayTime); // console.log(`nextWaitTime: ${time}, nextPlayTime: ${date.getHours()}:${date.getMinutes()}:${date.getSeconds()}, nextPlayName: ${this.nextPlayName}`); // } break; } } } /** 取得下一隻動畫的時間&名稱 */ GetClip_From_states(name: string): cc.AnimationClip { for (let i: number = 0; i < this.states.length; i++) { if (this.states[i].clip.name === name) { return this.states[i].clip; } } } //#endregion }