Putting Together a Full Game(10)

Putting Together a Full Game(10)

 

Using State-Based Processing

I developed the sample game to use state-based processing in order to effectively
use the application class's processing structure. The game uses these four states:

■ Main menu state. When executed, the game displays a main menu giving the
player the option to start a new game, load a game, return to or save a game
in progress, or to quit the game.

■ In-game state. This state is used most often because it takes care of updating
and rendering each frame of the game.

■ Character status window state. Whenever the player right-clicks during gameplay,
he accesses the character status window. Here, the player can use, equip,
or unequip items just by clicking them, as well as check on the character’s
statistics and known spells.

Putting Together a Full Game(10)_第1张图片

■ Barter window state. When the player talks to the villager, the barter window
opens in order to buy items. Click items to buy or press Esc or the right
mouse button to exit.

Putting Together a Full Game(10)_第2张图片

You use a state manager object to control the processing of these four states.

 

menu_frame:

 You use the menu_frame function to display the main menu, which, in all its glory, has
 a spinning texture-mapped polygon overlaid with the main menu options. The purpose
 of the menu_frame function is to track which option is being selected and to handle
 the appropriate functions.

void  menu_frame( void * data,  long  purpose)
{
    
static   const  sMenuVertex verts[] = 
    {
        { -100.0f,  100.0f, 1.0f, 0.0f, 0.0f },
        {  100.0f,  100.0f, 1.0f, 1.0f, 0.0f },
        { -100.0f, -100.0f, 1.0f, 0.0f, 1.0f },
        {  100.0f, -100.0f, 1.0f, 1.0f, 1.0f }
    };
    
    
static  IDirect3DVertexBuffer9*  menu_vb;
    
static  IDirect3DTexture9*       menu_texture;
    
static  IDirect3DTexture9*       menu_select;
    
static  ID3DXFont*               title_font;
    
static  cCamera                  menu_cam;
    
static  cWorldPos                menu_pos;
    
    cApp* app = (cApp*) data;

    
if (purpose == INIT_PURPOSE)  // initialize menu related data
    {   
        
// create and set the menu vertices
        create_vertex_buffer(&menu_vb, array_num(verts),  sizeof (sMenuVertex), MENU_FVF);
        fill_in_vertex_buffer(menu_vb, 0, array_num(verts), verts);

        load_texture_from_file(&menu_texture, "..\\Data\\MenuBD.bmp", 0, D3DFMT_UNKNOWN);
        load_texture_from_file(&menu_select,  "..\\Data\\Select.bmp", 0, D3DFMT_UNKNOWN);

        create_font(&title_font, "Consolas", 48, 
false false );
        menu_cam.point(0.0f, 0.0f, -150.0f, 0.0f, 0.0f, 0.0f);
    }
    
else   if (purpose == SHUTDOWN_PURPOSE)     // shutdown resources used in menu
    {
        release_com(menu_vb);
        release_com(menu_texture);
        release_com(menu_select);
        release_com(title_font);
    }
    
else      // process a frame of menu
    {
        
// exit game or return to game if ESC pressed
         if (app->m_keyboard.get_key_state(KEY_ESC))
        {
            app->m_keyboard.m_locks[KEY_ESC] = 
true ;
            app->m_keyboard.set_key_state(KEY_ESC, 
false );

            app->m_state_manager.pop(app);
            
return ;
        }        

        
// see which option was selected if mouse button pressed
         if (app->m_mouse.get_button_state(MOUSE_LBUTTON))
        {
            
// lock the mouse button and clear button state
            app->m_mouse.m_locks[MOUSE_LBUTTON] =  true ;
            app->m_mouse.set_button_state(MOUSE_LBUTTON, 
false );

            
// determine which, if any selection.

            
long  mouse_start = app->m_mouse.get_y_pos() - MAIN_MENU_TOP;

            
if (mouse_start >= 0)
            {
                
long  hit_index = mouse_start / MAIN_MENU_HEIGHT;
                
                app->m_state_manager.pop(app);  
// pop the menu state

                // determine what to do based on selection
                 switch (hit_index)
                {
                
case  NEW_GAME:
                    app->m_state_manager.pop_all(app);

                    app->m_game_chars.free();
                    app->m_game_spells.free();
                    app->m_game_script.reset_data();
                    
                    app->m_game_chars.add_char(ID_PLAYER, 0, CHAR_PC, CHAR_STAND, -100.0f, 0.0f, 50.0f, 3.14f);
                    g_player = app->m_game_chars.get_char(ID_PLAYER);

                    app->m_teleport_map = -1;

                    app->m_state_manager.push(game_frame, app);

                    
// start new game and let script process as startup
                    app->load_level(1);

                    
break ;

                
case  RETURN_TO_GAME:
                    app->m_state_manager.push(game_frame, app);
                    
break ;

                
case  LOAD_GAME:
                    app->m_state_manager.pop_all(app);

                    app->m_game_chars.free();
                    app->m_game_spells.free();

                    app->m_game_chars.add_char(ID_PLAYER, 0, CHAR_PC, CHAR_STAND, -100.0f, 0.0f, 50.0f, 3.14f);
                    g_player = app->m_game_chars.get_char(ID_PLAYER);

                    
// load character's stats and inventory
                    app->m_game_chars.load_char(ID_PLAYER, "..\\Data\\Char.cs");
                    g_player->char_ics->load("..\\Data\\Char.ci");

                    
if (g_player->char_def.weapon != -1)
                        app->m_game_chars.equip(g_player, g_player->char_def.weapon, WEAPON, 
true );

                    g_player->health_points = g_player->char_def.health_points;
                    g_player->mana_points   = g_player->char_def.mana_points;

                    app->m_game_script.load("..\\Data\\Script.sav");
                    app->m_teleport_map = -1;

                    app->m_state_manager.push(game_frame, app);

                    app->m_game_chars.move_char(ID_PLAYER, 100.0f, 0.0f, -100.0f);
                    app->load_level(1);     
// start in town

                    
break ;

                
case  SAVE_GAME:
                    app->m_game_script.save("..\\Data\\Script.sav");

                    
// save character's stats and inventory
                    app->m_game_chars.save_char(ID_PLAYER, "..\\Data\\Char.cs");
                    g_player->char_ics->save("..\\Data\\Char.ci");

                    
break ;

                
case  QUIT_GAME:
                    app->m_state_manager.pop_all(app);
                    
break ;
                }

                
return ;
            }
        }   
// [end] if(app->m_mouse.get_button_state(MOUSE_LBUTTON))

        set_display_camera(&menu_cam);
        
        menu_pos.rotate(0.0f, 0.0f, timeGetTime() / 4000.0f);   
// rotate backdrop

        // render menu backdrop and all menus

        begin_display_scene();

        disable_zbuffer();
        set_display_world(&menu_pos);
        g_d3d_device->SetTexture(0, menu_texture);
        render_vertex_buffer(menu_vb, 0, 2, D3DPT_TRIANGLESTRIP);

        
// draw the game's title
        draw_font(title_font, g_title_name, 0, 16, CLIENT_WIDTH, 0, COLOR_LIGHT_YELLOW, DT_CENTER);

        
// select option based on mouse position

        
long  mouse_start = app->m_mouse.get_y_pos() - MAIN_MENU_TOP;

        
if (mouse_start >= 0)
        {
            
long  hit_index = mouse_start / MAIN_MENU_HEIGHT;

            
if ( hit_index == NEW_GAME ||
               (hit_index == RETURN_TO_GAME && (g_menu_options & MENU_BACK)) ||
               (hit_index == LOAD_GAME && (g_menu_options & MENU_LOAD)) ||
               (hit_index == SAVE_GAME && (g_menu_options & MENU_SAVE)) ||
               (hit_index == QUIT_GAME))
            {
                begin_display_sprite();

                RECT rect;
                calculate_texture_rect(menu_select, 0, 0, 0, 0, &rect);

                
long  dest_y = hit_index * MAIN_MENU_HEIGHT + MAIN_MENU_TOP;
                draw_texture(g_d3d_sprite, menu_select, &rect, 192, dest_y, 1.0f, 1.0f, COLOR_WHITE);

                end_display_sprite();
            }
        }

        
// draw enabled options 
        
        draw_font(app->m_font, "New Game", 0, 150, CLIENT_WIDTH, 0, COLOR_LIGHT_YELLOW, DT_CENTER);

        
if (g_menu_options & MENU_BACK)
            draw_font(app->m_font, "Back to Game", 0, 214, CLIENT_WIDTH, 0, COLOR_LIGHT_YELLOW, DT_CENTER);

        
if (g_menu_options & MENU_LOAD)
            draw_font(app->m_font, "Load Game", 0, 278, CLIENT_WIDTH, 0, COLOR_LIGHT_YELLOW, DT_CENTER);

        
if (g_menu_options & MENU_SAVE)
            draw_font(app->m_font, "Save Game", 0, 342, CLIENT_WIDTH, 0, COLOR_LIGHT_YELLOW, DT_CENTER);
        
        draw_font(app->m_font, "Quit", 0, 410, CLIENT_WIDTH, 0, COLOR_LIGHT_YELLOW, DT_CENTER);

        end_display_scene();

        present_display();
    }
}

你可能感兴趣的:(Putting Together a Full Game(10))