最近有个需求是从配置文档读取图片来组合成动画,看了cocos里面的animate好像没有办法控制,又看了下timeline,编辑起来真是麻烦。
于是自己写了一个从已读取的图片资源创建简单动画的方法,不知道官方有没有什么办法能自己创建动画,并且可以轻松控制的pause,loop,
frame等属性。
local ActionUtils = {}
--生成一个简单动画,frames=包含SpriteFrame名字的table,speed=速度系数
function ActionUtils.createSimpleAct(frames, speed)
local actTimeLine = ccs.ActionTimeline:create()
local timeline = ccs.Timeline:create()
for k,v in pairs(frames) do
local frame = ccs.TextureFrame:create()
frame:setTextureName(v) --设置纹理的名字,现在framecach中查找,如果未找到会作为文件名搜索纹理加载
frame:setFrameIndex(k-1) --设置帧的编号,这个在换帧的时候 用到
timeline:addFrame(frame)
end
timeline:setActionTag(1) --这个tag要设置,因为sprite中保存了一个tag编号用来查找相应的timeline
actTimeLine:setTimeSpeed(speed) --设置速度,默认60帧/S,动画帧数直接用speed*60就可计算出来了
actTimeLine:setDuration(table.getn(frames)) --这个要设置,调用一个参数的play函数时比较方便,会用这个参数设置endframe
actTimeLine:addTimeline(timeline)
return actTimeLine
end
--增加一个监听帧actTimeline=actiontimeline,callback=回调,index=第几帧,sync=是否在这帧同步执行
function ActionUtils.addEvent(actTimeline, callback, index, sync)
local frame = ccs.EventFrame:create()
local timelines = actTimeline:getTimelines()
frame:setFrameIndex(index)
--并行时需要建立一个新的timeline而不是使用timeline1的原因是:和这个frame相同编号的执行时不在同一帧,比如
--要在第3帧插入event事件,那么会先执行事件在下一帧即1/60秒后执行相同编号的其它帧如textureframe等
if sync == true then
if table.getn(timelines) == 1 then
local timeline = ccs.Timeline:create()
actTimeline:addTimeline(timeline)
timeline:insertFrame(frame, 0)
else
timelines:insertFrame(frame, 0)
end
else
timelines:insertFrame(frame, index)
end
actTimeline:setFrameEventCallFunc(callback)
return frame
end
return ActionUtils
用法:
--建立一个图片名字数组
local names = {}
for i=1,count do
names* = string.format("Ele%02d_00.png",i)
end
local actionUtils= require (" ActionUtils ")
local act = actionUtils.createSimpleAct(names,0.2) --使用图片名字数组创建actiontimeline
local spr = cc.Sprite:create()
spr :setUserObject(ccs.ActionTimelineData:create(1))
spr:runAction(act)
act:gotoFrameAndPlay(0)
local function callback(frame)
print(frame:getFrameIndex())
end
actionUtils.addEvent(act ,callback,3, false) --在第3帧监听
*
但是使用带离散帧的timeline有个问题,就是如果帧数不是从第一个开始,每次循环之后切换回第一帧时都会执行一次timeline里的第一帧。
比如第一个timeline里有10个textureframe,第二个timeline里只有一个frameindex==3的eventframe,在循环回来第一次赋值只是简单的break
仍然会执行到frame的enter。导致这个event在第0帧触发一次,在第3帧触发一次。我想问问下面两段代码最底下确定是break,而不是return吗?
循环回来第一帧赋值之后如果当前帧的frameindex(0)小于timeline里的第一帧的frameindex(3)不是应该直接赋值duration然后return吗?
两段代码如下,请看每段代码最后一行的注释,希望有懂的给说下。
第一段:
void Timeline::binarySearchKeyFrame(int frameIndex)
{
Frame *from = nullptr;
Frame *to = nullptr;
long length = _frames.size();
bool needEnterFrame = false;
do
{
if (frameIndex < _frames.at(0)->getFrameIndex())
{
if(_currentKeyFrameIndex >= _frames.at(0)->getFrameIndex())
needEnterFrame = true;
_fromIndex = 0;
if(length > 1)
_toIndex = 1;
else
_toIndex = 0;
from = to = _frames.at(0);
_currentKeyFrameIndex = 0;
_betweenDuration = _frames.at(0)->getFrameIndex();
break; //这里是否应该return?
}
第二段
void Timeline::updateCurrentKeyFrame(int frameIndex)
{
//! If play to current frame’s front or back, then find current frame again
if (frameIndex < _currentKeyFrameIndex || frameIndex >= _currentKeyFrameIndex + _betweenDuration)
{
Frame *from = nullptr;
Frame *to = nullptr;
do
{
long length = _frames.size();
if (frameIndex < _frames.at(0)->getFrameIndex())
{
from = to = _frames.at(0);
_currentKeyFrameIndex = 0;
_betweenDuration = _frames.at(0)->getFrameIndex();
break; //这里是否应该return?
}