Simple DirectX animation: moving the box up and down
Last updated: 17-06-2006
Project: Game Programming with DirectX 9
Prerequisites: Completion of all the preceding tutorials in this project is required.
Downloads: DirectXBoxUpAndDown.zip
In this version of our application we will create our first DirectX animation by moving the box up and down on the screen. The source code that comes with this tutorial (see Downloads section above) extends the previous solution. To see all the tutorials that belong to this project click on the project name above.
First of all we modify the width and height of the main window to make it larger:
const int    MAIN_WINDOW_WIDTH  = 640,
            MAIN_WINDOW_HEIGHT = 480;
We then define additional constants to hold the box's movement boundaries:
const float    MAX_BOX_Y = 3.0f,
            MIN_BOX_Y = -4.0f;
As you probably understand from the names of these constants our box will move on Y axis. In the globals section we define the following global variable:
float timeDelta = 0.0f;
The timeDelta can be better understood as the "amount of movement". In other words how much our box will move in each frame. It is initialized here to 0. We will return to it later when we discuss the message loop in the WinMain() method.
Lets examine the modified drawScene() method provided bellow:
void drawScene(){     
    directXDevice->Clear(0, NULL, D3DCLEAR_TARGET, 
    0x00000000, 1.0f, 0);  // 0x00000000 = black
    directXDevice->BeginScene();
    // begin scene

    //
    // draw your objects here
    //
    

    static float y = 0.0f;
    static D3DXVECTOR3 direction = D3DXVECTOR3(0.0f, 0.0f, 0.0f);
    D3DXVECTOR3 vectorA, vectorB, newPosition;
    D3DXMATRIX matrix;

    vectorA = D3DXVECTOR3(0, y, 0);

    if(y < MIN_BOX_Y || (direction.y <=0 && y <= MAX_BOX_Y)){ 
        y += timeDelta; // move it up
    }
    else {    
        y -= timeDelta; // move it down
    }
    
    vectorB = D3DXVECTOR3(0, y, 0); 
    
        direction = vectorA - vectorB;
    D3DXVec3Normalize(&direction, &direction);
    newPosition = vectorA + (direction * timeDelta);

    D3DXMatrixTranslation(&matrix, 0, y, 0);
    directXDevice->SetTransform(D3DTS_WORLD, &matrix);


    // draw the object using the previously created world matrix.
    meshBox->DrawSubset(0); // box has only 1 subset (AttribId = 0)


    // end scene
    directXDevice->EndScene();
    directXDevice->Present(NULL, NULL, NULL, NULL);
}

As you can see we did add the static definition of y variable to hold the box's y coordinate between method calls and the static definition of a direction vector. The direction vector is going to change while box is moving up and down on the screen.
We need vectorA and vectorB to hold the departure position and the destination position of the box respectively and a newPosition vector to store the results of vector manipulations.
In order to understand the condition statement you should recall your knowledge of Linear Algebra. Box is moving up if its y coordinate is less than the minimum allowed, for example -4.2. It also moves up if its y coordinate is less or equal to the maximum allowed (for example 2.8) and in the same time if the value of direction.y is less or equal to 0. This last point is usually difficult to understand but the vector calculation behind is very simple.
For example when our box moves from A to B, vector A is defined as (0, 2, 0) and vector B is defined as (0, 3, 0) then direction vector (A - B) is (0, -1, 0) giving as a negative y direction value. This is obviously a good reason to move the box up.
As you can see in all the other cases our box will move down.
After subtracting vectorB from vectorA to calculate direction vector we have to normalize it. Then we calculate the new vector position and perform matrix transformation. Translated matrix is stored in the matrix variable. After matrix has been transformed we inform the directXDevice about the transformation by calling the SetTransform() method and passing the D3DTS_WORLD constant and the matrix as parameters. After that we draw the box by calling the DrawSubset(0) method of the meshBox object. We pass 0 because our box has only 1 subset to render.
Inside the WinMain() method the following code was modified:
// Message loop with timeDelta
static float lastTime = (float)timeGetTime(); 
while(msg.message != WM_QUIT){
    if(::PeekMessage(&msg, 0, 0, 0, PM_REMOVE)){
        ::TranslateMessage(&msg);
        ::DispatchMessage(&msg);
    }
    else{    
        float currTime  = (float)timeGetTime();
        timeDelta = (currTime - lastTime)*0.001f;
        drawScene();
        lastTime = currTime;
    }
}
Notice that inside the message loop we now calculate the difference between current time and the previous time. The previous time is stored in a static lastTime variable so it will preserve its value between the method calls. The timeDelta represents this difference in time and is used in our application to calculate the "amount of movement" of any given object on a screen between the animation frames.
In the next tutorial we show how to control box movements from a keyboard, how to create a viewport and a simple HUD for our application.