Jump to content

[TOPIC: topicViewTemplate]
[GLOBAL: userSmallPhoto]
Photo

How do i interpolate between animations?
Started by AppdojoStudios Dec 05 2013 06:27 PM

4 replies to this topic
spine interpolate animation
[TOPIC CONTROLS]
This topic has been archived. This means that you cannot reply to this topic.
[/TOPIC CONTROLS]
[modOptionsDropdown]
[/modOptionsDropdown]
[reputationFilter]
[TOPIC: post.html]
#1

AppdojoStudios

[GLOBAL: userInfoPane.html]
AppdojoStudios
  • Contributor

  • 110 posts
  • Corona SDK

I have a simple idle and run animation for my character and I have it working where when the character is not moving he displays the idle animation, and when he is moving he displays the run animation. My problem is that it doesn't fade (interpolate) between these animations, it just jumps from idle to running. Here is my current code: 
 

 
 
    local skeletonData = json:readSkeletonDataFile("examples/spineboy/skeleton.json")
 
    local skeleton = spine.Skeleton.new(skeletonData)
 

    local stateData = spine.AnimationStateData.new(skeletonData)
    stateData:setMix("idle", "run", 0.2)
    stateData:setMix("run", "idle", 0.4)
 

    local state = spine.AnimationState.new(stateData)
    state:setAnimationByName(0, "idle", true, 0)
 

    local state2 = spine.AnimationState.new(stateData)
    state2:setAnimationByName(0, "run", true, 0)
 
    local function enterFrame( event )
 
        if ( vx == 0 ) then --If the player's velocity is equal to 0...
            state:apply(skeleton)
        elseif ( vx ~= 0 ) then -- if the player's velocity doesn't equal 0...
            state2:apply(skeleton)
        end
 
    end



 

 

Is there a better way to handle animations? I looked at the examples on GitHub and the Spineboy example was the only one that showed multiple animations being played, but they didn't show any interpolating. I also looked at their documentation and the functions they show that are supposed to utilize interpolating don't seem to work in Corona. Does anyone have any ideas or examples? Any help is appreciated! :)

-Zac



[TOPIC: post.html]
#2

Reaver

[GLOBAL: userInfoPane.html]
Reaver
  • Enthusiast

  • 87 posts
  • Corona SDK

Hi,

 

I think you'll only need one animationState for each character. Then you can queue animations using addAnimation/addAnimationByName. (I think this might also work with setAnimation functions too now, after the animationState got a pretty big rewrite not to long ago, but you might want to test this yourself) This should play one animation and create a smooth transition to the next one queued. Using your example code it might look like:

 

 

local skeletonData = json:readSkeletonDataFile("examples/spineboy/skeleton.json")
	 
	local skeleton = spine.Skeleton.new(skeletonData)
	 
	 
	local stateData = spine.AnimationStateData.new(skeletonData)
	stateData:setMix("idle", "run", 0.2)
	stateData:setMix("run", "idle", 0.4)
	 
	 
	local state = spine.AnimationState.new(stateData)
	 
	local function enterFrame( event )
	 
	if ( vx == 0 ) then --If the player's velocity is equal to 0...
	
	
	state:setAnimationByName(0, "idle", true, 0)
		
		--or state:addAnimationByName(0, "idle", true, 0)
		
		
	
	
	elseif ( vx ~= 0 ) then -- if the player's velocity doesn't equal 0...
	
	
	state:setAnimationByName(0, "run", true, 0)
		--or state:addAnimationByName(0, "run", true, 0)
	
	
	end
	
	
	    state:apply(skeleton)
	
	
	end
	

Oh my, copy pasting and editing code in here is not cool. Sorry about the abysmal formatting.. Or am I just doing it wrong?

 

Anyway I think this might get your desired result.

 



[TOPIC: post.html]
#3

AppdojoStudios

[GLOBAL: userInfoPane.html]
AppdojoStudios
  • Contributor

  • 110 posts
  • Corona SDK

Sorry for the delayed response, but that almost works. I can use the functions you gave above to change the current animation, but it doesn't work in the enterFrame listener. Although, if I set the animation to "run" right after the creation of the state then it works. I get this error:
 

 

2013-12-08 22:52:03.846 Corona Simulator[30497:e03] Runtime error
...c/Documents/code/miners/spine-lua/AnimationState.lua:56: attempt to compare number with nil
stack traceback:
    [C]: ?
    ...c/Documents/code/miners/spine-lua/AnimationState.lua:56: in function 'setCurrent'
    ...c/Documents/code/miners/spine-lua/AnimationState.lua:172: in function <...c/Documents/code/miners/spine-lua/AnimationState.lua:167>
    (tail call): ?
    ...sers/Zac/Documents/code/miners/examples/spineboy.lua:115: in function 'enterFrame'
    /Users/Zac/Documents/code/miners/game.lua:329: in function 'onEnterFrame'
    /Users/Zac/Documents/code/miners/gui.lua:116: in function </Users/Zac/Documents/code/miners/gui.lua:113>
    ?: in function <?:218>
 
Do you know what this means?


[TOPIC: post.html]
#4

Reaver

[GLOBAL: userInfoPane.html]
Reaver
  • Enthusiast

  • 87 posts
  • Corona SDK

Hi,

 

Can't really say I know what's going on here. It seems like the call to getMix returns nil, but as far as I can see, that should not even be possible due to how AnimationStateData is set up. Have you gotten any further since posting? :P

 

How and where are you calling the update function of animationState?



[TOPIC: post.html]
#5

AppdojoStudios

[GLOBAL: userInfoPane.html]
AppdojoStudios
  • Contributor

  • 110 posts
  • Corona SDK

Sorry for the late reply, I haven't been able to code very much this week. Here is what I have so far, it still get's the error and I still can't figure out the cause:

 
 

local M = {}
 
function M.new(scale) 
    -- This example shows simple usage of displaying a skeleton with queued animations.
 
    local spine = require "spine-corona.spine"
 
    M.physicsBody = nil
    local animSpeed = 1
 
    local json = spine.SkeletonJson.new()
    json.scale = scale
    local skeletonData = json:readSkeletonDataFile("examples/spineboy/skeleton.json")
    
    local skeleton = spine.Skeleton.new(skeletonData)
    function skeleton:createImage (attachment)
        -- Customize where images are loaded.
        return display.newImage("examples/spineboy/images/" .. attachment.name .. ".png")
    end
 
    M.physicsBody = display.newRect( -45, -250, json.scale * 170, json.scale * 500)
    M.physicsBody.damage = 5
    M.physicsBody.alpha = 0.01
    physics.addBody(M.physicsBody, "dynamic", {bounce = 0.2, density = 2.5, friction = 1})
    M.physicsBody.isFixedRotation = true
 
    function M.addToGroup(group) 
        group:insert(skeleton.group)
        group:insert(M.physicsBody)
    end
 
    function M.getPhysicsBody() 
        return M.physicsBody
    end
 
    function M.setPlayerXScale(x) 
        skeleton.group.scaleX = x
    end
 
    function M.getSkeleton()
        return skeleton
    end
 
    function M.setAnimSpeed( speed )
        animSpeed = speed
    end
 
    skeleton.group.x = 0
    skeleton.group.y = 0
    skeleton.flipX = false
    skeleton.flipY = false
    skeleton.debug = true -- Omit or set to false to not draw debug lines on top of the images.
    skeleton.debugAabb = true
    skeleton:setToSetupPose()
 
    local bounds = spine.SkeletonBounds.new()
 
    -- AnimationStateData defines crossfade durations between animations.
    local stateData = spine.AnimationStateData.new(skeletonData)
    stateData:setMix("idle", "run", 0.2)
    stateData:setMix("run", "idle", 0.4)
 
    -- AnimationState has a queue of animations and can apply them with crossfading.
    local state = spine.AnimationState.new(stateData)
    state:setAnimationByName(0, "run", true, 0)
 
    -- local state2 = spine.AnimationState.new(stateData)
    -- state2:setAnimationByName(0, "run", true, 0)
 
    state.onStart = function (trackIndex)
        print(trackIndex.." start: "..state:getCurrent(trackIndex).animation.name)
    end
    state.onEnd = function (trackIndex)
        print(trackIndex.." end: "..state:getCurrent(trackIndex).animation.name)
    end
    state.onComplete = function (trackIndex, loopCount)
        print(trackIndex.." complete: "..state:getCurrent(trackIndex).animation.name..", "..loopCount)
    end
    state.onEvent = function (trackIndex, event)
        print(trackIndex.." event: "..state:getCurrent(trackIndex).animation.name..", "..event.data.name..", "..event.intValue..", "..event.floatValue..", '"..(event.stringValue or "").."'")
    end
 
    local lastTime = 0
    local touchX = 999999
    local touchY = 999999
    local headSlot = skeleton:findSlot("head")
 
    local hip = skeleton:findBone("hip")
 
    local rep = true
 
    function M.enterFrame (event) 
        -- Compute time in seconds since last frame.
        local currentTime = event.time / 1000
        local delta = currentTime - lastTime
        lastTime = currentTime
 
        -- Update the state with the delta time, apply it, and update the world transforms.
        --state2:update(delta * animSpeed)
 
        skeleton.group.x = M.physicsBody.x
        skeleton.group.y = M.physicsBody.y + (M.physicsBody.height / 2)
 
        local vx, vy = M.physicsBody:getLinearVelocity()
        if (vx == 0) then
            M.setAnimSpeed(  1) -- 140
            state:setAnimationByName(0, "idle", true, 0)
        else 
            M.setAnimSpeed(  math.abs(vx) /300) -- 140
            state:setAnimationByName(0, "run", true, 0)
        end
 
        -- Bounding box hit detection.
        bounds:update(skeleton, true)
 
        state:update(delta * animSpeed)
        state:apply(skeleton)
        skeleton:updateWorldTransform()
    end
end
 
 
return M

 



[topic_controls]
 
[/topic_controls]