# Working With Animations

This section looks at some of the example code in jsanimation.c, explaining the following:

- Loading an Animation
- Playing the Animation

## Loading an Animation

The Lib3DO functions `LoadAnim()` loads an animation, as shown in the code fragment in the example below, which is part of the `Initialize()` function.

Example 1: Loading an animation.

``

    if ( ( gExplosionAnim = LoadAnim("jsdata/art/boom.anim",
        MEMTYPE_CEL )) == 0)
        {
        PRT(("Can't load the explosion animation\n"));
        goto DONE;
        }
    UnifyAnimation(gExplosionAnim);
    gExplosionCCB = GetAnimCel(gExplosionAnim, 0);
    LAST_CEL(gExplosionCCB);

`LoadAnim()` expects the name of an animation file in 3DO file format, a buffer, and a pointer to an `ANIM` structure that is filled by `LoadAnim()`. The `ANIM` structure has as one of its fields a pointer to an array of `AnimFrame` structures. Together, the two structures contain all the information you need to manipulate the animation.

Example 2: The AnimFrame and ANIM structures.

``

    typedef struct tag_AnimFrame
        {
        CCB *af_CCB;                        /*Pointer to CCB for this frame*/
        char *af_PLUT;                        /*Pointer to PLUT for this frame*/
        char *af_pix;                        /*Pointer to pixels for this frame*/
        int32        reserved;
        } AnimFrame;

    typedef struct tag_ANIM
        {
        long num_Frames;                    /*max number of PDATs or CCBs in file*/
        frac16 cur_Frame;                    /*allow fract values for smooth speed*/
        long num_Alloced_Frames;
        AnimFrame *pentries;
        } ANIM;

## Playing the Animation

In the simplest case, you can loop through calls to `GetAnimCel()` to play the animation. `GetAnimCel()` takes an `ANIM` structure created by `LoadAnim()` and a frame increment as arguments. It returns a pointer to the CCB of the next cel in an animation sequence and adds frameIncrement to the current frame counter within the ANIM. It does not draw the cel.

The example below shows a code fragment from the `TargetAction()` function in jsanimation.c which retrieves and draws the animation. The FRAME_INCREMENT macro is defined at the beginning of the program.

Example 3: Retrieving and drawing an animation.

``

    /*
        Animate the UFO: If it's still exploding, play the explosion's next frame,
        otherwise display the UFO (after a nominal post-explosion delay).
    */
    {
        if (gBoomCount)
        {
            gBoomCount--;
            if (gBoomCount)
            {
                GetAnimCel(gExplosionAnim, FRAME_INCREMENT);
                DrawCels(gScreenContext->sc_BitmapItems
                                [gScreenContext->sc_curScreen], gExplosionCCB);
            }
            else
            {
                gExplosionAnim->cur_Frame = 0;                                    /* Reset animation to first frame */
                gPostBoomDelay = gExplosionAnim->num_Frames * 5;
                                                /* Wait awhile before showing the target */
            }
        }
        else
        {
            if (gPostBoomDelay)
                gPostBoomDelay--;
            if (!gPostBoomDelay)
                DrawCels(gScreenContext->sc_BitmapItems
                                                [gScreenContext->sc_curScreen], aTarget);
        }
    }

The actual switching of buffers is done by the `main()` function, which also displays the image, handles control pad input-discussed in "Getting User Input"-and handles the drawing of the UFO and explosion.

Example 4: Buffer switching and screen display.

``

    while ( HandleControlPad() >= 0 )
        {
            /* Draw the background image */
            DrawImage(gScreenContext->sc_Screens [gScreenContext->
                        sc_curScreen], gBackgroundImage, gScreenContext);

            /* Handle the drawing of the UFO cel and the explosion */
            TargetAction(gUFO_CCB);

            /*
                Display the current screen.

                DisplayScreen waits for the next vertical blank, then
                tells the display hardware to use the specified screen
                as the display buffer. The hardware continues showing
                this buffer on the TV every frame until another call
                to DisplayScreen specifies a different buffer.
            */
            DisplayScreen(gScreenContext->sc_Screens[gScreenContext->
                        sc_curScreen], 0);

            /* Toggle the current screen */
            gScreenContext->sc_curScreen = 1 - gScreenContext->
                        sc_curScreen;

`

        }

`