• <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>

            天行健 君子當(dāng)自強(qiáng)而不息

            Getting Online with Multiplayer Gaming(14)

             

            Updating Players

            In order to synchronize itself with clients, the server needs to maintain a simplified
            version of the game running internally. This version of the game doesn’t include
            graphics, sound, or any other fancy features; it only needs to track player’s actions.

            The server tracks those actions by updating the player’s actions every 33ms (just as
            the client application will do). Those actions include walking and waiting for other
            specific states to clear (such as sword swinging and being hurt).

            The cApp::update_players function is responsible for updating all players:

            void cApp::update_players()
            {
                sStateChangeMsg change_msg;

                
            // loop through all players
                for(int i = 0; i < MAX_PLAYERS; i++)
                {
                    
            // only update connected players
                    if(! m_players[i].connected)
                        
            continue;

                    
            long elapsed = timeGetTime() - m_players[i].last_update_time;

                    
            if(m_players[i].last_state == STATE_MOVE)
                    {
                        
            // calculate amount of movement by time passed
                        float speed  = elapsed / 1000.0f * m_players[i].speed;
                        
            float x_move = sin(m_players[i].direction) * speed;
                        
            float z_move = cos(m_players[i].direction) * speed;

                        
            // check for movement collision - can not walk past anything blocking path
                        if(check_intersect(&m_level_mesh,
                            m_players[i].x_pos,          m_players[i].y_pos + 16.0f, m_players[i].z_pos,
                            m_players[i].x_pos + x_move, m_players[i].y_pos + 16.0f, m_players[i].z_pos + z_move))
                        {
                            x_move = z_move = 0.0f;
                        }

                        
            // update player coordinates
                        m_players[i].x_pos += x_move;
                        m_players[i].y_pos  = 0.0f;     
            // stay on ground
                        m_players[i].z_pos += z_move;

                        m_players[i].last_update_time = timeGetTime();
                    }
                    
            else if(m_players[i].last_state == STATE_SWING && elapsed > 1000)   // clear swing status after 1 second
                    {
                        m_players[i].last_state = STATE_IDLE;

                        
            // send network message to player to clear
                        change_msg.header.type      = MSG_STATE_CHANGE;
                        change_msg.header.size      = 
            sizeof(sStateChangeMsg);
                        change_msg.header.player_id = m_players[i].player_id;
                        change_msg.x_pos            = m_players[i].x_pos;
                        change_msg.y_pos            = m_players[i].y_pos;
                        change_msg.z_pos            = m_players[i].z_pos;
                        change_msg.direction        = m_players[i].direction;
                        change_msg.speed            = m_players[i].speed;
                        change_msg.state            = m_players[i].last_state;

                        send_network_msg(&change_msg, DPNSEND_NOLOOPBACK, ALL_CLIENT_PLAYERS);
                    }
                    
            else if(m_players[i].last_state == STATE_HURT && elapsed > 1000)    // clear hurt status after 1 second
                    {
                        m_players[i].last_state = STATE_IDLE;

                        
            // send network message to player to clear
                        change_msg.header.type      = MSG_STATE_CHANGE;
                        change_msg.header.size      = 
            sizeof(sStateChangeMsg);
                        change_msg.header.player_id = m_players[i].player_id;
                        change_msg.x_pos            = m_players[i].x_pos;
                        change_msg.y_pos            = m_players[i].y_pos;
                        change_msg.z_pos            = m_players[i].z_pos;
                        change_msg.direction        = m_players[i].direction;
                        change_msg.speed            = m_players[i].speed;
                        change_msg.state            = m_players[i].last_state;

                        send_network_msg(&change_msg, DPNSEND_NOLOOPBACK, ALL_CLIENT_PLAYERS);
                    }
                }
            }

            As the server scans the list of players, it determines which players are connected
            and calculates the time since the last server update for all connected players. Next,
            if a player’s state is set to STATE_MOVE, the elapsed time is used to move the player.

            Next, the server deals with the STATE_SWING and STATE_HURT states. Those states are
            cleared only after one second has passed (as determined by the elapsed time).

            Surprisingly, that’s it for cApp::update_players! Remember that the update_players function
            is called every 33ms, so keeping the function quick and to the point is crucial.
            Once all players are updated, you need to notify other players.

             

            Updating the Network Clients

            Throughout earlier sections in this chapter, I mentioned periodic server updates
            that are sent to the client in order to synchronize game-play. That’s the purpose of
            the cApp::update_network function. The update_network function is quick and to the
            point, sending out the current state of all connected clients every 100ms.

            void cApp::update_network()
            {
                
            // send all player updates
                for(long i = 0; i < MAX_PLAYERS; i++)
                {
                    
            if(m_players[i].connected)  // only send data about connected players
                    {
                        sStateChangeMsg change_msg;

                        change_msg.header.type      = MSG_STATE_CHANGE;
                        change_msg.header.size      = 
            sizeof(sStateChangeMsg);
                        change_msg.header.player_id = m_players[i].player_id;
                        change_msg.x_pos            = m_players[i].x_pos;
                        change_msg.y_pos            = m_players[i].y_pos;
                        change_msg.z_pos            = m_players[i].z_pos;
                        change_msg.direction        = m_players[i].direction;
                        change_msg.speed            = m_players[i].speed;
                        change_msg.state            = m_players[i].last_state;
                        change_msg.latency          = m_players[i].latency;

                        send_network_msg(&change_msg, DPNSEND_NOLOOPBACK, ALL_CLIENT_PLAYERS);
                    }
                }
            }

             

            Calculating Latency

            The server periodically calculates the time it takes a message to be received from a
            client and uses the latency in the timed calculations to update clients, all of which
            is crucial to maintaining the synchronization of the game. The function that calculates
            the latency is update_latency, and it is called every 10 seconds from the main
            application loop (cApp::frame).

            void cApp::update_latency()
            {
                
            // go through all players
                for(long i = 0; i < MAX_PLAYERS; i++)
                {
                    
            if(m_players[i].connected)  // only process connected players
                    {
                        DPN_CONNECTION_INFO connect_info;

                        
            // request player connection settings
                        if(SUCCEEDED(m_server.get_server()->GetConnectionInfo(m_players[i].player_id, &connect_info, 0)))
                        {
                            m_players[i].latency = connect_info.dwRoundTripLatencyMS / 2;

                            
            // bounds latency to 1 second
                            if(m_players[i].latency > 1000)
                                m_players[i].latency = 1000;
                        }
                        
            else
                            m_players[i].latency = 0;
                    }
                }
            }

            To calculate the latency, the server queries DirectPlay for the connection statistics
            via the IDirectPlay8Server::GetConnectInfo function. That function call takes a structure
            (DPN_CONNECTION_INFO) as an argument, and inside the structure is a variable that
            represents the roundtrip latency time in milliseconds. The server divides that
            latency value in half and stores it in each player’s data structure.

             

            Other function:

            int WINAPI WinMain(HINSTANCE inst, HINSTANCE, LPSTR cmd_line, int cmd_show)
            {
                
            const char* class_name = "ServerClass";

                WNDCLASSEX win_class;

                
            // create window class and register it

                win_class.cbSize        = 
            sizeof(win_class);
                win_class.style         = CS_CLASSDC;
                win_class.lpfnWndProc   = window_proc;
                win_class.cbClsExtra    = 0;
                win_class.cbWndExtra    = 0;
                win_class.hInstance     = inst;
                win_class.hIcon         = LoadIcon(NULL, IDI_APPLICATION);
                win_class.hCursor       = LoadCursor(NULL, IDC_ARROW);
                win_class.hbrBackground = (HBRUSH) GetStockObject(LTGRAY_BRUSH);;
                win_class.lpszMenuName  = NULL;
                win_class.lpszClassName = class_name;
                win_class.hIconSm       = LoadIcon(NULL, IDI_APPLICATION);

                
            if(! RegisterClassEx(&win_class))
                    
            return false;

                DWORD style = WS_BORDER | WS_CAPTION | WS_MINIMIZEBOX | WS_SYSMENU;

                DWORD pos_x = (get_screen_width()  - CLIENT_WIDTH) / 2;
                DWORD pos_y = (get_screen_height() - CLIENT_HEIGHT) / 4;
                
                g_hwnd = CreateWindow(class_name, "Network Server Demo", style, pos_x, pos_y, 
                                      CLIENT_WIDTH, CLIENT_HEIGHT, NULL, NULL, inst, NULL);

                
            if(g_hwnd == NULL)
                    
            return -1;

                ShowWindow(g_hwnd, SW_NORMAL);
                UpdateWindow(g_hwnd);

                resize_window(g_hwnd, CLIENT_WIDTH, CLIENT_HEIGHT);

                cApp app;
                app.run();

                
            return 0;
            }

            ///////////////////////////////////////////////////////////////////////////////////////

            BOOL CALLBACK config_dlg_proc(HWND dlg, UINT msg, WPARAM wParam, LPARAM lParam)
            {
                
            static HWND adapter_wnd;

                
            switch(msg)
                {
                
            case WM_INITDIALOG:
                    adapter_wnd = GetDlgItem(dlg, IDC_ADAPTERS);

                    
            // add adapter names to list
                    for(long i = 0; i < g_adapter->get_num_adapters(); i++)
                    {
                        
            char text[256];
                        g_adapter->get_name(i, text);

                        insert_string_to_combo(adapter_wnd, i, text);
                    }

                    
            // select first adapter in list
                    set_combo_cur_sel(adapter_wnd, 0);

                    
            return TRUE;

                
            case WM_COMMAND:
                    
            switch(LOWORD(wParam))
                    {
                    
            case IDC_OK:
                        {
                        
            int sel = (int) get_combo_cur_sel(adapter_wnd);  

                        
            // make sure an adapter was selected
                        if(sel == LB_ERR)
                            
            break;

                        g_app->set_adapter_guid(g_adapter->get_guid(sel));

                        EndDialog(dlg, TRUE);
                        
            return TRUE;
                        }

                    
            case IDC_CANCEL:
                        EndDialog(dlg, FALSE);
                        
            return TRUE;
                    }
                }

                
            return FALSE;
            }

            ///////////////////////////////////////////////////////////////////////////////////////

            bool cApp::init()
            {
                
            // select a network adapter to use (or quit if selected)
                if(! select_adapter())
                    
            return false;

                setup_app_window();

                
            // intialize the game, set display mode, load level mesh.
                if(! init_game())
                {
                    show_error_msg(
            false, "Unable to initialize game.");
                    
            return false;
                }

                
            // begin hosting the game session
                if(! host_game())
                {
                    show_error_msg(
            false, "Unable to host network server.");
                    
            return false;
                }

                
            return true;
            }

            ///////////////////////////////////////////////////////////////////////////////////////

            bool cApp::frame()
            {
                
            static DWORD player_counter  = timeGetTime();
                
            static DWORD network_counter = timeGetTime();
                
            static DWORD latency_counter = timeGetTime();

                process_queue_msg();

                
            // update players every 33ms (30 times a second)
                if(timeGetTime() > player_counter + 33)
                {
                    update_players();
                    player_counter = timeGetTime();
                }
                
                
            // send out network update every 100ms (10 times a second)
                if(timeGetTime() > network_counter + 100)
                {
                    update_network();
                    network_counter = timeGetTime();
                }

                
            // update player latency values every 10 seconds
                if(timeGetTime() > latency_counter + 10000)
                {
                    update_latency();
                    latency_counter = timeGetTime();
                }

                
            return true;
            }

            ///////////////////////////////////////////////////////////////////////////////////////

            void cApp::shutdown()
            {
                delete[] m_msgs;
                m_msgs = NULL;

                delete[] m_players;
                m_players = NULL;

                DeleteCriticalSection(&m_msg_cs);
            }
                
            ///////////////////////////////////////////////////////////////////////////////////////

            bool cApp::select_adapter()
            {
                ShowWindow(g_hwnd, SW_HIDE);    
            // hide main window
                m_adapter.init();

                
            return (bool) DialogBox(get_window_inst(), MAKEINTRESOURCE(IDD_CONFIG), g_hwnd, config_dlg_proc);
            }

            ///////////////////////////////////////////////////////////////////////////////////////

            void cApp::setup_app_window()
            {
                
            // window to hold host IP address
                m_controls[CONTROL_SERVER_IP] = CreateWindow("STATIC", "", WS_CHILD | WS_VISIBLE, 4, 4, 312, 18,
                                                             g_hwnd, NULL, get_window_inst(), NULL);

                
            // window to hold number of connected players
                m_controls[CONTROL_PLAYER_NUM] = CreateWindow("STATIC", "No Connected Players",  WS_CHILD | WS_VISIBLE,
                                                              4, 26, 312, 18, g_hwnd, NULL, get_window_inst(), NULL);

                
            // list box to display connect player's names
                m_controls[CONTROL_PLAYER_LIST] = CreateWindow("LISTBOX", "", WS_CHILD | WS_BORDER | WS_VSCROLL | WS_VISIBLE,
                                                               4, 48, 312, 154, g_hwnd, NULL, get_window_inst(), NULL);

                
            // show main window
                ShowWindow(g_hwnd, SW_SHOW);
            }

            ///////////////////////////////////////////////////////////////////////////////////////

            bool cApp::init_game()
            {
                create_display(g_hwnd, CLIENT_WIDTH, CLIENT_HEIGHT, 16, 
            truetrue);

                
            // load the level mesh for collision checking
                if(! m_level_mesh.load("..\\Data\\ArenaCM.x", "..\\Data\\"))
                    
            return false;

                m_msgs = 
            new sMsg[MAX_MESSAGES];
                m_msg_head = m_msg_tail = 0;

                m_players = 
            new sPlayer[MAX_PLAYERS];
                m_connected_player_num = 0;

                
            return true;
            }

            ///////////////////////////////////////////////////////////////////////////////////////

            bool cApp::host_game()
            {
                
            // configure server and begin hosting

                m_server.init();

                
            if(! m_server.host(m_adapter_guid, 9123, "RPGGAME", NULL, MAX_PLAYERS))
                    
            return false;

                
            char text[33], ip[16];

                
            // get server ip address and display in application window
                m_server.get_ip(ip, 0);
                sprintf(text, "Host IP Address: %s", ip);
                SetWindowText(m_controls[CONTROL_SERVER_IP], text);

                
            return true;
            }

            download source and solution

            posted on 2007-12-18 23:20 lovedday 閱讀(208) 評(píng)論(0)  編輯 收藏 引用


            只有注冊(cè)用戶登錄后才能發(fā)表評(píng)論。
            網(wǎng)站導(dǎo)航: 博客園   IT新聞   BlogJava   博問   Chat2DB   管理


            公告

            導(dǎo)航

            統(tǒng)計(jì)

            常用鏈接

            隨筆分類(178)

            3D游戲編程相關(guān)鏈接

            搜索

            最新評(píng)論

            精品久久久久久久久久中文字幕 | 国产综合精品久久亚洲| 精品一久久香蕉国产线看播放| 一日本道伊人久久综合影| 狠狠色婷婷久久一区二区 | 久久国产精品无码网站| 久久国产精品无| 国产69精品久久久久777| 香蕉久久AⅤ一区二区三区| 国内精品久久国产大陆| 国产精品久久久久久五月尺| 国产免费久久精品丫丫| 亚洲AV无码一区东京热久久 | 亚洲国产精品无码久久久不卡| 99久久久久| 久久精品国产亚洲AV高清热| 午夜精品久久影院蜜桃| 99国产精品久久久久久久成人热| 亚洲精品第一综合99久久| 99久久国产综合精品网成人影院| 久久精品黄AA片一区二区三区| 亚洲精品综合久久| 久久青青国产| 久久精品中文字幕一区| 亚洲天堂久久精品| 色综合久久综合网观看| 国产精品久久免费| 久久99国产综合精品免费| 精品久久久无码人妻中文字幕| 亚洲精品综合久久| 亚洲va久久久久| 久久精品国产亚洲AV久| 无码任你躁久久久久久老妇App| 欧美日韩精品久久久久| 久久精品夜色噜噜亚洲A∨ | 久久精品国产69国产精品亚洲| 精品久久久久久国产 | 久久青青草原精品国产不卡| 国内精品久久久久久不卡影院| 亚洲国产精久久久久久久| 久久九九亚洲精品|