|
- -- 动画播放实例,根据状态表来决定什么状态播放什么动画
- -- 对外接口:
- --[[
- self.Entity 骨骼动画的节点
- self.StateValues 可以用来做数据绑定的状态值列表
- self.OnStateFinished 状态播放完成的回调,参数形式OnStateFinish(animEntity, key , value)
- self.OnGetNextValue 状态播放完成后需要把value设置成什么的回调,,参数形式OnGetNextValue(animEntity, key , value),函数里要返回一个int,表示value要变成什么
- self:setValue
- self:getValue
- --]]
- local AnimEntity = class("AnimEntity")
-
- -- 初始化,传进来initStatus是状态表,拥有多少个状态,以及各个状态的值
- -- animation 动画名字
- -- loop 是否循环播放
- -- staticWhenEnd 是否静止在最后一帧
- -- randomPosition 开始播放这个动画时是否使用随机位置
- --[[
- local status = {
- death =
- {
- 1 = {animation = "death" , loop = true};
- };
- skill =
- {
- 1 = {animation = "skill" , loop = false};
- };
- attack =
- {
- 1 = {animation = "attack" , loop = false};
- };
- move =
- {
- 0 = {animation = "stand" , loop = true};
- 1 = {animation = "move" , loop = true};
- };
- }
- local function getAnimation(values)
- if values.death == 1 then
- return status.death[1];
- elseif values.skill == 1 then
- return status.skill[1];
- elseif values.attack == 1 then
- return status.attack[1];
- elseif values.move == 1 then
- return status.move[1];
- else
- return status.move[0];
- end
- end
-
- local entity = AnimEntity:new(skeleton , status , getAnimation);
- --]]
-
- function AnimEntity:ctor(skeletonEntity , initStatus , callbackGetAnimation)
- self.Status = initStatus;
- self.StateValues = require("luaScript.Protocol.BindableArray")();
- self.CallbackGetAnimation = callbackGetAnimation
- self.CurrentAnimation = nil;
- self.Entity = skeletonEntity;
- skeletonEntity.AnimEntity = self;
-
- self:initStatus();
- end
-
- -- 初始化状态表
- function AnimEntity:initStatus()
- for i , v in pairs(self.Status) do
- self.StateValues[i] = 0;
- -- 初始化所有动画长度
- for ii , state in pairs(v) do
- state.OnStateFinished = {};
- state.OnGetNextValue = {};
-
- local clipFile;
- if self.Entity.getClipFile then
- clipFile = self.Entity:getClipFile();
- end
- if clipFile then
- local clip = clipFile:getAnimationClip(state.animation);
- if clip == nil then
- print("获取模型动画" .. state.animation .. "失败" , self.Entity:getMeshFile());
- else
- -- 这个动画的持续时间为毫秒
- state.duration = clip:getDuration() / 1000 / clip:getSpeed();
- if state.duration == nil then
- error("获取模型动画" .. state.animation .. "长度失败" , self.Entity:getMeshFile());
- end
- -- 这里不用侦听了,因为我们统一通过Action来停止
- -- 侦听动画结束回调
- --self.Entity:getAnimationClip(state.animation):addEndListener(function()self:onPlayEnd(state.animation)end);
- end
- end
- end
- end
- -- 侦听状态改变通知
- self.Entity:bindUpdate(self.StateValues , handler(self , self.updateState));
-
-
- local function initAnimation(index)
- if self.CurrentAnimation then
- self:onChangeAnimation(nil , self.CurrentAnimation);
- end
- end
- self.Entity:runOnLoad(initAnimation);
- end
-
- --[[
- -- 事件回调
- function AnimEntity:onPlayEnd(animation)
- -- 动画播放完毕
- -- 完成了一次循环,则把非循环动画停止
- if self.CurrentAnimation ~= nil and animation == self.CurrentAnimation.animation and not self.CurrentAnimation.loop and not self.CurrentAnimation.staticWhenEnd then
- --print(tostring(self) .. "动画complete" .. animation);
-
- self.CurrentAnimation = nil;
- end
- end
- --]]
- -- 一个状态的动作是否无限长
- function AnimEntity:isInfiniteByState(stateName, stateValue)
- local stateInfo = self.Status[stateName]
- if stateInfo ~= nil and stateInfo[stateValue] ~= nil then
- return stateInfo[stateValue].loop
- end
-
- return false
- end
-
- -- 改变状态值
- function AnimEntity:setValue(state , value)
- self.StateValues[state] = value;
- end
-
- -- 获取状态值
- function AnimEntity:getValue(state)
- return self.StateValues[state];
- end
-
- function AnimEntity:addStateFinishListener(state , value , listener)
- local stateStatus = self.Status[state][value];
- if stateStatus.OnStateFinishedLoop then
- print("AnimEntity:addStateFinishListener,添加无效", state, value)
- return
- end
-
- stateStatus.OnStateFinished[listener] = listener;
- end
-
- function AnimEntity:removeStateFinishListener(state , value , listener)
- local stateStatus = self.Status[state][value];
- if stateStatus.OnStateFinishedLoop then
- --print("AnimEntity:removeStateFinishListener,移除无效, 遍历完成后会全部移除掉的", state, value)
- return
- end
- stateStatus.OnStateFinished[listener] = nil;
- end
-
- function AnimEntity:addNextValueListener(state , value , listener)
- local stateStatus = self.Status[state][value];
- if stateStatus.OnGetNextValueLoop then
- print("AnimEntity:addNextValueListener,添加无效", state, value)
- return
- end
- stateStatus.OnGetNextValue[listener] = listener;
- end
-
- function AnimEntity:removeNextValueListener(state , value , listener)
- local stateStatus = self.Status[state][value];
- if stateStatus.OnGetNextValueLoop then
- print("AnimEntity:removeNextValueListener,移除无效, 遍历完成后会全部移除掉的", state, value)
- return
- end
- stateStatus.OnGetNextValue[listener] = nil;
- end
-
- function AnimEntity:resetValues()
- for i , v in self.StateValues:pairs() do
- if v ~= 0 then
- self.StateValues[i] = 0;
- end
- end
- end
-
- -- 更新状态
- function AnimEntity:updateState(entity , key , value)
- --print(tostring(self) .. "动画状态改变:" .. key .. " = " .. value);
- -- 找不到对应的状态名(则说明设置错了)
- if self.Status[key] == nil then
- print("找不到对应的状态名:" .. key);
- return
- end
-
- local state = self.Status[key][value];
- if state then
- if tolua.isnull(state.Action) then
- -- 非循环状态,则自动停止
- if not state.loop then
- local function onEnd()
- state.Action = nil;
- state.OnStateFinishedLoop = true
- -- 动画状态播放完成回调
- for i , v in pairs(state.OnStateFinished) do
- v(self, key , value);
- end
- state.OnStateFinishedLoop = false
- state.OnStateFinished = {}
- --print(tostring(self) .. "动画状态播放完毕" .. state.animation);
- if not state.staticWhenEnd then
- local retValue = 0;
- state.OnGetNextValueLoop = true
- -- 获取播放完毕要设置的值
- for i , v in pairs(state.OnGetNextValue) do
- local nextValue = v(self, key , value);
- if nextValue then
- retValue = nextValue;
- end
- end
- state.OnGetNextValueLoop = false
- state.OnGetNextValue = {}
-
- self:setValue(key , retValue);
- end
- end
-
- -- 当模型没有这个动画时duration在开始的时候并没有赋值
- if state.duration ~= nil then
- -- 时间到了之后,自动把状态设置成0
- state.Action = self.Entity:runActions(cc.DelayTime:create(state.duration) , onEnd);
- state.Action.OnEnd = onEnd;
- else
- -- 没有这个动画的立马回调
- onEnd();
- end
- end
- end
- end
-
- local anim = self.CallbackGetAnimation(self.StateValues)
- self:setAnimation(anim);
- end
-
- -- 设置当前状态
- function AnimEntity:setAnimation(animation)
- if self.CurrentAnimation == animation then
- return;
- end
- local from = self.CurrentAnimation;
- self.CurrentAnimation = animation;
- if self.Entity:getModelScene() then
- self:onChangeAnimation(from , animation);
- end
- end
-
- -- 动画改变通知
- function AnimEntity:onChangeAnimation(from , to)
- --print(tostring(self) .. "播放动画" .. to.animation);
-
- local fromClip;
- -- 先停止之前的动画
- if from then
- fromClip = self.Entity:getAnimationClip(from.animation);
- -- 停止回调
- if from.Action then
- if not tolua.isnull(from.Action) then
- from.Action.OnEnd();
- self.Entity:stopAction(from.Action)
- end
- from.Action = nil;
- end
- end
-
- local targetClip = self.Entity:getAnimationClip(to.animation);
- if targetClip then
- if to.loop then
- targetClip:setRepeatCount(0);
- else
- targetClip:setRepeatCount(1);
- end
- if fromClip then
- --print("从" , fromClip:getId() , "切换到" , targetClip:getId());
- fromClip:crossFade(targetClip , 200);
- else
- --print("直接播放" , targetClip:getId());
- targetClip:play();
- end
- -- 随机设置开始位置
- if to.randomPosition then
- targetClip:setTimePosition(math.random(0 , targetClip:getDuration()));
- end
- end
- end
-
- return AnimEntity;
|