随笔--骨骼动画的实现原理

骨骼动画原理

ž 由于手机游戏都受到容量的限制,

ž 一般不采用帧动画的方法制作角色的动画,而是将角色肢解,然后用肢解得到的各个部分重新组装成原来动画中的每个图片,

ž 而且这样角色的动画也可以更加丰富,

骨骼动画中的元素

ž 动画纹理图片

ž 骨骼Bone

ž 帧  Frame

ž 图层 layer

ž 动画 Animation

ž 一个骨骼就是肢解后的一个部分,主角的动画共有43个Bone。

ž 每个Bone绑定一个肢解的图块,描述图块需要4项数据:左上角在Image中的x坐标、y坐标、宽度和高度。

ž 每个骨骼都有一个唯一标识它的id。

ž 每个图块也有唯一标识的id

ž 在骨骼动画编辑器中定义他们之间的绑定

ž 骨骼和骨骼之间要定义父子关系,一般一个骨骼动画会有一个根节点骨骼

ž 父子关系决定了每个骨骼的运动依赖

Frame

ž Frame是每次画在屏幕上的内容,也是组成动作的一系列图片

ž 每个图层的当前帧叠加在一起组成了动画的Frame

ž 在CocoStudio中可以定义FrameEvent

ž 系统动画的播放中也定义了LOOP_COMPLETE 动画事件用于检测整个动画播放完成

图层Layer

ž Layer实际上是带有额外信息的骨骼图片块

ž Layer对原有矩形图片块做了各种变换操作,如旋转,缩放等

ž 在Cocostudio中骨骼也是一种Layer

 

Animation 动画

ž Animation就是连续播放的一系列Frame。一个动作中,每个Frame都有delay,表示在播放动作时这个Frame要持续画在屏幕上多少次。

显示过程

ž 每个Layer的显示过程分为三个部分——提取信息、计算数据和绘制图片

ž 对大图的处理会经过多次剪裁实现

使用Armature编辑器

ž 1创建骨骼

ž 2绑定图层

ž 3创建帧和关键帧

ž 4添加动画

ž 5导出文件

在战斗场景加入骨骼动画C++

ž ArmatureDataManager::getInstance()->addArmatureFileInfoAsync("armature/Cowboy.ExportJson",this, schedule_selector(TestAsynchronousLoading::dataLoaded));   ArmatureDataManager::getInstance()->addArmatureFileInfoAsync("armature/hero.ExportJson",this, schedule_selector(TestAsynchronousLoading::dataLoaded));

ž armature =Armature::create("Dragon");  

ž  armature->getAnimation()->playWithIndex(1);

ž //播放第二个动画   

ž armature->getAnimation()->setSpeedScale(0.4f);

在战斗场景加入骨骼动画lua

ž ccs.ArmatureDataManager:getInstance():addArmatureFileInfoAsync("armature/knight.png","armature/knight.plist","armature/knight.xml",dataLoaded)   ccs.ArmatureDataManager:getInstance():addArmatureFileInfoAsync("armature/weapon.png","armature/weapon.plist", "armature/weapon.xml", dataLoaded)

ž local armature =ccs.Armature:create("bear")   armature:getAnimation():playWithIndex(0)

设置骨骼动画的播放速度

ž C++

ž  armature->getAnimation()->setSpeedScale(0.4f);

ž Lua

ž  armature:setScale(0.2)

侦听动画播放完成事件C++

ž armature->getAnimation()->

         setMovementEventCallFunc(  

           CC_CALLBACK_0(TestAni::animationEvent,this));   

ž addChild(armature);

ž void TestAnimationEvent::animationEvent(

ž Armature *armature, MovementEventTypemovementType, const std::string& movementID){  

ž  if(movementType == LOOP_COMPLETE)    {        if (movementID =="Fire")        {

侦听动画播放完成事件Lua

ž armature:getAnimation():setMovementEventCallFunc(animationEvent)

ž local function animationEvent(

ž    armatureBack,movementType,movementID)       

ž local id = movementID      

ž if movementType == ccs.MovementEventType.loopCompletethen            if id == "Fire"then

ž   。。。。。。

ž end

ž end

ž end

动态修改骨骼显示NodeC++

ž std::string weapon[] ={"weapon_f-sword.png", "weapon_f-sword2.png","weapon_f-sword3.png", "weapon_f-sword4.png","weapon_f-sword5.png", "weapon_f-knife.png","weapon_f-hammer.png"};  

ž  for(int i = 0; i < 7; i++)    {     

ž   Skin *skin = Skin::createWithSpriteFrameName(weapon[i].c_str());      

ž  armature->getBone("weapon")->addDisplay(skin,i);    }

ž voidTest::onTouchesEnded(const std::vector<Touch*>&  touches, Event* event){  

ž  ++displayIndex;   

ž displayIndex= (displayIndex) % 8;   armature->getBone("weapon")->

ž changeDisplayWithIndex(displayIndex,true);}

动态修改骨骼显示Nodelua

ž local weapon = {"weapon_f-sword.png","weapon_f-sword2.png",        "weapon_f-sword3.png",        "weapon_f-sword4.png",        "weapon_f-sword5.png",        "weapon_f-knife.png",        "weapon_f-hammer.png",    } 

ž   local i = 1 

ž   fori = 1,table.getn(weapon) do       

ž local skin =ccs.Skin:createWithSpriteFrameName(weapon[i])       self.armature:getBone("weapon"):addDisplay(skin, i - 1) 

ž   end   -- handling touch events    

ž   local function onTouchEnded(touches,event)          

ž   self.displayIndex = (self.displayIndex + 1) %(table.getn(weapon) - 1)       self.armature:getBone("weapon"):changeDisplayWithIndex(self.displayIndex,true)   

ž end   

ž local listener =cc.EventListenerTouchAllAtOnce:create()   listener:registerScriptHandler(onTouchEnded,cc.Handler.EVENT_TOUCHES_ENDED)   

ž local eventDispatcher =self:getEventDispatcher()   eventDispatcher:addEventListenerWithSceneGraphPriority(listener, self)

lua中播放一个骨骼动画,

--加载动画到内存 ccs.ArmatureDataManager:getInstance():addArmatureFileInfo(

    "NewAniData/NewAniData0.png","NewAniData/NewAniData0.plist","NewAniData/NewAniData.ExportJson")

    --从内存中取出动画

    local armature=ccs.Armature:create("NewAniData")

    --播放第一个动画

    armature:getAnimation():play("move")

  --把动画添加到屏幕

    layer:addChild(armature)

    armature:setPosition(self.winsize.width/2,self.winsize.height/2)

lua中添加一个帧事件处理

--添加帧事件处理动画--

    local function onFrameEvent(bone,evt,originFrameIndex,currentFrameIndex)

       print("骨骼编号"..tostring(bone).."事件名"..evt.."当前帧"..currentFrameIndex)

    end

    --设定帧事件的回调函数

    armature:getAnimation():setFrameEventCallFunc(onFrameEvent)

 

--点击,获取骨骼,修改它的显示,动态修改骨骼显示Node lua

--首先定义一个全局的count

在构造中定义  self.count=1

--添加骨骼绑定的皮肤

    local weapon =    { "weapon_f-sword.png", "weapon_f-sword2.png","weapon_f-sword3.png",

       "weapon_f-sword4.png", "weapon_f-sword5.png""weapon_f-knife.png", "weapon_f-hammer.png",   } 

    cc.SpriteFrameCache:getInstance():addSpriteFrames("weapon.plist")

 

    local i = 1

    for i = 1,table.getn(weapon) do       

       local skin = ccs.Skin:createWithSpriteFrameName(weapon[i])       

       armature:getBone("Layer18"):addDisplay(skin, i - 1

    end    -- handling touch events    

 

    local lis=cc.EventListenerTouchOneByOne:create()

    local function onTouchBegan(t,e)

       self.count = (self.count + 1) % (table.getn(weapon) - 1)       

       armature:getBone("Layer18"):changeDisplayWithIndex(self.count, true)   

    end

 

 

    lis:registerScriptHandler(onTouchBegan,cc.Handler.EVENT_TOUCH_BEGAN)

    cc.Director:getInstance():getEventDispatcher():addEventListenerWithSceneGraphPriority(lis,layer)

--这样就实现了点击一下,就切换皮肤


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值