init
This commit is contained in:
74
animator-runtime/AnimatorAnimation.ts
Normal file
74
animator-runtime/AnimatorAnimation.ts
Normal file
@@ -0,0 +1,74 @@
|
||||
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
|
||||
import AnimatorStateLogic from "./core/AnimatorStateLogic";
|
||||
|
||||
const { ccclass, property, requireComponent } = cc._decorator;
|
||||
|
||||
/** Animation状态机组件 */
|
||||
@ccclass
|
||||
@requireComponent(cc.Animation)
|
||||
export default class AnimatorAnimation extends AnimatorBase {
|
||||
/** Animation组件 */
|
||||
private _animation: cc.Animation = null;
|
||||
/** 当前的动画实例 */
|
||||
private _animState: cc.AnimationState = null;
|
||||
|
||||
protected onLoad() {
|
||||
if (!this.PlayOnLoad || 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);
|
||||
|
||||
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.PlayOnLoad || this._hasInit) {
|
||||
return;
|
||||
}
|
||||
this._hasInit = true;
|
||||
|
||||
this.initArgs(...args);
|
||||
|
||||
this._animation = this.getComponent(cc.Animation);
|
||||
this._animation.on("finished", this.onAnimFinished, this);
|
||||
this._animation.on("lastframe", this.onAnimFinished, this);
|
||||
|
||||
if (this.AssetRawUrl !== null) {
|
||||
this.initJson(this.AssetRawUrl.json);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 播放动画
|
||||
* @override
|
||||
* @param animName 动画名
|
||||
* @param loop 是否循环播放
|
||||
*/
|
||||
protected playAnimation(animName: string, loop: boolean) {
|
||||
this._animState = this._animation.play(animName);
|
||||
this._animState.wrapMode = loop ? cc.WrapMode.Loop : cc.WrapMode.Default;
|
||||
}
|
||||
|
||||
/**
|
||||
* 缩放动画播放速率
|
||||
* @override
|
||||
* @param scale 缩放倍率
|
||||
*/
|
||||
protected scaleTime(scale: number) {
|
||||
if (scale > 0 && this._animState)
|
||||
this._animState.speed = scale;
|
||||
}
|
||||
}
|
51
animator-runtime/AnimatorAvatar.ts
Normal file
51
animator-runtime/AnimatorAvatar.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
|
||||
import AnimatorStateLogic from "./core/AnimatorStateLogic";
|
||||
|
||||
const { ccclass, property, requireComponent } = cc._decorator;
|
||||
|
||||
/** 纸娃娃系统状态机组件 */
|
||||
@ccclass
|
||||
export default class AnimatorAvatar extends AnimatorBase {
|
||||
/**
|
||||
* 手动初始化状态机,可传入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) {
|
||||
this._animationPlayer.playAnimation(animName, loop);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 缩放动画播放速率
|
||||
* @override
|
||||
* @param scale 缩放倍率
|
||||
*/
|
||||
protected scaleTime(scale: number) {
|
||||
if (this._animationPlayer) {
|
||||
this._animationPlayer.scaleTime(scale);
|
||||
}
|
||||
}
|
||||
}
|
29
animator-runtime/AnimatorDragonBones.ts
Normal file
29
animator-runtime/AnimatorDragonBones.ts
Normal file
@@ -0,0 +1,29 @@
|
||||
// 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;
|
||||
// }
|
||||
// }
|
45
animator-runtime/AnimatorSpine.ts
Normal file
45
animator-runtime/AnimatorSpine.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
// 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;
|
||||
// }
|
||||
// }
|
228
animator-runtime/core/AnimatorBase.ts
Normal file
228
animator-runtime/core/AnimatorBase.ts
Normal file
@@ -0,0 +1,228 @@
|
||||
import AnimatorController from "./AnimatorController";
|
||||
import AnimatorState from "./AnimatorState";
|
||||
import AnimatorStateLogic from "./AnimatorStateLogic";
|
||||
|
||||
const { ccclass, property, executionOrder } = cc._decorator;
|
||||
|
||||
/**
|
||||
* 自定义控制动画播放的接口
|
||||
*/
|
||||
export interface AnimationPlayer {
|
||||
/** 设置动画播放结束的回调 */
|
||||
setFinishedCallback(callback: (event: cc.Event.EventCustom) => void, target?: any): void;
|
||||
/** 播放动画 */
|
||||
playAnimation(animName: string, loop: boolean): void;
|
||||
/** 缩放动画播放速率 */
|
||||
scaleTime(scale: number): void;
|
||||
}
|
||||
|
||||
/**
|
||||
* 状态机组件基类 优先执行生命周期
|
||||
*/
|
||||
@ccclass
|
||||
@executionOrder(-1000)
|
||||
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 && '是否在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) {
|
||||
if (toState.motion && toState.motion !== "") {
|
||||
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);
|
||||
}
|
||||
}
|
81
animator-runtime/core/AnimatorCondition.ts
Normal file
81
animator-runtime/core/AnimatorCondition.ts
Normal file
@@ -0,0 +1,81 @@
|
||||
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 = null;
|
||||
/** 此条件对应的参数名 */
|
||||
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 {
|
||||
cc.error(`[AnimatorCondition.check] 错误的type: ${type}`);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
117
animator-runtime/core/AnimatorController.ts
Normal file
117
animator-runtime/core/AnimatorController.ts
Normal file
@@ -0,0 +1,117 @@
|
||||
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) {
|
||||
cc.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;
|
||||
}
|
||||
|
||||
/**
|
||||
* 无视条件直接跳转状态
|
||||
* @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) {
|
||||
cc.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 {
|
||||
cc.error(`[AnimatorController.changeState] error state: ${stateName}`);
|
||||
}
|
||||
}
|
||||
}
|
121
animator-runtime/core/AnimatorParams.ts
Normal file
121
animator-runtime/core/AnimatorParams.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
55
animator-runtime/core/AnimatorState.ts
Normal file
55
animator-runtime/core/AnimatorState.ts
Normal 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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
28
animator-runtime/core/AnimatorStateLogic.ts
Normal file
28
animator-runtime/core/AnimatorStateLogic.ts
Normal file
@@ -0,0 +1,28 @@
|
||||
/**
|
||||
* 状态逻辑基类
|
||||
*/
|
||||
export default class AnimatorStateLogic {
|
||||
constructor() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 进入状态时调用
|
||||
* @virtual
|
||||
*/
|
||||
public onEntry() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次状态机逻辑更新时调用
|
||||
* @virtual
|
||||
*/
|
||||
public onUpdate() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 离开状态时调用
|
||||
* @virtual
|
||||
*/
|
||||
public onExit() {
|
||||
}
|
||||
}
|
71
animator-runtime/core/AnimatorTransition.ts
Normal file
71
animator-runtime/core/AnimatorTransition.ts
Normal 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);
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user