Tutorial

The tutorial goes through all the steps in a making Kyra application, starting with the tool chain and going through the C++ code to animate a mage flying across the screen on a magic carpet.

You will need the source download of Kyra, and either the gcc (presumably Linux) or Visual Studio compiler. Go through the Build step first to build Kyra, and run the Demo to make sure everything is working.

The tutorial is provided complete. So if you are following through these steps (a good idea) we'll be overwriting existing files in the tutorial1 directory. You may want to copy these files to a backup directory, or you can unzip new files if something goes wrong.

Our Mage will fly across the screen from right to left. She is sitting on a Magic Carpet, and throws a spell every now and then. The pieces, in more detail:

Mage. The mage is a single animation from, of a woman sitting. There is the idea that different mages could be placed on the same carpet, so the Mage is provided as a separate graphic, not rendered with carpet.

Carpet: The carpet has 8 frames of animation of the carpet rippling along.

Spell: The spells we be created from a simple white circle that we will doctor at run-time.

Step 1: Art

The art comes from some mystical place, or hopefully an artist. In this case I rendered the Mage with Poser 4, the Carpet with Amorphium Pro, and the composited and cleaned the whole thing up with Photoshop. It has been saved as a 8-bit GIF file, tutorial1.tga. Creating art for a project is a huge undertaking, than I'm intentionally skimping over here.

Step 2: The Sprite Editor

The next step is to allow Kyra to import the graphics as Sprites. The arduous process of writing XML files to do this is done for you by the Sprite Editor. Assuming you are in the tutorial1 directory, execute the Sprite Editor. The Sprite Editor should be run from the directory where you want to edit. The input and output files will both go to this directory.

Windows: ..\spriteed\Release\krspriteed (use the Debug directory, if that is the version you built)

Linux: ../spriteed/krspriteed

Now, you have an image file (tutorial1.tga) and need to create the XML file to describe it (tutorial1.xml). The "image" command does this. However, you do need parameters. tutorial1 is a 8-bit file, which means it has no alpha (transparency) channel. IF it did have an alpha channel, then Kyra would see all the transparent pixels as...transparent. Background. Not something that can be drawn. However, since it doesn't, the editor needs to know which pixels are the background. There are 2 ways to do this:

  1. Specify a color key by its color. A color key is the pixel color that will become the background color. The syntax for this is 'image tutorial1.tga #000000' since our background color is black.
  2. Specify a color key by its location. Valid locations are UpperLeft, LowerLeft, UpperRight, and LowerRight.

Note: All the editor commands are case sensitive.

Note: You can specify multiple color keys.

It is usually easier to specify a color by location. So type 'image tutorial1.tga LowerLeft'.

Note: The editor supports tab command completion. i - tab will produce 'image'

You should now see a bunch of carpets, a woman sitting, and a white circle on a checkerboard pattern. If you don't see the checkerboard, but instead a black background, then you don't have a color key. Back up and try again.

We now define the 3 sprites that will be used. We'll start with the simplest to most involved.

Note: To get a better view at any time, press the keypad + to zoom in, and keypad - to zoom out. When in view mode (the main mode you are in now, accessed when you load an image or press F2) you can also right click to zoom in to a particular point.

The Particle

The particle sprite will be used for magic effects. Sprites have a name, and contain actions. Actions have a name and contain frames. The Particle is a one frame, one action sprite. To create the sprite type 'sprite PARTICLE'. The info box reads "PARTICLE, NONE, Creating new action". We aren't going to create an action -- we'll just use the default, 'NONE', so we'll just create a frame. Click and drag a box that encompasses the white circle. Extra space in the bounding box is fine; the background is ignored by Kyra.

You should see a white box around the particle with the number 0 in the upper left. If you click in or on the box, info should read "PARTICLE, NONE, 0 of 1". Which says that frame 0 of a 1 frame series is selected.

One more thing: the red cross in the upper left of the bounding box is the hotspot. The local origin of the frame. Ctrl-click to put the red-cross in the center of the particle. The red cross should now be in the center of the white circle.

That's it for the particle!

The Mage

The Mage, like the particle, is a one action one frame sprite and created the same way. Create the sprite 'sprite MAGE' and draw a box around the sitting woman, just like before. Put the hotspot on her head.

Type 'save' to save your work. It will choose "tutorial1.xml" for you, based on the image file name.

Note: The tutorial will never use the 'action' field. Actions are very powerful. In a real application, there would be multiple actions for the mage: SITTING and CASTING. Since these actions could happen in at least 4 directions, NORTH, SOUTH, EAST, and WEST, you would use combined actions: SITTING.NORTH, SITTING.SOUTH, CASTING.EAST, etc.

The Carpet

The carpet has 8 frames. Frame 0 is the upper left, frame 1 beneath it, and frame 4 is the upper right. Start by creating the sprite: 'sprite CARPET'. You can then click and drag to define each frame. The frame number will be incremented for you. If you make a mistake, shift-delete deletes the current frame.

Hotspots should go in the center of the white diamond on each carpet.

And be sure to save your work!

Alignment

Alignment is a big thing for, say, walking sprites, where the position of each frame relative to the previous is very exact. When something walks, its feet need to stay on the ground and not slide. So each frame is carefully positioned relative to the previous. (bem.xml is a fine example of this.)

For a magic carpet, not so much. Switch to the align screen by pressing F3.

A bit on the interface. You should see a column of numbers, any line that reads something like

0-->1 dx=-3 dy=0

What this means is that from frame 0 to 1 the sprites moves-3 x pixels and 0 y pixels. In the engine, you can either move the sprite frame by frame (in which case alignment doesn't matter) or use the Step() function. When a sprite Steps, its frame count goes up by one and its hotspot is moved by the specified delta.

When looking at the alignment screen, you can see the current carpet, and the previous carpet dimmed out simultaneously. Page up and down changes frames, the arrow keys adjust dx and dy.

For our carpet, simply set all the dx values to -3.

The Movie Screen

For a sprite that has been aligned, the tool will animate it for you. Press F4 to see the carpet cruise across the screen. Then hit F2 to go back to view and save your work.

Type 'exit' (after saving, of course) to close the editor.

Step 3: The Encoder

The encoder takes XML definition files (with their associated images) and encodes them into .dat binary files used directly by the engine. It also creates a header file for your use.

From the command line,

Windows: ..\encoder\Release\krencoder -pTUT1_ -w tutorial1.dat tutorial1.xml

Linux: ../encoder/krencoder -pTUT1_ -w tutorial1.dat tutorial1.xml

Note: It is common to have multiple xml files in one dat file.

The -pTUT1_ option (odd looking, true) appends a prefix before each entry in the header file. So instead of just writing MAGE to the header, it will write TUT1_MAGE which is handy for not polluting your namespace. -w tells the encoder to wait for a space bar between screens.

When you hit return, you should see all the sprites you just defined in blue boxes on the screen. Hit space bar to move on. Check the disk: you should see a new .dat and .h file.

Step 4: Code!

We've set up the art, the sprites, and defined the objects. Now its time to write some code! The code is organized into a series of files: code_a.cpp, code_b.cpp, etc. that reflects the steps in this section of the tutorial. There is only one makefile and dsp file provided. You should change the source file name to switch between versions of the code.

Code A : Framework

This is a simple SDL framework. It creates a surface, and creates a timer to hit our main message loop every TIMER_INTERVAL milliseconds. The callback posts to the message loop in order to avoid threading problems. Pressing any key exits the program.

The only Kyra code is:

#include "../engine/kyra.h" 

Which includes all the kyra you should ever need.

KrEngine* engine = new KrEngine( screen );
engine->Draw(); 

Creates the Kyra engine, and draws nothing to the screen, since no objects have been put in the engine.

Every timer event, we

case SDL_TIMER_EVENT: 
{ 
   engine->Draw(); 
} 
break; 

Which calls the draw function. Again, nothing but black screen. And:

 delete engine; 

cleans up just before we call SDL_Quit().

If you want to convince yourself there is an engine there at all, add the line:

KrRGBA yellow; 
yellow.Set( 128, 128, 0 ); 
engine->FillBackground( &yellow ); 

Just after the line that creates the engine.

Code B: Animation

Everything from this point out is flagged with the code_b (or c, etc.) comment, so you can find it. The code should be looked at with the comments.

code_b Include the generated header

This allows us to refer to Sprite Resources by ID rather than name. There's no real reason, in a simple example, to go one way or the other. We'll use IDs hear to demonstrate them. The "tutorial.h" file was created by the encoder.

code_b Load the dat file

Resources live in ResourceVaults. When we defined sprites in the editor above, we were really defining SpriteResources. You can have many instances of a resource (many Mages, for example) but there is only one SpriteResource.

Suffice to say, before we can create anything, we need Resources in our ResourceVault. To get Resources in our ResourceVault, we load the dat file, with 'engine->Vault()->LoadDatFile( "tutorial1.dat" )'.

code_b Get the CARPET resource

In this step, we pull the CARPET resource out of the vault. It's ID is actually TUT1_CARPET because we added the prefix in the encoding step.

code_b Create the carpet sprite and add it to the tree

Resources are not displayed directly on the screen. Images are. So we create a Sprite (child of Image) from the SpriteResource. We then set its position 'SetPos' to the middle right side of the screen.

There is another step. The Engine also contains an ImageTree, a depth sorted container where the Sprites (and other Images) are held. In order for the carpet to appear on the screen, we must add it to the Tree with the 'AddNode( 0, carpet )' call. The 0 for first parameter adds it as a child of the Root node. More on that later.

Code_b Move the carpet

Since the carpet has been aligned, it can be moved correctly each frame with the 'DoStep' function. So we do! An if case is added to detect going over the left edge of the screen, and Congratulations! Animation is yours!

Code C: Add the Mage

The carpet looks a little strange and lonely. (Well, it looks strange because it has an extra twist and I should re-render...but it will do.) So let's add the mage. The initial code_c code should look familiar: pull out the resource, create the sprite.

But where to add it?

code_c Add the Mage as a child of the carpet

We wish the mage to travel with the carpet, and sort on top. The Tree is discussed fully in the Engine documentation, but we'll note a few important things here.

  • The parent of a Sprites (in terms of inheritance) is an Image. The parent of an Image is a ImNode. ImNodes can contain other ImNodes. An ImNode that is contained by another composites position and color transformation from its owner. So if the Mage was the child (in terms of containment) of the Carpet, they would move as one object.
  • The nodes contained by an ImNode (the children, by containment) are drawn on top of the parent.

So if we make the Mage a child of the carpet, it will be drawn on top and move with the carpet. Perfect.

Note: A perfect use for the alpha channel (or an alpha transformation of an opaque sprite) would be to give the Mage a shadow. That would make it look more attached to the carpet.

Code D: Spell Effects

Largely, I'll let the code and comments speak for themselves, except for a few points. Note that the code_d stuff uses a circular list template class and generalized random number generator, so don't let that throw you. STL would work just as well.

Code_d Create the particle

This is a perfect example of why there are resources. We create bunches of sprites from one resource.

Code_d Remove the sprite from the Tree

An example of deleting the sprite from the Tree. The Engine will clean up memory.

Code_d Transform the color

Without color transformation, it would be silly white balls instead of silly colored spells. A color transform is randomly generated and applied to the PARTICLE sprites. The alpha channel is used to fade the balls out as they move across the screen.

By alpha blending the source image of the white ball, a much better particle effect can be generated. The alpha channel is used in the BEM demo.

Each color transform has a multiplier and addition component.

colorNew = color * multiplier / 255 + addition / 255

By setting all the addition components to 0, and assigning random multipliers 'colorXForm.SetRed( random.Rand( 256 ), 0 )' to each of the color channels, we effectively randomly generate a color out of the RGB color cube.

That is the basics! Welcome to Kyra. It's worth checking out the rest of the general HTML and API documentation. And of course you can ask questions and get tips at the bulletin board. Or contact me with questions or bugs.

 

Good luck, Lee