Our game Pablo and the Puppet Punch needed a lot of animations to play on screen at once along with an inverse kinematic implementation and a whole lot of VFX. We looked for options for implementing Skeletal Animations in our game. Skeletal Animation is one of the best ways to optimize the total size of your game for mobile devices such as iPhone and iPad.

For understanding what skeletal animation is and how it can help you, read this blog

This implementation is in C#; but unfortunately he did not share the exporter he used for converting flash animations to XML that can be read in code.

No point being sad, we continued our search for different skeletal animation tools which could help us. Another promising breakthrough was “Demina”. Again, a C# implementation based on bone structure, it looked promising at first sight as it had a good UI for getting your animation in place. The only concern is that you need a “mouse” as the control to move a bone is through middle mouse button. Not a difficult requirement though! But since you have the source, you can quickly change this input control and make it an easy drive for games created in XNA etc.

Interface of Demina

But we needed something that could serve our Cocos2D environment. We got through this tutorial on Cocos2D forum called TDAnimEngine which creates 2D characters in Maya and converts it into Cocos2D nodes. Maya sounded a little threatening but still we took a chance but there were many faults in the implementation of given source and none of us being an expert in mel script, it became a headache for us to get this thing working.

TDAnimEngine Implementation in Maya

If you want to try, download this version as a lot of things have been fixed in this one. Still there were some bugs in positioning the character, and Haykhelped me figure that out.  At first please make sure to build your necessary object using simple planes and add as textures your PNG files which you’re going to use in your iOS project. This is his changed version of MayaToCocos2DNodes.mel file:


string $master = "Body";
string $sel[] = `ls -selection`;

// Master position
float $originalPos[] = `xform -ws -q -t ($master)`;

string $children[] = `ls -selection`;
print ("<root>\n<nodesConfig>\n");

$mat = getSurfaceShader($master);
$fileText = getTextureFromMaterial($mat);
$fileName = filepart(`getAttr ($fileText+".fileTextureName")`);

float $width = `getAttr ($fileText+".outSizeX")`/100;
float $height = `getAttr ($fileText+".outSizeY")`/100;

float $ppoint[] = `xform -q -t ($master+".rotatePivot")`;
float $px = $ppoint[0];
float $py = $ppoint[1];

float $apX = ($width/2+$px)/$width;
float $apY = ($height/2+$py)/$height;
float $rot[] = `getAttr ($master+".r")`;
float $scl[] = `getAttr ($master+".s")`;

print ("\t<node id='"+$master+"' parent='root' x='"+$originalPos[0]+"'
y='"+$originalPos[1]+"' image='"+$fileName+"' apx='"+$apX+"' apy='"+$apY+"' rz='"+$rot[2]+"' sx='"+$scl[0]+"' sy='"+$scl[1]+"' w='"+$width+"' h='"+$height+"' />\n");

$parentnode = $master;

for ($o = 0; $o < `size $children`; $o++)
{
if ($children[$o] != $master)
{

// -------------------------------------------------------------
// GET POSITION

string $parent[] = `listRelatives -p ($children[$o])`;
float $pos[] = `getAttr ($children[$o]+".t")`;
float $rot[] = `getAttr ($children[$o]+".r")`;
float $scl[] = `getAttr ($children[$o]+".s")`;

// -------------------------------------------------------------
// GET ANCHOR POINT

float $ppoint[] = `xform -q -ws -t ($children[$o]+".rotatePivot")`;
float $px = $ppoint[0];
float $py = $ppoint[1];

$mat = getSurfaceShader($children[$o]);

$fileText = getTextureFromMaterial($mat);
$fileName = filepart(`getAttr ($fileText+".fileTextureName")`);

//print ("\n"+$children[$o]+"\n"+$px + "\n" + $py);
// -------------------------------------------------------------
// OUTPUT

print ("\t<node id='"+$children[$o]+"' parent='"+$parent[0]+"' image='"+$fileName+"' x='"+$pos[0]+"' y='"+$pos[1]+"' z='"+$pos[2]+"' rz='"+$rot[2]+"' sx='"+$scl[0]+"' sy='"+$scl[2]+"' apx='"+$px+"' apy='"+$py+"' />\n");
}
}
print ("</nodesConfig>\n</root>");

// HELPER METHODS -------------------------------------------------------------------

proc string getSurfaceShader (string $objName)
{

string $myShapeNode[] = `listRelatives -children -shapes $objName`;
string $mySGs[] = `listConnections -type shadingEngine $myShapeNode[0]`;
string $surfaceShader[] = `listConnections ($mySGs[0] + ".surfaceShader")`;
return $surfaceShader[0];
}

proc string rootNode( string $object )
{

string $buffer[];
tokenize $object "." $buffer;
return $buffer[0];
}

proc string getTextureFromMaterial( string $material )
{

string $texture = "";
string $class[] = getClassification( `nodeType $material` );
if ( "shader/surface" == $class[0] && `connectionInfo -id
( $material + ".color" )` )
{
$texture = rootNode( `connectionInfo -sfd ( $material + ".color" )` );
}
return $texture;
}

global proc string filepart( string $path )
// Extracts the path portion of an absolute filepath.
// Input: e.g. "D:/projects/default/scenes/myScene.mb"
// Result: e.g. "myScene.mb"
//
// Filepath can be delimited with
// either slash ("/" or "\")
{
string $filepart = match( "[^/\\]*$", $path );

return $filepart;
};

We did not try this but we are sharing this as it may be of use to someone who needs a solution.

Also , In getTextureFromMaterial function value of $class[0] is “drawdb/shader/surface/lambert:shader/surface” instead of “shader/surface”.

Once you make these changes it should work for you. If it doesn’t , don’t get disappointed and keep reading .

Along with this solution, we came across an excellent tool called grapefrukt exporter.( Hayk suggested it! ) I call it excellent as it finally solved all our troubles though it was a little difficult to start with. And the most important benefit was it uses Flash and not Maya.

Below we want to share with you quickly how you can set up grapefrukt exporter and convert the XML data it generates into cocos2D nodes. You can watch this video made by the developer of this exporter to have a quick idea of what grapefrukt can do for you. To read the tutorial on how to exactly use grapefrukt, read the second part of this series here.

If you any other awesome tools for skeletal animation, please share the links in comments below. We hope this will be of use to young developers like us.

Signing off,

Team MechMocha

FB page  : https://www.facebook.com/MechMocha

Twitter   :https://www.twitter.com/#!/MechMocha

Youtube : http://www.youtube.com/user/MechMocha

 

 

2 Comments

 

  1. November 16, 2012  5:32 pm by xataka android Reply

    Wow, amazing blog layout! How long have you been blogging for? you make blogging look easy. The overall look of your web site is excellent, let alone the content!. Thanks For Your article about Cocos2D Skeletal Animation : Part 1 .

Leave a reply

 

Your email address will not be published.