Actual, Basic Example of using Spine in Corona?

So, really struggling here and could use some guidance. I just need to know the most basic method to get an animation on screen using Spine.

-- Require in the spine manager local spine = require ("spine-corona.spine") -- Extract animation data from Json -- Assume it's in a folder called "anim" and is named "skeleton.json" local json = spine.SkeletonJson.new() local data = json:readSkeletonDataFile("anim/skeleton.json") -- Make the skeleton using this data local char = spine.Skeleton.new( data ) -- Fetch the idle animation local idle = data:findAnimation( "idle" ) -- Overwrite how spine creates bone animations. -- Assume seperate images; no imageSheets. function char:createImage(attachment) return display.newImage("anim/"..attachment.name..".png") end -- Set the animation state -- If I remove this line, Corona loads with no error messages, -- but there is no character on-screen. idle.apply( char, nil, true)

Unfortunately, idle.apply complains that char (the skeleton) is nil. (It’s not - a print statement confirms it.) However, looking at the animationState code, it’s looking for “skeleton.skeletonData”, which doesn’t seem to exist.

Where am I going wrong? The esoteric sample code is nice but I don’t have animations to blend together. Just a single skeleton with a single animation to play.

Hi!

I’m not sure this will solve the problem but apply should be called on the animation so it should be idle : apply(char, time, true). This leads me to believe that the idle variable is nil in the example.

You will also need to execute apply in a loop which increments a timer so that the animation can change based on the time change and then call skeleton:updateWorldTransform() afterwards to draw the change in animation. This is typically a runtime listener that gets executed on the “enterframe” event.

Let me know if anything is unclear :slight_smile:

idle is not nil; not only is there no error on finding the animation, but it shows up (properly) as a table if you use a print statement.

If I apply an actual number to the time variable (ie: 1000) Animation.lua reports an error with ipairs() on line 49. If I move the apply command to a Runtime loop (ie: the one shown in the sample code provided by Esoteric) the same error occurs. 

Totally stuck here… :frowning:

Did using : instead of . provide any useful results at least? :P 

I’m not sure if it’s necessary but I also run skeleton:setToSetupPose() before doing anything else with animations for example (just because it was done in the spine example). It might be the setup that is needed. 

Well, you’re right, I completely forgot to use : instead of ., which is a historical weakness of mine. But when I do that, I get:

/spine-lua/Animation.lua:221: attempt to perform arithmetic on field ‘rotation’ (a nil value)

(That line: amount = bone.data.rotation + (lastFrameValue + amount * percent) - bone.rotation )

…which strikes me as a legit bug in the Spine implementation or how it exports data.  

Investigating the variables, bone.data.rotation exists, while bone.rotation does not. ‘bone’ does exist, however.

I think everyone does that :stuck_out_tongue: It’s usually the first thing I check for when I get an error that a variable that I know has a value is reported of having a nil value.

I think calling skeleton:setToSetupPose() should initialize the bone fields including rotation. It should be called towards the end of the setup code and definitely before the animation is applied.

Reaver, you’re absolutely right - setToSetupPose() does add those values. Crazy that it’s not just added while making the skeleton, but okay.

So now the project loads without errors…but there is nothing on-screen. (I know from experience that if I feed the wrong path/filename to :createImage() that I would get an error, so it’s finding the right assets.)  I have the Runtime loop running like this:

local lastTime = 0 local animationTime = 0 Runtime:addEventListener("enterFrame", function (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. idle:apply( char, delta, true ) char:updateWorldTransform() end)

What am I missing to actually see anything?

Self update: It seems that the spine character is set to have a bottom reference point.

skeleton.group.x = display.contentCenterX skeleton.group.y = display.contentHeight

That gets my character visible! The only problem? There’s no animation at all (despite the Runtime listener). So it seems that the code above (previous post) is not enough to animate?

Nice. I think you might want to have an animationTime variable that you add the delta value to

local animationTime = 0

then in render loop:

animationTIme = animationTime + delta

idle:apply(char, animationTime, true)

Right now if delta is roughly the same value each frame the animation will be set to the same state each time the apply is called. Apply sets the skeleton rig to a state based on the time. If the time is the same each time apply is called the skeleton will be set to the same pose.

You’re right. That did it. It’s animating! Thanks Reaver!

Now to begin writing replacement code so Corona users can use this stuff without being bogged down in the details.

No problem!

You should also look at animationState. It removes some of the details and sets up a queue for animations.

Yeah, I suppose my beef was that if you only have one animation, animationState is completely counterproductive. But I will take a look asap.

I’ve fixed Bone not have SRT values by default. Sorry I didn’t see this earlier, I’m more active on the Spine forums.

Hi!

I’m not sure this will solve the problem but apply should be called on the animation so it should be idle : apply(char, time, true). This leads me to believe that the idle variable is nil in the example.

You will also need to execute apply in a loop which increments a timer so that the animation can change based on the time change and then call skeleton:updateWorldTransform() afterwards to draw the change in animation. This is typically a runtime listener that gets executed on the “enterframe” event.

Let me know if anything is unclear :slight_smile:

idle is not nil; not only is there no error on finding the animation, but it shows up (properly) as a table if you use a print statement.

If I apply an actual number to the time variable (ie: 1000) Animation.lua reports an error with ipairs() on line 49. If I move the apply command to a Runtime loop (ie: the one shown in the sample code provided by Esoteric) the same error occurs. 

Totally stuck here… :frowning:

Did using : instead of . provide any useful results at least? :P 

I’m not sure if it’s necessary but I also run skeleton:setToSetupPose() before doing anything else with animations for example (just because it was done in the spine example). It might be the setup that is needed. 

Well, you’re right, I completely forgot to use : instead of ., which is a historical weakness of mine. But when I do that, I get:

/spine-lua/Animation.lua:221: attempt to perform arithmetic on field ‘rotation’ (a nil value)

(That line: amount = bone.data.rotation + (lastFrameValue + amount * percent) - bone.rotation )

…which strikes me as a legit bug in the Spine implementation or how it exports data.  

Investigating the variables, bone.data.rotation exists, while bone.rotation does not. ‘bone’ does exist, however.

I think everyone does that :stuck_out_tongue: It’s usually the first thing I check for when I get an error that a variable that I know has a value is reported of having a nil value.

I think calling skeleton:setToSetupPose() should initialize the bone fields including rotation. It should be called towards the end of the setup code and definitely before the animation is applied.

Reaver, you’re absolutely right - setToSetupPose() does add those values. Crazy that it’s not just added while making the skeleton, but okay.

So now the project loads without errors…but there is nothing on-screen. (I know from experience that if I feed the wrong path/filename to :createImage() that I would get an error, so it’s finding the right assets.)  I have the Runtime loop running like this:

local lastTime = 0 local animationTime = 0 Runtime:addEventListener("enterFrame", function (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. idle:apply( char, delta, true ) char:updateWorldTransform() end)

What am I missing to actually see anything?

Self update: It seems that the spine character is set to have a bottom reference point.

skeleton.group.x = display.contentCenterX skeleton.group.y = display.contentHeight

That gets my character visible! The only problem? There’s no animation at all (despite the Runtime listener). So it seems that the code above (previous post) is not enough to animate?