Spine: 2D skeletal animation tool

It’s ok, let’s just move on. :slight_smile:

I’m familiar with both iOS and Android development but not with cocos2d-x. Are there issues with the current cocos2d-x runtime on these platforms? I developed on Windows because it was fastest. I’ll go back and try out a setup on mobile, but I want to do at least enough first to get people going for cocos2d-x and cocos2d-iphone.

Nathan,

Thanks for sticking with it.

The issue that I am having relates to file access.

On Android under Cocos2dx, you cannot use relative paths for assets (json, etc)

There are two methods in Cocos2dx that are used for cross platform.

CCFileUtils::sharedFileUtils()->fullPathFromRelativePath()

and

CCFileUtils::sharedFileUtils()->getFileData()

These methods, used together, will reliably allow you to read on any platform.

Because Android files are packaged into the APK, and iOS may have different paths, these methods are required.

I’m so excited to see the new runtimes coming online. Reading the code, I love how straightforward it appears.

From my POV, we’ve got some minor issues with cross-platform API use in Cocos2dx and we’ll be ready to rock :slight_smile:

We’ve got your back and will all be testing. I know my art team is TOTALLY jazzed about Spine. Great work.

-Cory

I see, thanks for the brief cocos2d tutorial. :slight_smile: No problem to fix, the base classes already have the functionality needed. Fixed here:


The example code now looks like this:
https://github.com/EsotericSoftware/spine-runtimes/blob/master/spine-cocos2dx/spine-cocos2dx/example/ExampleScene.cpp#L20
Internally it uses CCFileUtils::sharedFileUtils()->fullPathForFilename and getFileData. Hope that works for you on mobile. Sorry I haven’t tested it yet!

Hi, also to better align to the cocos2d-x coding style you could use the autorelease pool to have the memory deallocation managed automatically.

Eg: for CCSkeleton you would have

CCSkeleton* CCSkeleton::create(SkeletonData* skeletonData)
{
   CCSkeleton* pRet=new CCSkeleton(skeletonData);
   pRet->autorelease();

   return pRet;
}

and in the example:

    CCSkeleton* skeletonNode = CCSkeleton::create(skeletonData);
    skeletonNode->state->setAnimation(animation, true);

More info regarding this can be found here: http://www.cocos2d-x.org/projects/cocos2d-x/wiki/Reference_Count_and_AutoReleasePool_in_Cocos2d-x

PS: Spine is plain awesome:)

Well he’ve worked hard to push it out in quite a short time. The example does not include an iOS project, but we can create it easily, don’t we?
>
Here’s an iOS project which is identical to Nate’s Windows project. To make it small, I removed stuffs in “libs” folder. Please fill in the folder first to make the project run.

Your IOS project missed 2 files, ExampleScene.h and ExampleScene.cpp.

Zync Tedy wrote:

> Well he’ve worked hard to push it out in quite a short time. The example does not include an iOS project, but we can create it easily, don’t we?
>
> Here’s an iOS project which is identical to Nate’s Windows project. To make it small, I removed stuffs in “libs” folder. Please fill in the folder first to make the project run.
>
Your IOS project missed 2 files, ExampleScene.h and ExampleScene.cpp.

Sorry guys, I forgot to add files.

I forked and edited example project. You can download a working iOS example from here:

proj.win32 is messed up in my fork, I’ll fix it as soon as I get access to a Windows computer.

[Update] I also added multiple-resolutions demo, cocos2d-x 2.1.2 style :smiley:

I forked and edited example project. You can download a working iOS example from here:
https://github.com/vinova/spine-runtimes
>

Thanks guy. iOS example prj work quite well :slight_smile:

very perfect tool for skeletal animation tool!

Nathan Sweet wrote:

The cocos2d-x runtime is ready for you to use!
https://github.com/EsotericSoftware/spine-runtimes/tree/master/spine-cocos2dx
Feedback is welcome. :slight_smile:

Nathan, stop wasting time on Draco, not worth it :slight_smile:

Great work, glad you finished the runtime, works great.

Draco, LLC Draco
What are you trying to prove smartass? appreciate and help instead of complaining like a 12 year old boy, Grow up!

I smell jealousy :wink:

Hi guys,

I needed debug drawing so I wrote a CCNode subclass to do it.
Feel free to use & contribute:

Thanks Stefan! I incorporated your debug rendering into CCSkeleton, just set debug=true. :slight_smile: Maybe you would like to do a pull request for the iOS project?

Nathan Sweet wrote:

Thanks Stefan! I incorporated your debug rendering into CCSkeleton, just set debug=true. :slight_smile: Maybe you would like to do a pull request for the iOS project?

Yes I will, as soon as I fix proj.win32 :stuck_out_tongue:

Btw, how do we handle multiple-resolutions with Spine?
The scenario is that I create game for both iPhone Retina and iPhone non-retina. I draw my character in Photoshop at retina resolution. Animate my character in Spine at retina resolution. Now how do I generate proper JSON files for retina and non-retina resolutions? For images I can use TexturePacker, but then the skeleton and the images will mismatch.

You can set a scale on the SkeletonJson to scale the skeleton and animations. Eg, if you are using images twice as big as when the images used when the Spine animations were created, set a scale of 2.

I’ve merged Stefan Nguyen’s changes, thanks! I’ve tested the Windows and iOS projects and everything is working as intended. :slight_smile:

Cristian Cristea, I didn’t miss your suggestion. :slight_smile: I added CCSkeleton::create(SkeletonData*). The Atlas, SkeletonData, and Animation objects still need to be manually freed. I added code to the example to do this. I started changing them to extend CCObject so they could use the autorelease pool, but then reverted. These objects are intended for reuse over a long period of time. I think typical usage will require explicit retains to keep instances around until needed, so the end result is the same. It you always need to do an explicit release, might as well just use delete.

Nathan Sweet wrote:

You can set a scale on the SkeletonJson to scale the skeleton and animations. Eg, if you are using images twice as big as when the images used when the Spine animations were created, set a scale of 2.

Thanks, Nathan. I found another way around: scale bones before export. Will there be an “Export scale” option?

Nathan Sweet wrote:

These objects are intended for reuse over a long period of time. I think typical usage will require explicit retains to keep instances around until needed, so the end result is the same. It you always need to do an explicit release, might as well just use delete.

In this case maybe we could have an asset manager that will automatically release the resources registered when it is destroyed. We are using something similar for sprites and animations in our game.

Stefan Nguyen, unlikely. You can just get the root bone and set a scale programmatically. The difference is setting a scale on the root bone doesn’t change the units for the bone’s local SRT, while setting a scale on the JSON loader does change the values for all the bones.

Question Nathan,

How does the animation blending work? Let’s say I want to switch smoothly from idle animation to running and vice versa. Is there any support for this?

Thanks.

You have a skeleton and can pose it with an animation:
walkAnimation.apply(skeleton, time, loop)
apply() sets the skeleton bones to the animation pose for the given time. There is another method:
jumpAnimation.mix(skeleton, time, loop, alpha)
This sets the skeleton bones to somewhere between the current pose and the animation pose for the given time. The alpha parameter is between 0 and 1 and describes how much of the current pose (0) and how much of the animation pose (1) to use.

So, mixing is just a matter of using apply() and mix() with different animations and keeping track of the time. There is a helper called AnimationState:
AnimationStateData stateData = new AnimationStateData();
stateData.setMixing(walkAnimation, jumpAnimation, 0.4f);
state = new AnimationState(stateData);
AnimationStateData describes the mixing between animations, AnimationState holds the current state for a skeleton. You set the current animation:
state.setAnimation(walkAnimation, loop);
Then in the game loop you update the state with a delta time and pose the skeleton with it:
state.update(deltaTime);
state.apply(skeleton);
As the current animation changes with state.setAnimation(), the AnimationState automatically handles posing the skeleton with the old animation and mixing the new one for the durations described with setMixing().

Hope that helps! Some example code here: