在网络游戏里,玩家的行走与平时单机版的游戏有着很大的差别,当你按下键盘时,人物角色并不能立即就向前行走,而是需要把它移动的请求发送到服务器,让服务器来作出判断是否可以行走,然后把行走位置通知视野里所有其它玩家,第二人生的客户端就会把这个人物按位置信息显示出来。下面就来分析怎么样发送玩家状态信息给服务器。
#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 深圳