一些网络操作,诸如下载玩家配置或搜索可用的会话,会花费大量的时间。前面的教程中使用的是最简单的设置,这些操作会使程序暂停直至操作完成,这段时间中你想让玩家知道操作的信息!
XNA为几乎所有需要时间完成的网络操作提供了异步选择。例如,NetworkSession. Find 方法的异步操作对应NetworkSession. BeginFind方法。
在异步操作的开始,XNA会创建第二个线程用于这个操作,让这个操作可以与主程序并行处理。这样做的优点是,你的主程序只需初始化异步操作,然后可以继续自己的处理。这让你可以向玩家提供任何运行在第二个线程中的异步操作的信息。
一旦异步操作完成,结果会传递到你指定的方法中,让你可以处理异步操作产生的结果。
这个教程会解释如何使用NetworkSession.BeginFind方法,XNA中的其他的异步操作工作原理是相同的。
这个教程是教程8-3的异步版本,在那个教程中,程序开始处于SignIn状态并依次进入SearchSession, CreateSession和InSession状态。在这个教程中,你将添加一个Searching状态,当操作在后台运行时可以向用户提供信息:
public enum GameState ...{ SignIn, SearchSession, Searching, CreateSession, InSession }
SearchSession状态很容易,因为它要做的只是初始化异步操作:
case GameState.SearchSession: ...{ NetworkSession.BeginFind(NetworkSessionType.SystemLink, 2, null, EndAsynchSearch, null); log.Add("ASynch search started - proceed to Searching"); log.Add("Searching"); currentGameState = GameState.Searching; } break;
NetworkSession.BeginFind方法会导致在后台创建第二个线程,这个线程与主程序并行进行搜索操作,这样带来的好处是主程序在运行到NetworkSession.BeginFind时无需等待(而使用NetworkSession.Find方法时需要),可以立即进入到Searching状态。
NetworkSession.BeginFind方法需要五个参数。前三个和NetworkSession. Find方法是相同的,可见教程8-3的解释。
要理解第四个参数,我需要解释当后台的搜索操作结束后会发生什么。第二个线程会调用你的方法之一并将它传递到结果。这意味着你必须指定应该调用哪个方法,这可以通过使用第四个参数做到。在本例中,当第二个线程结束后你指定它调用EndAsynchSearch方法,这个方法后面就会讲到。
最后一个参数让你识别异步操作,当在同一时间有多个异步操作的情况中这是很有用的。可见教程1—9看一下这个参数的例子。
当搜索在后台进行时,你可以自由地在Searching状态中做任何其他操作。在这个简单的例子中,每次调用Update方法时, 会在显示在屏幕的文字后面加上一个”.”。
case GameState.Searching: ...{ log[log.Count - 1] +=”.” } break;
当运行在后台的第二个线程结束异步搜索后,它会调用在NetworkSession. BeginFind方法中第四个参数指定的方法。在前面的代码中,我指定的是EndAsynchSearch方法,具体代码如下,看起来比较复杂,但主要部分来自于前一个教程的SearchSession状态中的代码:
private void EndAsynchSearch(IAsyncResult result) ...{ AvailableNetworkSessionCollection activeSessions = NetworkSession.EndFind(result); if (activeSessions.Count == 0) ...{ currentGameState = GameState.CreateSession; log.Add("No active sessions found - proceed to CreateSession"); } else ...{ AvailableNetworkSession sessionToJoin = activeSessions[0]; networkSession = NetworkSession.Join(sessionToJoin); string myString = "Joined session hosted by " + sessionToJoin.HostGamertag; myString += " with " + sessionToJoin.CurrentGamerCount.ToString() + " players"; myString += " and " + sessionToJoin.OpenPublicGamerSlots.ToString() + " open player slots."; log.Add(myString); HookSessionEvents(); currentGameState = GameState.InSession; } }
这个方法将异步操作的结果作为参数。
对每个开始一个异步操作的方法,你都会找到一个方法可以处理它的结果。本例中开始异步操作的是NetworkSession.BeginFind方法,你可以将结果传递到NetworkSession.EndFind方法,这个方法将结果放在一个AvailableNetworkSessionCollection对象中。接下去的操作就和前一个教程一模一样了。
下面是Update方法中的switch代码块,这个代码让程序从SignIn状态移动到SearchSession和Searching状态。EndAsynchSearch方法决定是否移动到CreateSession或 InSession状态。
switch (currentGameState) ...{ case GameState.SignIn: ...{ if (Gamer.SignedInGamers.Count < 1) ...{ Guide.ShowSignIn(1, false); log.Add("Opened User SignIn Interface"); currentGameState = GameState.SearchSession; log.Add(Gamer.SignedInGamers[0].Gamertag + " logged in - proceed to SearchSession"); } } break; case GameState.SearchSession: ...{ NetworkSession.BeginFind(NetworkSessionType.SystemLink, 2, null, EndAsynchSearch, null); log.Add("ASynch search started - proceed to Searching"); log.Add("Searching"); currentGameState = GameState.Searching; } break; case GameState.Searching: ... { log[log.Count - 1] += "."; } break; case GameState.CreateSession: ... { networkSession = NetworkSession.Create(NetworkSessionType.SystemLink,4, 16); networkSession.AllowHostMigration = true; networkSession.AllowJoinInProgress = false; log.Add("New session created"); HookSessionEvents(); currentGameState = GameState.InSession; } break; case GameState.InSession: ...{ networkSession.Update(); } break; }