Better animation control through scripting

Edit: I uploaded a video on YouTube that shows these features in action. The video can be found at the bottom of the post

Among the features I implemented in the past two weeks this is probably the most promising one: the ability to control animations through Lua scripts. Simply put, now it is posible to load an animated scene and attach it a Lua script that controls the animation loop by specifying which animation to play.

Animation Components

Any node in the scene may have one or more components attached to it. A component can be anything from a single value to complex artificial intelligence behaviors. In this case, I’m going to focus on the Animation Components family.  Since an animation can be defined in multiple ways, it seems logical to have several animation components. For example, the VertexAnimationComponent class is used to perform vertex morphing (i.e. the animation used in MD2 models). SpriteAnimationComponent is a new class created with the purpose of handling sprite animations through the update of texture coordinates. Although not yet completed, the SkeletalAnimationComponent class will be used when dealing with skeletal animation. The following is a simplified UML diagram of the animation-related components:

A simplified class diagram for animation-related components

A single animation interface

For the sake of simplicity, we’re going to focus only on the two operations that are present in the diagram: setCurrentAnimation() and update()

setCurrentAnimation() is used to indicate the key frames that we want to display in the animation. For example, setCurrentAnimation(0, 10, -1) will reproduce an animation from key frame 0 to key frame 10 in an infinite loop (the last argument indicates how may loops we want, with -1 indicating infinite).

As it name suggests, update() is used to perform the animation step and varies depending on the animation type. If we’re performing a morphing animation, the update() function will modify the vertex positions to the interpolated value between the current frame and the next one. On the other hand, a sprite animation will change the texture coordinates based on the texture atlas containing all of the animation frames.

A texture atlas containing all of the animation frames for the character

These two methods are key to handle animations regardless of the actual animation implementations:

Node *aNode = getSomeNode();
AnimationComponent *animationComponent = 
   static_cast(aNode->getComponentWithName(AnimationComponent::NAME));
if (animationComponent) {
   animationComponent->setCurrentAnimation(0, 10, -1);
}

Scripting

In Lua, the above code is translated as follows:

function playJumpAnimation()
   animationComponent = owner:getComponent("Animation")
   animationComponent:setCurrentAnimation(0, 10, -1)
end

Whenever the character jumps it will perform the animation indicated by the script. And since this script can be changed in real-time, we do any adjustment as necessary on the fly. This is particularly useful for artists, as they can modify the animation execution as they play the game.

Demo

I just uploaded this video to YouTube showing these features in action using the Sandbox

Conclusion

This is my first attempt for consolidating animation control. I still need to implement some sort of speed mechanism that can be used to vary the time between frames (some animations may be required to be played at lower/higher frame rates). I tried this out in the Sandbox with both MD2 models and sprites and it works like a charm. In most cases I was able to switch between one and the other without having to modify the Lua script at all.

See you next time

Advertisements

Cleaning up the mess

Although this week I took some time off from Crimild due to other priorities, I still managed to do a little code cleanup. The large amount of changes that were implemented in the engine in the last past months produced a nasty side-effect: there were a lot of functions, classes and even entire features that were no longer used, like Effects, Behaviors and several “old-styled” Terrain implementations, just to name a few.

In addition, I found several problems with the CMake template for iOS-related projects after upgrading the iOS SDK to version 4.3. Particularly, using the generated Crimild library in iPhone projects led to linking errors. Apparently, there is a target architecture mismatch between the library and the final executable (armv7 vs armv6) but I was not able to confirm this. Instead, I created a new Xcode project including all Crimild sources in order to build the iPhone library from it. Some months ago I wrote about how annoying this process is since I need to manually add or remove source files whenever something changes, so this is actually a step back. But until I figure out what is really going on here I’m out of option.

Concerning new stuff, I only had enough time to fix a couple of bugs in the Sandbox that were producing clipping errors during the rendering phase. And that was pretty much it.

See you next week

New Sandbox features

I have some many things to write about that it was hard to decide where to start. A lot of new features were added in the past couple of weeks, including scene streaming (the possibility to save/load an entire scene either to a file or to a memory buffer), new reusable components, an improved XML factory and even an entire new interface for the Sandbox.

Contrary to common sense, I will start from the very end. That is, the new user interface for the Sandbox which I just finished a couple of hours ago. If you recall from my previous post, the interface for the Sandbox was, well, a bit ugly to say the least:

Web developers are familiar with the jQuery library. This library provides a set of useful Javascript tools to create state-of-the-art web interfaces. And there’s also jQuery UI (which you can learn more about it here). jQuery UI is built on top of jQuery and comes with an entire collection of ready-to-use widgets and themes. Thanks to jQuery, the Sandbox interface now looks a lot better:

In addition to the new interface I also added several new functionalities. Tacking advantage of the new streaming features, I can now save and load any scene created within the Sandbox. I added new/load/save project modal dialogs to handle this:

The script editor is now making use of the Lua mode for editing, which allows for syntax highlighting. I’m still not sure about the dark theme and the font size is a bit small, but I’ll worry about that later:

An asset loader was also added, listing all available assets. Assets are specified using the Crimild XML schema as defined by the XML Factory. This allows the possibility of creating new assets on the fly without having to restart the Sandbox:

I’m still working on node selection and manipulation. I want to achieve a mechanism that allows the user to select, move, rotate and scale any object in the scene (whether it’s representing geometry, a trigger, a camera or any other type of object) using simple controls. Mainly because we’re all using laptops here with touch pads and I want the the object manipulation to feel as natural as possible.  I’ll probably make a video about this once it’s done.

That’s it for this week. Next week I’ll give a brief introduction to scene streaming support, including some design considerations and usage instructions