第二人生的源码分析(二十五)人物行走与服务器同步
在网络游戏里,玩家的行走与平时单机版的游戏有着很大的差别,当你按下键盘时,人物角色并不能立即就向前行走,而是需要把它移动的请求发送到服务器,让服务器来作出判断是否可以行走,然后把行走位置通知视野里所有其它玩家,第二人生的客户端就会把这个人物按位置信息显示出来。下面就来分析怎么样发送玩家状态信息给服务器。
#001 void LLAppViewer::idle()
#002 {
#003 // Update frame timers
#004 static LLTimer idle_timer;
#005
#006 LLControlBase::updateAllListeners();
#007
#008 LLFrameTimer::updateFrameTime();
#009 LLEventTimer::updateClass();
#010 LLCriticalDamp::updateInterpolants();
#011 LLMortician::updateClass();
#012 F32 dt_raw = idle_timer.getElapsedTimeAndResetF32();
#013
……
#077
#078 static LLFrameTimer agent_update_timer;
#079 static U32 last_control_flags;
#080
#081 // When appropriate, update agent location to the simulator.
#082 F32 agent_update_time = agent_update_timer.getElapsedTimeF32();
#083 BOOL flags_changed = gAgent.controlFlagsDirty() || (last_control_flags != gAgent.getControlFlags());
#084
#085 if (flags_changed || (agent_update_time > (1.0f / (F32) AGENT_UPDATES_PER_SECOND)))
#086 {
#087 // Send avatar and camera info
#088 last_control_flags = gAgent.getControlFlags();
#089 send_agent_update(TRUE);
#090 agent_update_timer.reset();
#091 }
#092 }
#093 ......
#094 }
上面第83行获取当前角色的状态是否发生变化,然后通过send_agent_update函数不断地发送状态消息给服务器。接着下来就去分析这个函数,它的代码如下:
#001 void send_agent_update(BOOL force_send, BOOL send_reliable)
#002 {
#003 if (gAgent.getTeleportState() != LLAgent::TELEPORT_NONE)
#004 {
#005 // We don't care if they want to send an agent update, they're not allowed to until the simulator
……
#147
#148 if (duplicate_count < DUP_MSGS && !gDisconnected)
#149 {
#150 // Build the message
#151 msg->newMessageFast(_PREHASH_AgentUpdate);
#152 msg->nextBlockFast(_PREHASH_AgentData);
#153 msg->addUUIDFast(_PREHASH_AgentID, gAgent.getID());
#154 msg->addUUIDFast(_PREHASH_SessionID, gAgent.getSessionID());
#155 msg->addQuatFast(_PREHASH_BodyRotation, body_rotation);
#156 msg->addQuatFast(_PREHASH_HeadRotation, head_rotation);
#157 msg->addU8Fast(_PREHASH_State, render_state);
#158 msg->addU8Fast(_PREHASH_Flags, flags);
#159
#160 // if (camera_pos_agent.mV[VY] > 255.f)
#161 // {
#162 // llinfos << "Sending camera center " << camera_pos_agent << llendl;
#163 // }
#164
#165 msg->addVector3Fast(_PREHASH_CameraCenter, camera_pos_agent);
#166 msg->addVector3Fast(_PREHASH_CameraAtAxis, gCamera->getAtAxis());
#167 msg->addVector3Fast(_PREHASH_CameraLeftAxis, gCamera->getLeftAxis());
#168 msg->addVector3Fast(_PREHASH_CameraUpAxis, gCamera->getUpAxis());
#169 msg->addF32Fast(_PREHASH_Far, gAgent.mDrawDistance);
#170
#171 msg->addU32Fast(_PREHASH_ControlFlags, control_flags);
#172
#173 if (gDebugClicks)
#174 {
#175 if (control_flags & AGENT_CONTROL_LBUTTON_DOWN)
#176 {
#177 llinfos << "AgentUpdate left button down" << llendl;
#178 }
#179
#180 if (control_flags & AGENT_CONTROL_LBUTTON_UP)
#181 {
#182 llinfos << "AgentUpdate left button up" << llendl;
#183 }
#184 }
#185
#186 gAgent.enableControlFlagReset();
#187
#188 if (!send_reliable)
#189 {
#190 gAgent.sendMessage();
#191 }
#192 else
#193 {
#194 gAgent.sendReliableMessage();
#195 }
#196
#197 //llinfos << "agent " << avatar_pos_agent << " cam " << camera_pos_agent << llendl;
#198
#199 // Copy the old data
#200 last_head_rot = head_rotation;
#201 last_render_state = render_state;
#202 last_camera_pos_agent = camera_pos_agent;
#203 last_camera_at = gCamera->getAtAxis();
#204 last_camera_left = gCamera->getLeftAxis();
#205 last_camera_up = gCamera->getUpAxis();
#206 last_control_flags = control_flags;
#207 last_flags = flags;
#208 }
#209 }
#210
在上面的代码里,就调用msg消息对象创建状态消息,然后通过sendMessage和sendReliableMessage函数发送给服务器,这样在服务器的玩家角色就会更新状态,如果行走的话,也会得到更新的。第二人生里的消息结构是根据XML模板来构造的,这个部分的功能也比较复杂。
蔡军生 2008/3/14 QQ:9073204 深圳