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

@@ -0,0 +1,7 @@
{
"ver": "1.0.1",
"uuid": "1d876d7a-3ee1-4416-a86b-478e7a2291bc",
"isSubpackage": false,
"subpackageName": "",
"subMetas": {}
}

View File

@@ -0,0 +1,90 @@
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import AnimatorStateLogic from "./core/AnimatorStateLogic";
const { ccclass, property, requireComponent, disallowMultiple } = cc._decorator;
/**
* 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 start() {
if (!this.PlayOnStart || this._hasInit) {
return;
}
this._hasInit = true;
this._animation = this.getComponent(cc.Animation);
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);
}
}
/**
* 手动初始化状态机可传入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(cc.Animation);
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);
}
}
/**
* 播放动画
* @override
* @param animName 动画名
* @param loop 是否循环播放
*/
protected playAnimation(animName: string, loop: boolean) {
if (!animName) {
return;
}
this._animState = this._animation.play(animName);
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);
}
/**
* 缩放动画播放速率
* @override
* @param scale 缩放倍率
*/
protected scaleTime(scale: number) {
if (this._animState) {
this._animState.speed = scale;
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "1.0.5",
"uuid": "c0ecc4d1-4b6b-457f-90ff-bda6d5513a1c",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@@ -0,0 +1,58 @@
import AnimatorBase, { AnimationPlayer } from "./core/AnimatorBase";
import AnimatorStateLogic from "./core/AnimatorStateLogic";
const { ccclass, property, requireComponent, disallowMultiple } = cc._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,9 @@
{
"ver": "1.0.5",
"uuid": "0e26f0aa-d7c7-489f-bb19-f153adc82108",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

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,9 @@
{
"ver": "1.0.5",
"uuid": "fa000d43-3009-42cd-9fe1-926c9209785c",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

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,9 @@
{
"ver": "1.0.5",
"uuid": "81397024-6f01-43e4-8ce0-ec5d32635fc3",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

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

@@ -0,0 +1,9 @@
{
"ver": "1.0.5",
"uuid": "32504c5e-bda8-4d01-b957-cdac7a65d92f",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@@ -0,0 +1,7 @@
{
"ver": "1.0.1",
"uuid": "686e46ec-3c93-40c8-a343-98d92f38c904",
"isSubpackage": false,
"subpackageName": "",
"subMetas": {}
}

View File

@@ -0,0 +1,227 @@
import AnimatorController from "./AnimatorController";
import AnimatorState from "./AnimatorState";
import AnimatorStateLogic from "./AnimatorStateLogic";
const { ccclass, property, executionOrder } = cc._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 cc.Component {
@property({ type: cc.JsonAsset, tooltip: CC_DEV && '状态机json文件' })
protected AssetRawUrl: cc.JsonAsset = null;
@property({ tooltip: CC_DEV && '是否在start中自动启动状态机' })
protected PlayOnStart: 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) {
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,9 @@
{
"ver": "1.0.5",
"uuid": "701554ae-6d5e-4606-97fd-fbb86dce0eaf",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View 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;
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "1.0.5",
"uuid": "ed0e9617-42fd-4623-adbf-e10f876c7dd6",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@@ -0,0 +1,118 @@
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;
// 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) {
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}`);
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "1.0.5",
"uuid": "a787c52f-976b-4787-89cb-fb8f430d2ad2",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

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,9 @@
{
"ver": "1.0.5",
"uuid": "8ffa0112-1623-4dfb-9787-3a11097540e4",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

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,9 @@
{
"ver": "1.0.5",
"uuid": "929e1ea1-3a0b-4764-98a7-84ae9d325e82",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

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

View File

@@ -0,0 +1,9 @@
{
"ver": "1.0.5",
"uuid": "66b34e37-c416-4284-b5dc-55a4a8004a7d",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

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);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "1.0.5",
"uuid": "488defce-de0a-4628-987e-cee1f6cf96f2",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@@ -0,0 +1,7 @@
{
"ver": "1.0.1",
"uuid": "64382c67-97b0-472c-9e01-a61341a0f16c",
"isSubpackage": false,
"subpackageName": "",
"subMetas": {}
}

View File

@@ -0,0 +1,7 @@
{
"ver": "1.0.1",
"uuid": "1aa00128-3386-4c14-8bd1-18e71df90d5b",
"isSubpackage": false,
"subpackageName": "",
"subMetas": {}
}

View File

@@ -0,0 +1,70 @@
import AnimatorAnimation from "../../animator/AnimatorAnimation";
import AnimatorStateLogic from "../../animator/core/AnimatorStateLogic";
import SheepHit from "./SheepHit";
import SheepIdle from "./SheepIdle";
import SheepRun from "./SheepRun";
const { ccclass, property } = cc._decorator;
@ccclass
export default class AnimationScene extends cc.Component {
@property(AnimatorAnimation) Animator: AnimatorAnimation = null;
public speed: number = 0;
protected onLoad() {
let map: Map<string, AnimatorStateLogic> = new Map();
map.set('sheep_idle', new SheepIdle());
map.set('sheep_run', new SheepRun());
map.set('sheep_hit', new SheepHit(this));
this.Animator.onInit(map);
cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
}
protected update(dt: number) {
let delt = this.Animator.curStateName === 'sheep_hit' ? 0 : this.speed * -this.Animator.node.scaleX * dt;
this.Animator.node.x = cc.misc.clampf(this.Animator.node.x + delt, -1000, 1000);
}
protected lateUpdate() {
this.Animator.setNumber('speed', this.speed);
this.Animator.manualUpdate();
}
protected onDestroy() {
cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
cc.systemEvent.off(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
}
private onKeyDown(event: cc.Event.EventKeyboard) {
let code: cc.macro.KEY = event.keyCode;
switch (code) {
case cc.macro.KEY.left:
this.Animator.node.scaleX = 1;
this.speed = 100;
break;
case cc.macro.KEY.right:
this.Animator.node.scaleX = -1;
this.speed = 100;
break;
case cc.macro.KEY.k:
this.Animator.setTrigger('hit');
default:
break;
}
}
private onKeyUp(event: cc.Event.EventKeyboard) {
let code: cc.macro.KEY = event.keyCode;
switch (code) {
case cc.macro.KEY.left:
case cc.macro.KEY.right:
this.speed = 0;
break;
default:
break;
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "1.0.5",
"uuid": "14db7554-9454-4338-a487-150523459aca",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@@ -0,0 +1,25 @@
import AnimatorStateLogic from "../../animator/core/AnimatorStateLogic";
import AnimationScene from "./AnimationScene";
export default class SheepHit extends AnimatorStateLogic {
private _ctr: AnimationScene = null;
public constructor(ctr: AnimationScene) {
super();
this._ctr = ctr;
}
public onEntry() {
this._ctr.speed = 0;
cc.log('hit entry');
}
public onUpdate() {
this._ctr.speed = 0;
cc.log('hit update');
}
public onExit() {
cc.log('hit exit');
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "1.0.5",
"uuid": "b1e94d2a-165f-4350-8035-c4e0ce55221b",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@@ -0,0 +1,16 @@
import AnimatorStateLogic from "../../animator/core/AnimatorStateLogic";
export default class SheepIdle extends AnimatorStateLogic {
public onEntry() {
cc.log('idle entry');
}
public onUpdate() {
cc.log('idle update');
}
public onExit() {
cc.log('idle exit');
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "1.0.5",
"uuid": "ffe798df-0253-48ab-bdcc-31b7c2ddc3c7",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@@ -0,0 +1,16 @@
import AnimatorStateLogic from "../../animator/core/AnimatorStateLogic";
export default class SheepRun extends AnimatorStateLogic {
public onEntry() {
cc.log('run entry');
}
public onUpdate() {
cc.log('run update');
}
public onExit() {
cc.log('run exit');
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "1.0.5",
"uuid": "249d7306-946e-4f59-9446-b6ecc1d456a4",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@@ -0,0 +1,7 @@
{
"ver": "1.0.1",
"uuid": "fcde15b6-7401-4e97-8d61-f6f7eab6f002",
"isSubpackage": false,
"subpackageName": "",
"subMetas": {}
}

View File

@@ -0,0 +1,95 @@
import AnimatorCustomization from "../../animator/AnimatorCustomization";
import { AnimationPlayer } from "../../animator/core/AnimatorBase";
const { ccclass, property } = cc._decorator;
@ccclass
export default class CustomizationScene extends cc.Component implements AnimationPlayer {
@property(cc.Node) Cube: cc.Node = null;
private _animator: AnimatorCustomization = null;
private _curTween: cc.Tween = null;
private _call: () => void = null;
private _traget: any = null;
protected onLoad() {
this._animator = this.Cube.getComponent(AnimatorCustomization);
// 自定义动画播放必须要将实现了AnimationPlayer接口的对象传入
this._animator.onInit(this);
this.node.on(cc.Node.EventType.TOUCH_START, () => { this._animator.setTrigger('next'); }, this);
}
private move(dur: number, pos: cc.Vec3, loop: boolean) {
if (loop) {
this._curTween = cc.tween(this.Cube)
.repeatForever(
cc.tween()
.to(dur, { position: pos })
.call(() => {
this._call.call(this._traget);
})
)
.start();
} else {
this._curTween = cc.tween(this.Cube)
.to(dur, { position: pos })
.call(() => {
this._call.call(this._traget);
})
.start();
}
}
/**
* - 实现接口 AnimationPlayer
* 设置动画播放结束的回调
*/
public setFinishedCallback(callback: () => void, target: any): void {
this._call = callback;
this._traget = target;
}
/**
* - 实现接口 AnimationPlayer
* 播放动画
*/
public playAnimation(animName: string, loop: boolean): void {
this._curTween && this._curTween.stop();
if (animName === 'idle') {
if (loop) {
this._curTween = cc.tween(this.Cube)
.repeatForever(
cc.tween()
.to(1, { scale: 2 })
.to(1, { scale: 0.5 })
.call(() => {
this._call.call(this._traget);
})
)
.start();
} else {
this._curTween = cc.tween(this.Cube)
.to(1, { scale: 2 })
.to(1, { scale: 0.5 })
.call(() => {
this._call.call(this._traget);
})
.start();
}
} else if (animName === 'move1') {
this.move(2, cc.v3(500, 500, 0), loop);
} else if (animName === 'move2') {
this.move(4, cc.v3(0, 0, 0), loop);
}
}
/**
* - 实现接口 AnimationPlayer
* 缩放动画播放速率
*/
public scaleTime(scale: number): void {
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "1.0.5",
"uuid": "4ecb8927-f33a-4833-9ffb-8e38c1193687",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@@ -0,0 +1,7 @@
{
"ver": "1.0.1",
"uuid": "19bb3ee7-3033-4cb7-85ea-59d38ab1797f",
"isSubpackage": false,
"subpackageName": "",
"subMetas": {}
}

View File

@@ -0,0 +1,12 @@
import AnimatorDragonBones from "../../animator/AnimatorDragonBones";
const {ccclass, property} = cc._decorator;
@ccclass
export default class DragonBonesScene extends cc.Component {
@property(AnimatorDragonBones) Animator: AnimatorDragonBones = null;
protected onLoad() {
this.node.on(cc.Node.EventType.TOUCH_START, () => { this.Animator.setTrigger('next'); }, this);
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "1.0.5",
"uuid": "46c5fdeb-47df-4174-bfe0-f233c54da45b",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}

View File

@@ -0,0 +1,7 @@
{
"ver": "1.0.1",
"uuid": "56d84939-6606-4c19-be06-e9583942e3d2",
"isSubpackage": false,
"subpackageName": "",
"subMetas": {}
}

View File

@@ -0,0 +1,64 @@
import AnimatorSpine from "../../animator/AnimatorSpine";
import AnimatorSpineSecondary from "../../animator/AnimatorSpineSecondary";
const { ccclass, property } = cc._decorator;
@ccclass
export default class SpineScene extends cc.Component {
@property(sp.Skeleton) SpineBoy: sp.Skeleton = null;
private _updateSpeed: boolean = false;
private _speed: number = 0;
private _animatorMain: AnimatorSpine = null;
private _animatorSecondary: AnimatorSpineSecondary[] = [];
protected onLoad() {
this._animatorMain = this.SpineBoy.getComponent(AnimatorSpine);
this._animatorMain.onInit((fromState: string, toState: string) => {
cc.log(`state change: ${fromState} -> ${toState}`);
});
this._animatorSecondary = this.SpineBoy.getComponents(AnimatorSpineSecondary);
cc.systemEvent.on(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
cc.systemEvent.on(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
}
protected update(dt: number) {
this._speed = this._updateSpeed ? Math.min(5, this._speed + dt) : Math.max(0, this._speed - dt * 2);
this._animatorMain.setNumber('speed', this._speed);
}
protected onDestroy() {
cc.systemEvent.off(cc.SystemEvent.EventType.KEY_DOWN, this.onKeyDown, this);
cc.systemEvent.off(cc.SystemEvent.EventType.KEY_UP, this.onKeyUp, this);
}
private onKeyDown(event: cc.Event.EventKeyboard) {
let code: cc.macro.KEY = event.keyCode;
switch (code) {
case cc.macro.KEY.left:
case cc.macro.KEY.right:
this._updateSpeed = true;
break;
case cc.macro.KEY.space:
this._animatorMain.autoTrigger('jump');
break;
case cc.macro.KEY.k:
this._animatorSecondary[0].autoTrigger('shoot');
default:
break;
}
}
private onKeyUp(event: cc.Event.EventKeyboard) {
let code: cc.macro.KEY = event.keyCode;
switch (code) {
case cc.macro.KEY.left:
case cc.macro.KEY.right:
this._updateSpeed = false;
break;
default:
break;
}
}
}

View File

@@ -0,0 +1,9 @@
{
"ver": "1.0.5",
"uuid": "1810c37f-1e5a-41ec-b2ba-e78ac9b155e0",
"isPlugin": false,
"loadPluginInWeb": true,
"loadPluginInNative": true,
"loadPluginInEditor": false,
"subMetas": {}
}