• <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(9)

             

            Storing Player Information

            Players in the game are only allowed to move around and swing their weapons (hitting
            other players). The server will want to track every player’s current state (walking,
            standing still, swinging their weapons, or being hurt), the coordinates in the world,
            the direction they are facing, and the speed they are walking (if they are walking).

            This player data is stored inside a structure called sPlayer. Because all connected
            players in the game need their own set of unique data, an array of sPlayer structures
            are allocated to store the information. Both the number of player structures
            to allocate and the number of players to allow to join the game session are stored
            in the macro MAX_PLAYERS, which is currently set to 8.

            The sPlayer structure is as follows (with supporting state definition macros):

            #define MAX_PLAYERS           8     // Maximum number of players allowed to be connected at once

            #define STATE_IDLE            1 
            #define STATE_MOVE            2
            #define STATE_SWING           3
            #define STATE_HURT            4

            typedef 
            struct sPlayer
            {
                
            bool    connected;

                
            char    name[256];
                DPNID   player_id;

                
            long    last_state;      
                
            long    last_update_time;
                
            long    latency;

                
            float   x_pos, y_pos, z_pos;
                
            float   direction;
                
            float   speed;

                
            ///////////////////////////////////////////////////////////////
                
                sPlayer()
                {
                    ZeroMemory(
            thissizeof(*this));
                }
            } *sPlayerPtr;

            There’s not much to the sPlayer structure; you have a flag if the player is connected,
            the name of the player, the player’s DirectPlay identification number, the
            player’s current state (as defined by the state macros), time of last state change,
            network latency value, the player’s coordinates, direction, and walking speed.

            The variables in sPlayer are self-explanatory, except for latency. Remember that
            latency is the delay resulting from network transmission. By storing the time it takes
            for a message to go from the server to the client (and vice versa), time-based calculations
            become more synchronized between the server and client.

            Speaking of time-based calculations, that's the purpose of the last_update_time variable. Whenever
            the server updates all players, it needs to know the time that has elapsed between
            updates. Every time a player state is changed (from the client), the last_update_time variable is set
            to the current time (minus the latency time).

            Time is also used to control actions. If a player swings a weapon, the server refuses
            to accept further state changes from the client until the swing weapon state is
            cleared. How does the state clear? After a set amount of time, that’s how! After one
            second passes, the update player cycle clears the player’s state back to idle, allowing
            the client to begin sending new state-change messages.

            On the subject of sending messages, take a look at how the server deals with the
            incoming network messages.

             

            Handling Messages

            You’ve already seen DirectPlay messages in action, but now you focus on the game
            action messages (state changes). Because DirectPlay has only three functions of
            interest when handling incoming network messages (create_player, destroy_player, and
            receive), the server will need to convert the incoming networking message to messages
            more suited to game-play.

            The server receives messages from clients via the DirectPlay network’s receive function.
            Those messages are stored in the pReceiveData buffer contained within the
            DPNMSG_RECEIVE structure passed to the receive function. That buffer is cast into a
            more usable game message, which is stuffed into the game message queue.

            The server game code doesn’t deal directly with network messages. Those are handled
            by a small subset of functions that take the incoming messages and convert
            them into game messages (which are entered into the message queue). The server
            game code works with those game messages.

            Because there can be many different types of game messages, a generic message
            container structure is needed. Each message starts with a header that stores
            the type of message, the total size of the message data (in bytes) including the
            header, and a DirectPlay player identification number that is usually set to the
            player sending the message.

            I’ve taken the liberty of separating the header into another structure, making
            it possible to reuse the header in every game message:

            #define MESSAGES_PER_FRAME 64 // number of messages to process per frame
            #define MAX_MESSAGES 1024 // number of message to allocate for message queue

            typedef struct sMsgHeader
            {
              long type; // type of message (MSG_*)
              long size; // size of data to send
              DPNID player_id; // player performing action
            } *sMsgHeaderPtr;

            Because there can be many different game messages, you first need a generic message
            container capable of holding all the different game messages. This generic
            message container is a structure as follows:

            typedef struct sMsg // the message queue message structure
            {
              sMsgHeader header;
              char data[512];
            } *sMsgPtr;

            Pretty basic, isn’t it? The sMsg structure needs to contain only the message header
            and an array of chars used to store the specific message data. To use a specific message,
            you can cast the sMsg structure into another structure to access the data.

            For example, here is a structure that represents a state-change message:

            typedef struct sStateChangeMsg
            {
              sMsgHeader header;

              long state; // State message (STATE_*)
              float x_pos, y_pos, z_pos;
              float direction;
              float speed;
              long latency;
            } *sStateChangeMsgPtr;

             

            To cast the sMsg structure that contains a state-change message into a usable
            sStateChangeMsg structure, you can use this code bit:

            sMsg Msg; // Assuming message contains data
            sStateChangeMsg *scm = (sStateChangeMsg*) Msg;

            // Access state-change message data
            scm->state = STATE_IDLE;
            scm->direction = 1.57f;

            In addition to the state-change message, the following message structures are used
            in the network game:

            typedef struct sCreatePlayerMsg
            {
              sMsgHeader header;
              float x_pos, y_pos, z_pos; // create player coordinates
              float direction;
            } *sCreatePlayerMsgPtr;

            typedef struct sRequestPlayerInfoMsg
            {
              sMsgHeader header;
              DPNID request_player_id; // which player to request
            } *sRequestPlayerInfoMsgPtr;

            typedef struct sDestroyPlayerMsg
            {
              sMsgHeader header;
            } *sDestroyPlayerMsgPtr;

            Each message also has a related macro that both the server and client use. Those
            message macros are the values store in the sMsgHeader::type variable. Those message
            type macros are as follows:

            #define MSG_CREATE_PLAYER    1
            #define MSG_SEND_PLAYER_INFO 2
            #define MSG_DESTROY_PLAYER   3
            #define MSG_STATE_CHANGE     4

            You see each message in action in the sections “Processing Game Messages” and
            “Working with Game Clients,” later in this chapter, but for now, check out how the
            server maintains these game-related messages.

            posted on 2007-12-18 19:52 lovedday 閱讀(269) 評(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)論

            国内精品久久久久久99蜜桃| 久久99国内精品自在现线| 精品久久久久中文字幕一区| 久久国产福利免费| 色婷婷久久综合中文久久一本| 久久精品国产亚洲AV香蕉| 国产精品久久一区二区三区| 亚洲国产成人久久综合野外| 精品少妇人妻av无码久久| 久久精品国产清自在天天线| 国产麻豆精品久久一二三| 久久久青草青青国产亚洲免观| 亚洲va久久久噜噜噜久久狠狠| 青青草原综合久久| 无码人妻精品一区二区三区久久| 国产—久久香蕉国产线看观看| 久久精品国产精品亚洲毛片| 伊人久久大香线蕉综合网站| 国产亚洲精午夜久久久久久| 国产亚洲精久久久久久无码| 久久AV高潮AV无码AV| 婷婷久久综合九色综合绿巨人| 国产欧美久久久精品| 久久婷婷五月综合97色一本一本| 亚洲午夜福利精品久久| 欧美久久久久久午夜精品| 国产精品狼人久久久久影院| 99久久国产热无码精品免费| 久久亚洲精品国产精品| 亚洲中文久久精品无码ww16| 久久综合久久美利坚合众国| 亚洲Av无码国产情品久久| 久久综合亚洲色HEZYO国产| 精品久久久久久无码国产| 丰满少妇人妻久久久久久4| 精品久久久久久无码国产| 99精品久久久久久久婷婷| 激情五月综合综合久久69| 久久久精品国产Sm最大网站| 久久综合精品国产一区二区三区 | 久久综合给合久久狠狠狠97色69|