问题

创建了会话后,你想给所有玩家时间用来聚集、聊天、让他们可以示意已经准备好可以进行游戏了。

解决方案

XNA在会话状态和玩家的IsReady属性中带有基本的lobby功能。

会话开始于Lobby状态。只有主机可以调用NetworkSession. StartGame方法,这个方法将会话移动到Playing状态。主机可以基于所有玩家的IsReady状态做出决定。

工作原理

当会话创建后,会话的SessionState属性会拥有Lobby值。 当在这个状态时,你需要让所有在这个会话中的玩家可以示意他们已经做好了准备,这可以通过将他们的IsReady设为true做到。这个值可以被会话中的所有玩家读取:

case GameState.InSession:
...{
    switch (networkSession.SessionState)
...    {
        case NetworkSessionState.Lobby:
        ...{
            if (keybState != lastKeybState) 
...            {
                if (keybState.IsKeyDown(Keys.R))
                {
                    LocalNetworkGamer localGamer = networkSession.LocalGamers[0]; 
                    localGamer.IsReady = !localGamer.IsReady;
                }
            }
        }
        break;
        case NetworkSessionState.Playing:
...        {
        }
        break;
    }

    networkSession.Update(); 
}

主机需要检测是否所有玩家都将IsReady设为了true。最简单的方法是检查NetworkSess ion.IsEveryoneReady的值,如果所有人都准备好了,主机会调用NetworkSession.StartGame方法,这个方法将状态从Lobby移动到Playing:

case NetworkSessionState.Lobby:
...{
    if (keybState != lastKeybState)
...    {
        if (keybState.IsKeyDown(Keys.R))
...        {
            LocalNetworkGamer localGamer = networkSession.LocalGamers[0]; 
            localGamer.IsReady = !localGamer.IsReady;
        }
    }
    if (networkSession.IsHost)
    ...{
        if (networkSession.AllGamers.Count > 1) 
        ...{
            if (networkSession.IsEveryoneReady) 
            ...{
                networkSession.StartGame();
                log.Add("All players ready -- start the game!");
            }
        }
    }
}
break;

当状态改变至Playing时,会话会引发GameStarted事件,这个事件所有玩家都会进行监听。这样可以让他们绘制游戏屏幕并开始发送和接收游戏数据。

当主机决定结束游戏时,需要调用NetworkSession.EndGame方法,这个方法将所有玩家的IsReady重置为false并返回Lobby状态。

case NetworkSessionState.Playing:
...{
    if (networkSession.IsHost)
...    {
        if (keybState != lastKeybState) 
...        {
            if (keybState.IsKeyDown(Keys.E)) 
                ...{
                    networkSession.EndGame();
            }
        }
        }
}
break;

这会引发会话的GameEnded事件,所有玩家都可以监听这个事件,这样他们就可以,例如,绘制lobby图像。

代码

InSession状态包含大多数基本代码让多个玩家表示他们的IsReady,让主机从Lobby状态移动到Playing状态或返回:

case GameState.InSession:
...{
    switch (networkSession.SessionState)
    ...{
        case NetworkSessionState.Lobby:
        ...{
            if (keybState != lastKeybState)
...            {
                if (keybState.IsKeyDown(Keys.R))
...                {
                    LocalNetworkGamer localGamer = networkSession.LocalGamers[0]; localGamer.IsReady = !localGamer.IsReady;
                }
            }
            if (networkSession.IsHost)
...            {
                if (networkSession.AllGamers.Count > 1) 
                ...{
                    if (networkSession.IsEveryoneReady) 
                    ...{
                        networkSession.StartGame();
                        log.Add("All players ready -- start the game!");
                    } 
                }
            }
        }
        break;
        case NetworkSessionState.Playing:
...        {
            if (networkSession.IsHost)
...            {
                if (keybState != lastKeybState)
...                {
                    if (keybState.IsKeyDown(Keys.E))
...                    {
                        networkSession.EndGame();
                    }
                }
            }
        }
        break; 
    }
    networkSession.Update();
}
break;