fix:编辑器文件导入. add:example,runtime

This commit is contained in:
YipLee
2021-01-24 19:29:37 +08:00
parent c232a91a41
commit 91f4d8011b
214 changed files with 41328 additions and 120 deletions

View File

@@ -1,29 +0,0 @@
// import AnimatorBase from "./lib/AnimatorBase";
// const { ccclass, property, requireComponent } = cc._decorator;
// /** DragonBones状态机组件 */
// @ccclass
// @requireComponent(dragonBones.ArmatureDisplay)
// export default class AnimatorDragonBones extends AnimatorBase {
// /** DragonBones组件 */
// private _dragonBones: dragonBones.ArmatureDisplay = null;
// protected start() {
// this._dragonBones = this.getComponent(dragonBones.ArmatureDisplay);
// if (this.AssetRawUrl !== null) {
// this.initJson(this.AssetRawUrl.json);
// }
// this._dragonBones.addEventListener(dragonBones.EventObject.COMPLETE, this.onAnimFinished, this);
// }
// public playAnimation(animName: string, loop: boolean) {
// this._dragonBones.playAnimation(animName, loop ? 0 : -1);
// }
// public scaleTime(scale: number) {
// if (scale > 0)
// this._dragonBones.timeScale = scale;
// }
// }

View File

@@ -1,45 +0,0 @@
// import AnimatorBase from "./lib/AnimatorBase";
// const { ccclass, property, requireComponent } = cc._decorator;
// /** Spine状态机组件 */
// @ccclass
// @requireComponent(sp.Skeleton)
// export default class AnimatorSpine extends AnimatorBase {
// spine: sp.Skeleton = null;
// listeners: Array<Function>;
// protected start(): void {
// this.listeners = new Array<Function>();
// this.spine = this.getComponent(sp.Skeleton);
// if (this.AssetRawUrl !== null) {
// this.initJson(this.AssetRawUrl.json);
// }
// this.spine.setCompleteListener(this.spineAniStateEvent.bind(this));
// this.spine.setEventListener(this.spineAniEvent.bind(this));
// }
// private spineAniStateEvent(obj, trackIndex, type, event, loopCount): void {
// this._animatorController.onAnimationComplete();
// }
// private spineAniEvent(track, event): void {
// for (let i = 0; i < this.listeners.length; i++) {
// this.listeners[i](track, event);
// }
// }
// public addEventListener(cb: Function): void {
// this.listeners.push(cb);
// }
// public playAnimation(aniName: string, loop: boolean): void {
// this.spine.setAnimation(0, aniName, loop);
// }
// public scaleTime(scale: number): void {
// if (scale > 0)
// this.spine.timeScale = scale;
// }
// }

View File

@@ -1,26 +1,31 @@
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import AnimatorStateLogic from "./core/AnimatorStateLogic";
const { ccclass, property, requireComponent } = cc._decorator;
const { ccclass, property, requireComponent, disallowMultiple } = cc._decorator;
/** Animation状态机组件 */
/**
* Cocos Animation状态机组件
*/
@ccclass
@disallowMultiple
@requireComponent(cc.Animation)
export default class AnimatorAnimation extends AnimatorBase {
/** Animation组件 */
private _animation: cc.Animation = null;
/** 当前的动画实例 */
private _animState: cc.AnimationState = null;
/** 记录初始的wrapmode */
private _wrapModeMap: Map<cc.AnimationState, cc.WrapMode> = new Map();
protected onLoad() {
if (!this.PlayOnLoad || this._hasInit) {
protected start() {
if (!this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
this._animation = this.getComponent(cc.Animation);
this._animation.on("finished", this.onAnimFinished, this);
this._animation.on("lastframe", this.onAnimFinished, this);
this._animation.on(cc.Animation.EventType.FINISHED, this.onAnimFinished, this);
this._animation.on(cc.Animation.EventType.LASTFRAME, this.onAnimFinished, this);
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
@@ -35,7 +40,7 @@ export default class AnimatorAnimation extends AnimatorBase {
* @override
*/
public onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
if (this.PlayOnLoad || this._hasInit) {
if (this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
@@ -43,8 +48,8 @@ export default class AnimatorAnimation extends AnimatorBase {
this.initArgs(...args);
this._animation = this.getComponent(cc.Animation);
this._animation.on("finished", this.onAnimFinished, this);
this._animation.on("lastframe", this.onAnimFinished, this);
this._animation.on(cc.Animation.EventType.FINISHED, this.onAnimFinished, this);
this._animation.on(cc.Animation.EventType.LASTFRAME, this.onAnimFinished, this);
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
@@ -58,8 +63,18 @@ export default class AnimatorAnimation extends AnimatorBase {
* @param loop
*/
protected playAnimation(animName: string, loop: boolean) {
if (!animName) {
return;
}
this._animState = this._animation.play(animName);
this._animState.wrapMode = loop ? cc.WrapMode.Loop : cc.WrapMode.Default;
if (!this._animState) {
return;
}
if (!this._wrapModeMap.has(this._animState)) {
this._wrapModeMap.set(this._animState, this._animState.wrapMode);
}
this._animState.wrapMode = loop ? cc.WrapMode.Loop : this._wrapModeMap.get(this._animState);
}
/**
@@ -68,7 +83,8 @@ export default class AnimatorAnimation extends AnimatorBase {
* @param scale
*/
protected scaleTime(scale: number) {
if (scale > 0 && this._animState)
if (this._animState) {
this._animState.speed = scale;
}
}
}

View File

@@ -1,11 +1,18 @@
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import AnimatorStateLogic from "./core/AnimatorStateLogic";
const { ccclass, property, requireComponent } = cc._decorator;
const { ccclass, property, requireComponent, disallowMultiple } = cc._decorator;
/** 纸娃娃系统状态机组件 */
/**
*
*/
@ccclass
export default class AnimatorAvatar extends AnimatorBase {
@disallowMultiple
export default class AnimatorCustomization extends AnimatorBase {
/** 此组件必须主动调用onInit初始化 */
@property({ override: true, visible: false })
protected PlayOnStart: boolean = false;
/**
* 0-3
* - onStateChangeCall
@@ -33,7 +40,7 @@ export default class AnimatorAvatar extends AnimatorBase {
* @param loop
*/
protected playAnimation(animName: string, loop: boolean) {
if (this._animationPlayer) {
if (this._animationPlayer && animName) {
this._animationPlayer.playAnimation(animName, loop);
}
}

View File

@@ -0,0 +1,71 @@
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import AnimatorStateLogic from "./core/AnimatorStateLogic";
const { ccclass, property, requireComponent, disallowMultiple } = cc._decorator;
/**
* DragonBones状态机组件
*/
@ccclass
@disallowMultiple
@requireComponent(dragonBones.ArmatureDisplay)
export default class AnimatorDragonBones extends AnimatorBase {
/** DragonBones组件 */
private _dragonBones: dragonBones.ArmatureDisplay = null;
protected start() {
if (!this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
this._dragonBones = this.getComponent(dragonBones.ArmatureDisplay);
this._dragonBones.addEventListener(dragonBones.EventObject.COMPLETE, this.onAnimFinished, this);
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
}
}
/**
* 手动初始化状态机可传入0-3个参数类型如下
* - onStateChangeCall 状态切换时的回调
* - stateLogicMap 各个状态逻辑控制
* - animationPlayer 自定义动画控制
* @override
*/
public onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
if (this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
this.initArgs(...args);
this._dragonBones = this.getComponent(dragonBones.ArmatureDisplay);
this._dragonBones.addEventListener(dragonBones.EventObject.COMPLETE, this.onAnimFinished, this);
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
}
}
/**
* 播放动画
* @override
* @param animName 动画名
* @param loop 是否循环播放
*/
protected playAnimation(animName: string, loop: boolean) {
animName && this._dragonBones.playAnimation(animName, loop ? 0 : -1);
}
/**
* 缩放动画播放速率
* @override
* @param scale 缩放倍率
*/
protected scaleTime(scale: number) {
this._dragonBones.timeScale = scale;
}
}

View File

@@ -0,0 +1,120 @@
import AnimatorSpineSecondary from "./AnimatorSpineSecondary";
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import AnimatorStateLogic from "./core/AnimatorStateLogic";
const { ccclass, property, requireComponent, disallowMultiple } = cc._decorator;
/**
* Spine状态机组件主状态机trackIndex为0
*/
@ccclass
@disallowMultiple
@requireComponent(sp.Skeleton)
export default class AnimatorSpine extends AnimatorBase {
/** spine组件 */
private _spine: sp.Skeleton = null;
/** 动画完成的回调 */
private _completeListenerMap: Map<(entry?: any) => void, any> = new Map();
/** 次状态机注册的回调 */
private _secondaryListenerMap: Map<(entry?: any) => void, AnimatorSpineSecondary> = new Map();
protected start() {
if (!this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
this._spine = this.getComponent(sp.Skeleton);
this._spine.setCompleteListener(this.onSpineComplete.bind(this));
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
}
}
/**
* 手动初始化状态机可传入0-3个参数类型如下
* - onStateChangeCall 状态切换时的回调
* - stateLogicMap 各个状态逻辑控制
* - animationPlayer 自定义动画控制
* @override
*/
public onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
if (this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
this.initArgs(...args);
this._spine = this.getComponent(sp.Skeleton);
this._spine.setCompleteListener(this.onSpineComplete.bind(this));
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
}
}
private onSpineComplete(entry: any) {
entry.trackIndex === 0 && this.onAnimFinished();
this._completeListenerMap.forEach((target, cb) => { target ? cb.call(target, entry) : cb(entry); });
this._secondaryListenerMap.forEach((target, cb) => { entry.trackIndex === target.TrackIndex && cb.call(target, entry); });
}
/**
* 播放动画
* @override
* @param animName 动画名
* @param loop 是否循环播放
*/
protected playAnimation(animName: string, loop: boolean) {
if (animName) {
this._spine.setAnimation(0, animName, loop);
} else {
this._spine.clearTrack(0);
}
}
/**
* 缩放动画播放速率
* @override
* @param scale 缩放倍率
*/
protected scaleTime(scale: number) {
this._spine.timeScale = scale;
}
/**
* 注册次状态机动画结束的回调(状态机内部方法,不能由外部直接调用)
*/
public addSecondaryListener(cb: (entry?: any) => void, target: AnimatorSpineSecondary) {
this._secondaryListenerMap.set(cb, target);
}
/**
* 注册动画完成时的监听
* @param cb 回调
* @param target 调用回调的this对象
*/
public addCompleteListener(cb: (entry?: any) => void, target: any = null) {
if (this._completeListenerMap.has(cb)) {
return;
}
this._completeListenerMap.set(cb, target);
}
/**
* 注销动画完成的监听
* @param cb 回调
*/
public removeCompleteListener(cb: (entry?: any) => void) {
this._completeListenerMap.delete(cb);
}
/**
* 清空动画完成的监听
*/
public clearCompleteListener() {
this._completeListenerMap.clear;
}
}

View File

@@ -0,0 +1,72 @@
import AnimatorSpine from "./AnimatorSpine";
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import AnimatorStateLogic from "./core/AnimatorStateLogic";
const { ccclass, property, requireComponent } = cc._decorator;
/**
* Spine状态机组件次状态机同一节点可添加多个用于在不同track中播放动画trackIndex必须大于0
*/
@ccclass
@requireComponent(sp.Skeleton)
export default class AnimatorSpineSecondary extends AnimatorBase {
@property({ tooltip: CC_DEV && '动画播放的trackIndex必须大于0' }) TrackIndex: number = 1;
/** 主状态机 */
private _main: AnimatorSpine = null;
/** spine组件 */
private _spine: sp.Skeleton = null;
protected start() {
if (!this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
this._spine = this.getComponent(sp.Skeleton);
this._main = this.getComponent(AnimatorSpine);
this._main.addSecondaryListener(this.onAnimFinished, this);
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
}
}
/**
* 手动初始化状态机可传入0-3个参数类型如下
* - onStateChangeCall 状态切换时的回调
* - stateLogicMap 各个状态逻辑控制
* - animationPlayer 自定义动画控制
* @override
*/
public onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
if (this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
this.initArgs(...args);
this._spine = this.getComponent(sp.Skeleton);
this._main = this.getComponent(AnimatorSpine);
this._main.addSecondaryListener(this.onAnimFinished, this);
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
}
}
/**
* 播放动画
* @override
* @param animName 动画名
* @param loop 是否循环播放
*/
protected playAnimation(animName: string, loop: boolean) {
if (animName) {
this._spine.setAnimation(this.TrackIndex, animName, loop);
} else {
this._spine.clearTrack(this.TrackIndex);
}
}
}

View File

@@ -9,7 +9,7 @@ const { ccclass, property, executionOrder } = cc._decorator;
*/
export interface AnimationPlayer {
/** 设置动画播放结束的回调 */
setFinishedCallback(callback: (event: cc.Event.EventCustom) => void, target?: any): void;
setFinishedCallback(callback: () => void, target: any): void;
/** 播放动画 */
playAnimation(animName: string, loop: boolean): void;
/** 缩放动画播放速率 */
@@ -25,8 +25,8 @@ export default class AnimatorBase extends cc.Component {
@property({ type: cc.JsonAsset, tooltip: CC_DEV && '状态机json文件' })
protected AssetRawUrl: cc.JsonAsset = null;
@property({ tooltip: CC_DEV && '是否在onLoad中自动启动状态机' })
protected PlayOnLoad: boolean = true;
@property({ tooltip: CC_DEV && '是否在start中自动启动状态机' })
protected PlayOnStart: boolean = true;
@property({ tooltip: CC_DEV && '是否在update中自动触发状态机逻辑更新' })
protected AutoUpdate: boolean = true;
@@ -43,10 +43,11 @@ export default class AnimatorBase extends cc.Component {
/** 自定义的动画播放控制器 */
protected _animationPlayer: AnimationPlayer = null;
/** 当前状态名 */
public get curStateName(): string {
return this._ac.curState.name;
}
/** 当前动画名 */
public get curStateMotion(): string {
return this._ac.curState.motion;
}
@@ -150,9 +151,7 @@ export default class AnimatorBase extends cc.Component {
*
*/
public onStateChange(fromState: AnimatorState, toState: AnimatorState) {
if (toState.motion && toState.motion !== "") {
this.playAnimation(toState.motion, toState.loop);
}
this.playAnimation(toState.motion, toState.loop);
let fromStateName = fromState ? fromState.name : '';

View File

@@ -77,6 +77,7 @@ export default class AnimatorController {
public onAnimationComplete() {
this.animComplete = true;
this.animCompleteState = this._curState;
// cc.log(`animation complete: ${this._curState.name}`);
}
/**

View File

@@ -36,7 +36,7 @@ export default class AnimatorState {
for (let i = 0; i < data.transitions.length; i++) {
let transition: AnimatorTransition = new AnimatorTransition(data.transitions[i], ac);
transition.isValid && this._transitions.push(transition);
transition.isValid() && this._transitions.push(transition);
}
}

View File

@@ -2,9 +2,6 @@
*
*/
export default class AnimatorStateLogic {
constructor() {
}
/**
*
* @virtual

View File

@@ -0,0 +1,92 @@
import { Animation, AnimationState, _decorator, __private } from "cc";
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import AnimatorStateLogic from "./core/AnimatorStateLogic";
const { ccclass, property, requireComponent, disallowMultiple } = _decorator;
/**
* Cocos Animation状态机组件
*/
@ccclass
@disallowMultiple
@requireComponent(Animation)
export default class AnimatorAnimation extends AnimatorBase {
/** Animation组件 */
private _animation: Animation = null!;
/** 当前的动画实例 */
private _animState: AnimationState = null!;
/** 记录初始的wrapmode */
private _wrapModeMap: Map<AnimationState, number> = new Map();
protected start() {
if (!this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
this._animation = this.getComponent(Animation)!;
this._animation.on(Animation.EventType.FINISHED, this.onAnimFinished, this);
this._animation.on(Animation.EventType.LASTFRAME, this.onAnimFinished, this);
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
}
}
/**
* 手动初始化状态机可传入0-3个参数类型如下
* - onStateChangeCall 状态切换时的回调
* - stateLogicMap 各个状态逻辑控制
* - animationPlayer 自定义动画控制
* @override
*/
public onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
if (this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
this.initArgs(...args);
this._animation = this.getComponent(Animation)!;
this._animation.on(Animation.EventType.FINISHED, this.onAnimFinished, this);
this._animation.on(Animation.EventType.LASTFRAME, this.onAnimFinished, this);
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
}
}
/**
* 播放动画
* @override
* @param animName 动画名
* @param loop 是否循环播放
*/
protected playAnimation(animName: string, loop: boolean) {
if (!animName) {
return;
}
this._animation.play(animName);
this._animState = this._animation.getState(animName);
if (!this._animState) {
return;
}
if (!this._wrapModeMap.has(this._animState)) {
this._wrapModeMap.set(this._animState, this._animState.wrapMode);
}
this._animState.wrapMode = loop ? 2 : this._wrapModeMap.get(this._animState)!;
}
/**
* 缩放动画播放速率
* @override
* @param scale 缩放倍率
*/
protected scaleTime(scale: number) {
if (this._animState) {
this._animState.speed = scale;
}
}
}

View File

@@ -0,0 +1,59 @@
import { _decorator } from "cc";
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import AnimatorStateLogic from "./core/AnimatorStateLogic";
const { ccclass, property, requireComponent, disallowMultiple } = _decorator;
/**
* 自定义动画控制的状态机组件
*/
@ccclass
@disallowMultiple
export default class AnimatorCustomization extends AnimatorBase {
/** 此组件必须主动调用onInit初始化 */
@property({ override: true, visible: false })
protected PlayOnStart: boolean = false;
/**
* 手动初始化状态机可传入0-3个参数类型如下
* - onStateChangeCall 状态切换时的回调
* - stateLogicMap 各个状态逻辑控制
* - animationPlayer 自定义动画控制
* @override
*/
public onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
if (this._hasInit) {
return;
}
this._hasInit = true;
this.initArgs(...args);
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
}
}
/**
* 播放动画
* @override
* @param animName 动画名
* @param loop 是否循环播放
*/
protected playAnimation(animName: string, loop: boolean) {
if (this._animationPlayer && animName) {
this._animationPlayer.playAnimation(animName, loop);
}
}
/**
* 缩放动画播放速率
* @override
* @param scale 缩放倍率
*/
protected scaleTime(scale: number) {
if (this._animationPlayer) {
this._animationPlayer.scaleTime(scale);
}
}
}

View File

@@ -0,0 +1,74 @@
import { dragonBones, _decorator } from "cc";
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import AnimatorStateLogic from "./core/AnimatorStateLogic";
const { ccclass, property, requireComponent, disallowMultiple } = _decorator;
/**
* DragonBones状态机组件
*/
@ccclass
@disallowMultiple
@requireComponent(dragonBones.ArmatureDisplay)
export default class AnimatorDragonBones extends AnimatorBase {
/** DragonBones组件 */
private _dragonBones: dragonBones.ArmatureDisplay = null!;
protected start() {
if (!this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
this._dragonBones = this.getComponent(dragonBones.ArmatureDisplay)!;
this._dragonBones.addEventListener('complete', this.onAnimFinished, this);
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
}
}
/**
* 手动初始化状态机可传入0-3个参数类型如下
* - onStateChangeCall 状态切换时的回调
* - stateLogicMap 各个状态逻辑控制
* - animationPlayer 自定义动画控制
* @override
*/
public onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
if (this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
this.initArgs(...args);
this._dragonBones = this.getComponent(dragonBones.ArmatureDisplay)!;
this._dragonBones.addEventListener('complete', this.onAnimFinished, this);
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
}
}
/**
* 播放动画
* @override
* @param animName 动画名
* @param loop 是否循环播放
*/
protected playAnimation(animName: string, loop: boolean) {
if (animName)
this._dragonBones.playAnimation(animName, loop ? 0 : -1);
}
/**
* 缩放动画播放速率
* @override
* @param scale 缩放倍率
*/
protected scaleTime(scale: number) {
if (scale > 0)
this._dragonBones.timeScale = scale;
}
}

View File

@@ -0,0 +1,122 @@
import { sp, _decorator } from "cc";
import AnimatorSpineSecondary from "./AnimatorSpineSecondary";
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import AnimatorStateLogic from "./core/AnimatorStateLogic";
const { ccclass, property, requireComponent, disallowMultiple } = _decorator;
/**
* Spine状态机组件主状态机trackIndex为0
*/
@ccclass
@disallowMultiple
@requireComponent(sp.Skeleton)
export default class AnimatorSpine extends AnimatorBase {
/** spine组件 */
private _spine: sp.Skeleton = null!;
/** 动画完成的回调 */
private _completeListenerMap: Map<(entry?: any) => void, any> = new Map();
/** 次状态机注册的回调 */
private _secondaryListenerMap: Map<(entry?: any) => void, AnimatorSpineSecondary> = new Map();
protected start() {
if (!this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
this._spine = this.getComponent(sp.Skeleton)!;
this._spine.setCompleteListener(this.onSpineComplete.bind(this));
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
}
}
/**
* 手动初始化状态机可传入0-3个参数类型如下
* - onStateChangeCall 状态切换时的回调
* - stateLogicMap 各个状态逻辑控制
* - animationPlayer 自定义动画控制
* @override
*/
public onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
if (this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
this.initArgs(...args);
this._spine = this.getComponent(sp.Skeleton)!;
this._spine.setCompleteListener(this.onSpineComplete.bind(this));
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
}
}
private onSpineComplete(entry: any) {
entry.trackIndex === 0 && this.onAnimFinished();
this._completeListenerMap.forEach((target, cb) => { target ? cb.call(target, entry) : cb(entry); });
this._secondaryListenerMap.forEach((target, cb) => { entry.trackIndex === target.TrackIndex && cb.call(target, entry); });
}
/**
* 播放动画
* @override
* @param animName 动画名
* @param loop 是否循环播放
*/
protected playAnimation(animName: string, loop: boolean) {
if (animName) {
this._spine.setAnimation(0, animName, loop);
} else {
this._spine.clearTrack(0);
}
}
/**
* 缩放动画播放速率
* @override
* @param scale 缩放倍率
*/
protected scaleTime(scale: number) {
if (scale > 0)
this._spine.timeScale = scale;
}
/**
* 注册次状态机动画结束的回调(状态机内部方法,不能由外部直接调用)
*/
public addSecondaryListener(cb: (entry?: any) => void, target: AnimatorSpineSecondary) {
this._secondaryListenerMap.set(cb, target);
}
/**
* 注册动画完成时的监听
* @param cb 回调
* @param target 调用回调的this对象
*/
public addCompleteListener(cb: (entry?: any) => void, target: any = null) {
if (this._completeListenerMap.has(cb)) {
return;
}
this._completeListenerMap.set(cb, target);
}
/**
* 注销动画完成的监听
* @param cb 回调
*/
public removeCompleteListener(cb: (entry?: any) => void) {
this._completeListenerMap.delete(cb);
}
/**
* 清空动画完成的监听
*/
public clearCompleteListener() {
this._completeListenerMap.clear;
}
}

View File

@@ -0,0 +1,73 @@
import { sp, _decorator } from "cc";
import AnimatorSpine from "./AnimatorSpine";
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import AnimatorStateLogic from "./core/AnimatorStateLogic";
const { ccclass, property, requireComponent } = _decorator;
/**
* Spine状态机组件次状态机同一节点可添加多个用于在不同track中播放动画trackIndex必须大于0
*/
@ccclass
@requireComponent(sp.Skeleton)
export default class AnimatorSpineSecondary extends AnimatorBase {
@property({ tooltip: '动画播放的trackIndex必须大于0' }) TrackIndex: number = 1;
/** 主状态机 */
private _main: AnimatorSpine = null!;
/** spine组件 */
private _spine: sp.Skeleton = null!;
protected start() {
if (!this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
this._spine = this.getComponent(sp.Skeleton)!;
this._main = this.getComponent(AnimatorSpine)!;
this._main.addSecondaryListener(this.onAnimFinished, this);
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
}
}
/**
* 手动初始化状态机可传入0-3个参数类型如下
* - onStateChangeCall 状态切换时的回调
* - stateLogicMap 各个状态逻辑控制
* - animationPlayer 自定义动画控制
* @override
*/
public onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
if (this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
this.initArgs(...args);
this._spine = this.getComponent(sp.Skeleton)!;
this._main = this.getComponent(AnimatorSpine)!;
this._main.addSecondaryListener(this.onAnimFinished, this);
if (this.AssetRawUrl !== null) {
this.initJson(this.AssetRawUrl.json);
}
}
/**
* 播放动画
* @override
* @param animName 动画名
* @param loop 是否循环播放
*/
protected playAnimation(animName: string, loop: boolean) {
if (animName) {
this._spine.setAnimation(this.TrackIndex, animName, loop);
} else {
this._spine.clearTrack(this.TrackIndex);
}
}
}

View File

@@ -0,0 +1,228 @@
import { Component, JsonAsset, _decorator } from 'cc';
import AnimatorController from "./AnimatorController";
import AnimatorState from "./AnimatorState";
import AnimatorStateLogic from "./AnimatorStateLogic";
const { ccclass, property, executionOrder } = _decorator;
/**
* 自定义控制动画播放的接口
*/
export interface AnimationPlayer {
/** 设置动画播放结束的回调 */
setFinishedCallback(callback: () => void, target: any): void;
/** 播放动画 */
playAnimation(animName: string, loop: boolean): void;
/** 缩放动画播放速率 */
scaleTime(scale: number): void;
}
/**
* 状态机组件基类 优先执行生命周期
*/
@ccclass
@executionOrder(-1000)
export default class AnimatorBase extends Component {
@property({ type: JsonAsset, tooltip: '状态机json文件' })
protected AssetRawUrl: JsonAsset = null!;
@property({ tooltip: '是否在start中自动启动状态机' })
protected PlayOnStart: boolean = true;
@property({ tooltip: '是否在update中自动触发状态机逻辑更新' })
protected AutoUpdate: boolean = true;
/** 是否初始化 */
protected _hasInit: boolean = false;
/** 状态机控制 */
protected _ac: AnimatorController = null!;
/** 各个状态逻辑控制key为状态名 */
protected _stateLogicMap: Map<string, AnimatorStateLogic> = null!;
/** 状态切换时的回调 */
protected _onStateChangeCall: (fromState: string, toState: string) => void = null!;
/** 自定义的动画播放控制器 */
protected _animationPlayer: AnimationPlayer = null!;
/** 当前状态名 */
public get curStateName(): string {
return this._ac.curState.name;
}
/** 当前动画名 */
public get curStateMotion(): string {
return this._ac.curState.motion;
}
/**
* 手动初始化状态机可传入0-3个参数类型如下
* - onStateChangeCall 状态切换时的回调
* - stateLogicMap 各个状态逻辑控制
* - animationPlayer 自定义动画控制
* @virtual
*/
public onInit(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
}
/**
* 处理初始化参数
*/
protected initArgs(...args: Array<Map<string, AnimatorStateLogic> | ((fromState: string, toState: string) => void) | AnimationPlayer>) {
args.forEach((arg) => {
if (!arg) {
return;
}
if (typeof arg === 'function') {
this._onStateChangeCall = arg;
} else if (typeof arg === 'object') {
if (arg instanceof Map) {
this._stateLogicMap = arg;
} else {
this._animationPlayer = arg;
this._animationPlayer.setFinishedCallback(this.onAnimFinished, this);
}
}
});
}
private updateAnimator() {
// 混合当前动画播放速度
let playSpeed = this._ac.curState.speed;
if (this._ac.curState.multi) {
playSpeed *= this._ac.params.getNumber(this._ac.curState.multi) || 1;
}
this.scaleTime(playSpeed);
// 更新AnimatorStateLogic
if (this._stateLogicMap) {
let curLogic = this._stateLogicMap.get(this._ac.curState.name);
curLogic && curLogic.onUpdate();
}
// 更新状态机逻辑
this._ac.updateAnimator();
}
protected update() {
if (this._hasInit && this.AutoUpdate) {
this.updateAnimator();
}
}
/**
* 手动调用更新
*/
public manualUpdate() {
if (this._hasInit && !this.AutoUpdate) {
this.updateAnimator();
}
}
/**
* 解析状态机json文件
*/
protected initJson(json: any) {
this._ac = new AnimatorController(this, json);
}
/**
* 动画结束的回调
*/
protected onAnimFinished() {
this._ac.onAnimationComplete();
}
/**
* 播放动画
* @virtual
* @param animName 动画名
* @param loop 是否循环播放
*/
protected playAnimation(animName: string, loop: boolean) {
}
/**
* 缩放动画播放速率
* @virtual
* @param scale 缩放倍率
*/
protected scaleTime(scale: number) {
}
/**
* 状态切换时的逻辑(状态机内部方法,不能由外部直接调用)
*/
public onStateChange(fromState: AnimatorState, toState: AnimatorState) {
this.playAnimation(toState.motion, toState.loop);
let fromStateName = fromState ? fromState.name : '';
if (this._stateLogicMap) {
let fromLogic = this._stateLogicMap.get(fromStateName);
fromLogic && fromLogic.onExit();
let toLogic = this._stateLogicMap.get(toState.name);
toLogic && toLogic.onEntry();
}
this._onStateChangeCall && this._onStateChangeCall(fromStateName, toState.name);
}
/**
* 设置boolean类型参数的值
*/
public setBool(key: string, value: boolean) {
this._ac.params.setBool(key, value);
}
/**
* 获取boolean类型参数的值
*/
public getBool(key: string): boolean {
return this._ac.params.getBool(key) !== 0;
}
/**
* 设置number类型参数的值
*/
public setNumber(key: string, value: number) {
this._ac.params.setNumber(key, value);
}
/**
* 获取number类型参数的值
*/
public getNumber(key: string): number {
return this._ac.params.getNumber(key);
}
/**
* 设置trigger类型参数的值
*/
public setTrigger(key: string) {
this._ac.params.setTrigger(key);
}
/**
* 重置trigger类型参数的值
*/
public resetTrigger(key: string) {
this._ac.params.resetTrigger(key);
}
/**
* 设置autoTrigger类型参数的值autoTrigger类型参数不需要主动reset每次状态机更新结束后会自动reset
*/
public autoTrigger(key: string) {
this._ac.params.autoTrigger(key);
}
/**
* 无视条件直接跳转状态
* @param 状态名
*/
public play(stateName: string) {
if (!this._hasInit) {
return;
}
this._ac.play(stateName);
}
}

View File

@@ -0,0 +1,82 @@
import { error } from "cc";
import AnimatorController from "./AnimatorController";
/** 参数类型 */
export enum ParamType {
COMPLETE = 0,
BOOLEAN = 1,
NUMBER = 2,
TRIGGER = 3,
AUTO_TRIGGER = 4
}
/** 逻辑类型 */
export enum LogicType {
EQUAL = 0,
NOTEQUAL = 1,
GREATER = 2,
LESS = 3,
GREATER_EQUAL = 4,
LESS_EQUAL = 5
}
/**
* 单项条件
*/
export default class AnimatorCondition {
private _ac: AnimatorController;
/** 此条件对应的参数名 */
private _param: string = "";
/** 此条件对应的值 */
private _value: number = 0;
/** 此条件与值比较的逻辑 */
private _logic: LogicType = LogicType.EQUAL;
constructor(data: any, ac: AnimatorController) {
this._ac = ac;
this._param = data.param;
this._value = data.value;
this._logic = data.logic;
}
public getParamName() {
return this._param;
}
public getParamType(): ParamType {
return this._ac.params.getParamType(this._param);
}
/** 判断此条件是否满足 */
public check(): boolean {
let type: ParamType = this.getParamType();
if (type === ParamType.BOOLEAN) {
return this._ac.params.getBool(this._param) === this._value;
} else if (type === ParamType.NUMBER) {
let value: number = this._ac.params.getNumber(this._param);
switch (this._logic) {
case LogicType.EQUAL:
return value === this._value;
case LogicType.NOTEQUAL:
return value !== this._value;
case LogicType.GREATER:
return value > this._value;
case LogicType.LESS:
return value < this._value;
case LogicType.GREATER_EQUAL:
return value >= this._value;
case LogicType.LESS_EQUAL:
return value <= this._value;
default:
return false;
}
} else if (type === ParamType.AUTO_TRIGGER) {
return this._ac.params.getAutoTrigger(this._param) !== 0;
} else if (type === ParamType.TRIGGER) {
return this._ac.params.getTrigger(this._param) !== 0;
} else {
error(`[AnimatorCondition.check] 错误的type: ${type}`);
return false;
}
}
}

View File

@@ -0,0 +1,119 @@
import { error } from "cc";
import AnimatorBase from "./AnimatorBase";
import AnimatorParams from "./AnimatorParams";
import AnimatorState from "./AnimatorState";
/**
* 状态机控制类
*/
export default class AnimatorController {
private _jsonData: any = null;
private _animator: AnimatorBase = null!;
private _params: AnimatorParams = null!;
private _states: Map<string, AnimatorState> = null!;
private _anyState: AnimatorState = null!;
private _curState: AnimatorState = null!;
/** 状态切换次数 */
private _changeCount: number = 0;
/** 对应animComplete的状态 */
public animCompleteState: AnimatorState = null!;
/** 动画播放完毕的标记 */
public animComplete: boolean = false;
/** 当前运行的状态 */
public get curState(): AnimatorState { return this._curState; }
public get params(): AnimatorParams { return this._params; }
constructor(player: AnimatorBase, json: any) {
this._animator = player;
this._jsonData = json;
this._states = new Map<string, AnimatorState>();
this._params = new AnimatorParams(json.parameters);
this.init(json);
}
/**
* 初始化状态机所有动画状态
*/
private init(json: any) {
if (json.states.length <= 0) {
error(`[AnimatorController.init] 状态机json错误`);
return;
}
let defaultState: string = json.defaultState;
this._anyState = new AnimatorState(json.anyState, this);
for (let i = 0; i < json.states.length; i++) {
let state: AnimatorState = new AnimatorState(json.states[i], this);
this._states.set(state.name, state);
}
this.changeState(defaultState);
}
private updateState() {
this._curState.checkAndTrans();
if (this._curState !== this._anyState && this._anyState !== null) {
this._anyState.checkAndTrans();
}
}
/**
* 更新状态机逻辑
*/
public updateAnimator() {
// 重置计数
this._changeCount = 0;
this.updateState();
// 重置动画完成标记
if (this.animComplete && this.animCompleteState.loop) {
this.animComplete = false;
}
// 重置autoTrigger
this.params.resetAllAutoTrigger();
}
public onAnimationComplete() {
this.animComplete = true;
this.animCompleteState = this._curState;
// cc.log(`animation complete: ${this._curState.name}`);
}
/**
* 无视条件直接跳转状态
* @param 状态名
*/
public play(stateName: string) {
if (!this._states.has(stateName) || this._curState.name === stateName) {
return;
}
// 重置动画完成标记
this.animComplete = false;
this.changeState(stateName);
}
/**
* 切换动画状态
*/
public changeState(stateName: string) {
this._changeCount++;
if (this._changeCount > 1000) {
error('[AnimatorController.changeState] error: 状态切换递归调用超过1000次transition设置可能出错!');
return;
}
if (this._states.has(stateName) && (this._curState === null || this._curState.name !== stateName)) {
let oldState = this._curState;
this._curState = this._states.get(stateName)!;
this._animator.onStateChange(oldState, this._curState);
this.updateState();
} else {
error(`[AnimatorController.changeState] error state: ${stateName}`);
}
}
}

View File

@@ -0,0 +1,121 @@
import { ParamType } from "./AnimatorCondition";
/**
* 参数结构
*/
interface Param {
type: ParamType;
value: number;
}
/**
* 状态机参数
*/
export default class AnimatorParams {
private _paramMap: Map<string, Param> = new Map();
constructor(dataArr: any[]) {
dataArr.forEach((data: any) => {
let param: Param = {
type: data.type,
value: data.init
};
this._paramMap.set(data.param, param);
});
}
public getParamType(key: string): ParamType {
let param: Param = this._paramMap.get(key)!;
if (param) {
return param.type;
} else {
return null!;
}
}
public setNumber(key: string, value: number) {
let param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.NUMBER) {
param.value = value;
}
}
public setBool(key: string, value: boolean) {
let param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.BOOLEAN) {
param.value = value ? 1 : 0;
}
}
public setTrigger(key: string) {
let param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.TRIGGER) {
param.value = 1;
}
}
public resetTrigger(key: string) {
let param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.TRIGGER) {
param.value = 0;
}
}
public autoTrigger(key: string) {
let param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.AUTO_TRIGGER) {
param.value = 1;
}
}
public resetAutoTrigger(key: string) {
let param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.AUTO_TRIGGER) {
param.value = 0;
}
}
public resetAllAutoTrigger() {
this._paramMap.forEach((param: Param, key: string) => {
if (param.type === ParamType.AUTO_TRIGGER) {
param.value = 0;
}
});
}
public getNumber(key: string): number {
let param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.NUMBER) {
return param.value;
} else {
return 0;
}
}
public getBool(key: string): number {
let param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.BOOLEAN) {
return param.value;
} else {
return 0;
}
}
public getTrigger(key: string): number {
let param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.TRIGGER) {
return param.value;
} else {
return 0;
}
}
public getAutoTrigger(key: string): number {
let param: Param = this._paramMap.get(key)!;
if (param && param.type === ParamType.AUTO_TRIGGER) {
return param.value;
} else {
return 0;
}
}
}

View File

@@ -0,0 +1,55 @@
import AnimatorController from "./AnimatorController";
import AnimatorTransition from "./AnimatorTransition";
/**
* 状态管理类
*/
export default class AnimatorState {
private _name: string = "";
private _motion: string = "";
private _loop: boolean = false;
private _speed: number = 1;
private _multi: string = "";
private _transitions: AnimatorTransition[] = [];
private _ac: AnimatorController = null!;
/** 状态名 */
public get name() { return this._name; }
/** 动画名 */
public get motion() { return this._motion; }
/** 动画是否循环播放 */
public get loop() { return this._loop; }
/** 动画播放速度 */
public get speed() { return this._speed; }
/** 动画播放速度的混合参数 */
public get multi() { return this._multi; }
constructor(data: any, ac: AnimatorController) {
this._name = data.state;
this._motion = data.motion || '';
this._loop = data.loop || false;
this._speed = data.speed || 1;
this._multi = data.multiplier || '';
this._ac = ac;
for (let i = 0; i < data.transitions.length; i++) {
let transition: AnimatorTransition = new AnimatorTransition(data.transitions[i], ac);
transition.isValid() && this._transitions.push(transition);
}
}
/**
* 判断各个分支是否满足条件,满足则转换状态
*/
public checkAndTrans() {
for (let i = 0; i < this._transitions.length; i++) {
let transition: AnimatorTransition = this._transitions[i];
if (transition && transition.check()) {
transition.doTrans();
return;
}
}
}
}

View File

@@ -0,0 +1,25 @@
/**
* 状态逻辑基类
*/
export default class AnimatorStateLogic {
/**
* 进入状态时调用
* @virtual
*/
public onEntry() {
}
/**
* 每次状态机逻辑更新时调用
* @virtual
*/
public onUpdate() {
}
/**
* 离开状态时调用
* @virtual
*/
public onExit() {
}
}

View File

@@ -0,0 +1,71 @@
import AnimatorCondition, { ParamType } from "./AnimatorCondition";
import AnimatorController from "./AnimatorController";
/**
* 状态过渡类
*/
export default class AnimatorTransition {
private _toStateName: string = '';
private _hasExitTime: boolean = false;
private _conditions: AnimatorCondition[] = [];
private _ac: AnimatorController = null!;
constructor(data: any, ac: AnimatorController) {
this._toStateName = data.toState;
this._hasExitTime = data.hasExitTime;
this._ac = ac;
for (let i = 0; i < data.conditions.length; i++) {
let condition: AnimatorCondition = new AnimatorCondition(data.conditions[i], ac);
this._conditions.push(condition);
}
}
/**
* 返回该transition是否有效当未勾选hasExitTime以及没有添加任何condition时此transition无效并忽略
*/
public isValid(): boolean {
return this._hasExitTime || this._conditions.length > 0;
}
/**
* 判断是否满足所有转换条件
*/
public check(): boolean {
if (this._toStateName === this._ac.curState.name) {
return false;
}
if (this._hasExitTime && (this._ac.curState !== this._ac.animCompleteState || !this._ac.animComplete)) {
return false;
}
for (let i = 0; i < this._conditions.length; i++) {
if (!this._conditions[i].check()) {
return false;
}
}
return true;
}
/**
* 转换状态
*/
public doTrans() {
// 满足条件时重置动画播完标记
if (this._hasExitTime) {
this._ac.animComplete = false;
}
// 满足状态转换条件时重置trigger和autoTrigger
for (let i = 0; i < this._conditions.length; i++) {
let type = this._conditions[i].getParamType();
let name = this._conditions[i].getParamName();
if (type === ParamType.TRIGGER) {
this._ac.params.resetTrigger(name);
} else if (type === ParamType.AUTO_TRIGGER) {
this._ac.params.resetAutoTrigger(name);
}
}
this._ac.changeState(this._toStateName);
}
}