fix:编辑器文件导入. add:example,runtime
This commit is contained in:
7
examples/example2-2-2/assets/script/animator.meta
Normal file
7
examples/example2-2-2/assets/script/animator.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "1d876d7a-3ee1-4416-a86b-478e7a2291bc",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "c0ecc4d1-4b6b-457f-90ff-bda6d5513a1c",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "0e26f0aa-d7c7-489f-bb19-f153adc82108",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "fa000d43-3009-42cd-9fe1-926c9209785c",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
120
examples/example2-2-2/assets/script/animator/AnimatorSpine.ts
Normal file
120
examples/example2-2-2/assets/script/animator/AnimatorSpine.ts
Normal 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;
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "81397024-6f01-43e4-8ce0-ec5d32635fc3",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "32504c5e-bda8-4d01-b957-cdac7a65d92f",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
7
examples/example2-2-2/assets/script/animator/core.meta
Normal file
7
examples/example2-2-2/assets/script/animator/core.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "686e46ec-3c93-40c8-a343-98d92f38c904",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "701554ae-6d5e-4606-97fd-fbb86dce0eaf",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "ed0e9617-42fd-4623-adbf-e10f876c7dd6",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
@@ -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}`);
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "a787c52f-976b-4787-89cb-fb8f430d2ad2",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "8ffa0112-1623-4dfb-9787-3a11097540e4",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "929e1ea1-3a0b-4764-98a7-84ae9d325e82",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
@@ -0,0 +1,25 @@
|
||||
/**
|
||||
* 状态逻辑基类
|
||||
*/
|
||||
export default class AnimatorStateLogic {
|
||||
/**
|
||||
* 进入状态时调用
|
||||
* @virtual
|
||||
*/
|
||||
public onEntry() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 每次状态机逻辑更新时调用
|
||||
* @virtual
|
||||
*/
|
||||
public onUpdate() {
|
||||
}
|
||||
|
||||
/**
|
||||
* 离开状态时调用
|
||||
* @virtual
|
||||
*/
|
||||
public onExit() {
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "66b34e37-c416-4284-b5dc-55a4a8004a7d",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "488defce-de0a-4628-987e-cee1f6cf96f2",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
7
examples/example2-2-2/assets/script/cases.meta
Normal file
7
examples/example2-2-2/assets/script/cases.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "64382c67-97b0-472c-9e01-a61341a0f16c",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
||||
}
|
7
examples/example2-2-2/assets/script/cases/animation.meta
Normal file
7
examples/example2-2-2/assets/script/cases/animation.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "1aa00128-3386-4c14-8bd1-18e71df90d5b",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "14db7554-9454-4338-a487-150523459aca",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
@@ -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');
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "b1e94d2a-165f-4350-8035-c4e0ce55221b",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
@@ -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');
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "ffe798df-0253-48ab-bdcc-31b7c2ddc3c7",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
@@ -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');
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "249d7306-946e-4f59-9446-b6ecc1d456a4",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "fcde15b6-7401-4e97-8d61-f6f7eab6f002",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
||||
}
|
@@ -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 {
|
||||
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "4ecb8927-f33a-4833-9ffb-8e38c1193687",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "19bb3ee7-3033-4cb7-85ea-59d38ab1797f",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
||||
}
|
@@ -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);
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "46c5fdeb-47df-4174-bfe0-f233c54da45b",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
7
examples/example2-2-2/assets/script/cases/spine.meta
Normal file
7
examples/example2-2-2/assets/script/cases/spine.meta
Normal file
@@ -0,0 +1,7 @@
|
||||
{
|
||||
"ver": "1.0.1",
|
||||
"uuid": "56d84939-6606-4c19-be06-e9583942e3d2",
|
||||
"isSubpackage": false,
|
||||
"subpackageName": "",
|
||||
"subMetas": {}
|
||||
}
|
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"ver": "1.0.5",
|
||||
"uuid": "1810c37f-1e5a-41ec-b2ba-e78ac9b155e0",
|
||||
"isPlugin": false,
|
||||
"loadPluginInWeb": true,
|
||||
"loadPluginInNative": true,
|
||||
"loadPluginInEditor": false,
|
||||
"subMetas": {}
|
||||
}
|
Reference in New Issue
Block a user