Developer Insights
GAF from animator and developer points of view
Developer: Glera Games
Location: Vilnius, Lithuania
Game Title: Mahjong Treasure Quest
Game Genre: Mahjong, Board
Framework: Cocos2d-x
Release date: March 17, 2016
Kirill Barkouski
Mobile game developer
Glera Games
To find the best solution to a task, people often have to reinvent the wheel. At our company, we spend a lot of time developing products to perfection and have in the past taken up to two years. While diligently searching for a solution for our animation challenges, we finally found the GAF Converter.
Once we began using animations made with GAF, we discovered that the animations could be quickly incorporated into our project without any negative impact on FPS. Animation requirements became simpler with GAF, which subsequently offered new opportunities to our animators. A considerable advantage of using GAF is that the new approach to animation arrangement reduces the size of our files by two-thirds! For example, we had an animation based on our own method that was 300kb, but with GAF, the size of the animation was reduced to 100kb. This reduction in size allowed us to add more animations with no significant increase in the size of the game; and a great number of active animations on the maps does appeal to our players. Another cool feature is that our game, Mahjong Treasure Quest, now has touch control animations built into the level maps. The project is written in Cocos2d-x; therefore, the sample code provided is in C++.
Parallax is available when viewing Mahjong Treasure Quest maps of any level, so having smooth touch control was something we kept in the forefront of our minds. Therefore, all GAF assets are pre-loaded within the initialization method. While each map is being initialized, the assets are retrieved from a resource cache and assigned to a button:
const auto& chars = chaptersHeroes.at(chapterId); //animations for current chapter
for(const auto& ch : chars){
string nameIdle = ch.first;
auto mAssets = (GAFAsset*)_mapChars.at(nameIdle); //assets from cache
auto animChar = mAssets->createObject();
animChar->playSequence("idle", true); //start idle animation
int startFrame = animChar->getStartFrame("idle");
int endFrame = animChar->getEndFrame("idle");
int framesCount = endFrame - startFrame;
animChar->start();
animChar->setFrame(startFrame +
Macros::random()%framesCount; //play animation from randrom place
auto animHolder = Node::create(); //holder for animation object
animHolder->setAnchorPoint(Vec2::ANCHOR_MIDDLE);
animHolder->setContentSize(animChar->getContentSize());
animHolder->addChild(animChar);
animChar->setNormalizedPosition({.5f, .5f});
auto charMenuItem = MenuItemLabel::create(animHolder,
CC_CALLBACK_1(ParallaxLevelMap::onMapCharTap,
this)); //menu item object with animation label
//setting disable color for preventing gray image
charMenuItem->setDisabledColor(Color3B::WHITE);
charMenuItem->setAnchorPoint(Vec2::ZERO);
itemSp->addChild(charMenuItem, 1, 1);
Vec2 pos = ch.second; //relative position of center on chapter map
//calculating relative position of bottom left angle
pos -= Vec2(animChar->getContentSize().width*.5f/itemSp->getContentSize().width,
animChar->getContentSize().height*.5/itemSp->getContentSize().height);
charMenuItem->setNormalizedPosition(pos);
}
Button-pressing processing method:
void ParallaxLevelMap::onMapCharTap(cocos2d::Ref *sender){
auto charMenuItem = (MenuItemLabel*)sender;
//getting access to gaf object from menu item
auto charObject = (GAFObject*)charMenuItem->getLabel()->getChildByTag(1);
//not all objects have tap animation
if(charObject->playSequence("tap", false)){
//disable menu item for preventing lag on animation
charMenuItem->setEnabled(false);
charObject->setAnimationFinishedPlayDelegate([](GAFObject* object){
//back to normal state
((MenuItem*)(object->getParent()->getParent()))->setEnabled(true);
object->playSequence("idle", true);
object->setAnimationFinishedPlayDelegate(nullptr);
});
}
}
The GAF Converter has given immense relief to our programmers and animators, making it possible for us to easily create a vivid and brisk experience for users. The procedure of building in animation has entailed almost no issues. All of the aforementioned, provides the best proof that GAF deserves its place on the market.
Kirill Kagan
Animator
Glera Games
The use of Flash in mobile gaming was rather limited until recently, as application size requirements involved certain restrictions. It wasn’t possible to harness all the power of the technology for creating smooth animations with high FPS. In particular, this was due to spritesheet atlases that simply forced animators to reduce the number of character animation frames as much as possible. There have always been attempts to convert parametric Flash animation into a format compatible with third-party engines. A lot of companies have used their own converters. These attempts have provided fairly acceptable results, although the animator has always remained confined. In order to make a converter understand the original Adobe Flash file correctly, it had to comply with quite strict requirements that included limitations on number of layers, the necessity to match animations in the file to a determined hierarchy, and no effects, masks, and nesting available. The GAF Converter is the solution that allows use of Adobe Flash for gaming tasks of any kind.
The advantages from the point of view of an animator:
-
Fully automatic Timeline export and packing, rasterization of all characters’ vector images and their placement in an atlas.
-
Easy scaling. In order to change the animation scale, you can simply make the upper movie clip in the hierarchy bigger or smaller.
-
No animation restrictions (nesting, the number of movie clips, length, and the number of layers).
-
Frame-by-frame animation availability (when exporting, it’s being rendered into a sequence of frames that will be put in an atlas).
-
A GAF file can store any number of animations.
-
GAF Player enables a check for animation names, correct looping, and possibility of placing a character in any background.
Disadvantages:
-
Not all frameworks support advanced GAF functionality. For instance, I had issues with displaying a mask in Unity.
-
Different modes of aliasing can’t be applied.
There is no special way or algorithm of how to use GAF. Below, you’ll find my approach to creating character animations:
Character creation:
-
A puppet with a set of human body parts is put in the movie clip.
-
Make animations inside the movie clip. If nested animation is needed, I do it by placing the animation as a graphic with any desired playback mode.
-
I do the whole set of character animations in different movie clips, where a separate animation means a separate copy. As a result, I have a set of movie clips in the main scene, with each of them storing character animation.
-
I convert them in “Play Once” graphics and place them in layers, setting the length of a layer equal to animation length of the graphic that is in this layer.
-
I arrange all animations, one by one, in Timeline; and I create an empty layer at the top, with frames in the points where each animation begins. Each frame is then assigned a name (idle, walk, run, attack).
-
Set AS3 in compilation settings, and then publish.
-
Launch the GAF converter, and drag the compiled SWF file into the converter.
-
The resulting ZIP archive is submitted to a programmer, and then we can start creating a new character.
I’d like to say thanks to the GAF Media team for their excellent product that has helped solve so many issues, and revealed new Flash usage opportunities in a modern gamedev.