角色登场,消失及同步化
以下实现客户端登陆后, 构建角色的登场,消失在游戏场景中.
1. 客户端A登陆成功的话,角色的位置发送给服务器”进入游戏”通知.
2. 服务器端接收信息后,发送客户端A已经存在角色信息,并且发送其它客户端新的信息.
3. 客户端接收后添加新角色到游戏场景中.
客户端 "进入游戏!" 的信息在PIDL中定义.
global Simple 1000
{
JoinGameScene([in] float x, [in] float y, [in] float z, [in] float angle);
Player_Appear([in] int hostID, [in] std::wstring userID,
[in] float x, [in] float y, [in] float z,
[in] float vx, [in] float vy, [in] float vz,
[in] float angle);
Player_Disappear([in] int hostID);
...
|
客户端登陆成功的话,通知服务器 "进入游戏!".
m_stub.NotifyLoginSuccess = (HostID remote, RmiContext rmiContext) =>
{
// join the world!
m_proxy.JoinGameScene(HostID.HostID_Server, RmiContext.ReliableSend,
m_localPlayer.transform.position.x,
m_localPlayer.transform.position.y,
m_localPlayer.transform.position.z,
m_localPlayer.GetComponent<PlayControl>().carAngle); // show 30 ends here
...
|
现在,添加服务器处理的代码.
class SimpleServer
{
DECRMI_Simple_JoinGameScene;
...
DEFRMI_Simple_JoinGameScene(SimpleServer)
{
// validation check
auto it = m_remoteClients.find(remote);
if (it == m_remoteClients.end())
{
return true;
}
auto& rc = it->second;
// update player info
rc->m_x = x;
rc->m_y = y;
rc->m_z = z;
rc->m_angle = angle;
|
以上代码中JoinGameScene继续添加一下代码.
DEFRMI_Simple_JoinGameScene(SimpleServer)
{
...
assert(it->first == remote);
// Let incomer know others, let others know incomers.
for (auto otherIter : m_remoteClients)
{
if (otherIter.first != it->first)
{
auto& otherRC = otherIter.second;
m_proxy.Player_Appear((HostID)it->first, RmiContext::ReliableSend,
(HostID)otherIter.first,
otherRC->m_userID,
otherRC->m_x, otherRC->m_y, otherRC->m_z,
otherRC->m_vx, otherRC->m_vy, otherRC->m_vz,
otherRC->m_angle);
m_proxy.Player_Appear((HostID)otherIter.first, RmiContext::ReliableSend,
(HostID)it->first,
rc->m_userID,
rc->m_x, rc->m_y, rc->m_z,
rc->m_vx, rc->m_vy, rc->m_vz,
rc->m_angle);
}
}
|
以上代码解析如下:
1. 接收到的更新游戏角色的信息。
2. 传递之前客户端名单,告知客户端新用户的加入
。同样,告知新客户端现有客户端的加入。
客户端离开的情况,进行相反的处理. 离开后,出现"客户端OO消失"的信息.
m_netServer->OnClientLeave = [this](CNetClientInfo* info, ErrorInfo*, const ByteArray&)
{
// let others know the disappear
vector<int> others;
for (auto otherIter : m_remoteClients)
{
others.push_back(otherIter.first);
}
m_proxy.Player_Disappear((HostID*)others.data(), others.size(),
RmiContext::ReliableSend,
info->m_HostID);
...
|
调用以上远程函数时,变量HostID的数组进入.这样的话,可对多个设备进行信息发送.
添加客户端中调用Player_Appear的处理代码.,在游戏场景中角色登场.
public class NetManager : MonoBehaviour
{
public GameObject m_remotePlayerPrefab;
void Start()
{
m_stub.Player_Appear = (HostID remote, RmiContext rmiContext, int hostID, System.String userID, float x, float y, float z, float vx, float vy, float vz, float angle) =>
{
if (hostID != (int)m_netClient.GetLocalHostID())
{
var rot = Quaternion.AngleAxis(angle, new UnityEngine.Vector3(0, 1, 0));
var remotePlayerCharacter = (GameObject)Instantiate(m_remotePlayerPrefab, new UnityEngine.Vector3(x, y, z), rot);
remotePlayerCharacter.name = "RemotePlayer/" + hostID.ToString();
}
return true;
};
|
设置以下条件.
Unity Editor中选择NetManager GameObject后,在 Inspector中 m_remotePlayerPrefab下添加名为RemotePlayer的Prefab.如果没有 RemoteCar Prefab的话,制作场景内LocalPlayer的复制版后,并删除所有的 Script Behavior.
调用Player_Disappear后, 此角色在游戏场景中被删除.
m_stub.Player_Disappear = (Nettention.Proud.HostID remote,
Nettention.Proud.RmiContext rmiContext, int hostID) =>
{
var g = GameObject.Find("RemotePlayer/" + hostID.ToString());
if (g != null)
{
Destroy(g);
}
return true;
};
|
现在进行测试. 运行两个以上的客户端后,角色登场.
首先会出现角色的位置,但是无法操控,下篇将继续讲述.