[翻译]XNA 3.0 Game Programming Recipes之fifty-four
PS:自己翻译的,转载请著明出处
8-2 创建一个网络会话
问题
你想要创建一个网络会话,这样别的Xbox360控制台,Zunes,或者PCs可以找到并且加入你的会话中。
解决方案
一台机器首先需要去开始一个网络会话,你可以非常容易的实现它,使用NetworkSession.Create方法。这台机器,它创建一个会话将会是主机的会话。
在这个绘画被创建,所有的机器连接到这个会话,包括主机,通过会话可以监听任何发生的事件,例如一个玩家加入或者离开这个会话。
它如何工作的
你需要去包括Microsoft.XNA.Framework.Net命名空间从这节在本章的结尾的地方。通过添加下面的代码行去实现,并把它放在你代码文件的上面:
开始定义这些状态:
SignIn状态已经在前面的章节中讨论过了。让我们开始编写CreateSession状态。
Creating a NetWwork Session(创建一个网络会话)
在这种状态下,你将会创建一个新的网络会话。通过添加这个变量到你的代码中:
这个第一个参数指定它应该创建的会话类型。如果所有的玩家都被连接到一个同意个机器上时,一个NetworkSessionType.Local类型的会话应该被创建,例如,四个玩家可以有它们自己的控制器连接到同一台Xbox360控制台上。
如果一个或者更多的玩家在不同的机器上,它被连接到同样的网络中,你可以创建一个NetworkSessionType.SystemLink类型的会话。
NetworkSessionType.PlayerMatch类型与SystemLink类型以相同的方式工作,但是它将允许用户去连接会话在因特网上,产生有用的在线服务器。在此刻,虽然,为了使用这些服务,你需要去买一个Live Gold 会员为所有的多个Xbox360控制台。
注意:因为Zune可以创建网络连接到其他的Zunes,你可以使用唯一的NetworkSessionType.Local和NetworkSessionType.SystemLink会话
类型为这个Zune.
第二个参数指定是否多个玩家连接到网络上的同一台机器。如果不能,你应该指定,这里每台机器只能有一个玩家。如果你想这样,例如,开始一个本地会话,你应该允许更多玩家去连接到同一台机器。
注意:一个本地玩家是一个用户在这台机器上允许它的代码。现在,XNA3.0支持唯一的一个本地玩家在每一个Windows-based机器和Zune,同时让四个玩家可以连接到一个Xbox360控制台。通过其他三个玩家连接到同样的机器上,这台四个玩家之一的玩家机器被认为是本地机器(译者:主机)
最后一个参数指定它能连接会话中的最大玩家数量。因为你处理多人游戏,这个数量至少是2,同时它应该等于或者小于上限,那么PC的上限是31,Xbox360的是31,Zune设备的上限是8
NetworkSession.Create方法有一个重载版本,它接收两个以上的参数。第一个参数指定玩家的数量,它应该保持这个变量为你的朋友。这样,只有你标记为朋友的玩家将可以加入这个会话。最后一个参数允许你去标记你的会话用一个NetworkSessionProperties对象,这样其他可以很容易的找到它。参看8-3节的列子。
注意:如果机器根本没有连接任何的网络,这个NetworkSession.Create方法将会抛出一个错误,这样你希望封装它在try-catch结构中。
现在,我们开始一个新的会话,你可以设置一些它的属性。一个重要的属性定义为什么会发生,如果主机退出这个会话。你可以指定XNA应该自动选择客户/同行之一通过设置这个AllowHostMigration属性为true,去成为新的主机:
2 networkSession.AllowJoinInProgress=false;
正如你所看见的,你同样可以指定客户是否被允许加入这个会话在游戏已经开始了。
注意:应该特别注意采取主机的移植。如果任何游戏数据被专门的保存在旧的主机上,当它退出这个会话,它是非常重要的使这些数据自动转换到新的主机上。你想使至关重要的数据复制到最新的两台机器上,这样如果主机退出了,你可以复制这个数据到新的主机上。
因为XNA3.0,当本地玩家离开这个游戏时,本地网络会话将不会结束。相反,这个会话将持续至少还有一个玩家在这个会话中。
Hooking to the Session Events
现在,你的机器主持一个网络会话(主机),它将会很容易知道当其他人加入了这个会话。你可以通过挂起一个自身-定义的方法到网络会话的GamerJoined事件来实现它。只要一个玩家加入这个会话,这个会话将自动触发这个GamerJoined事件。作为一个结果,所有的方法挂起到这个将会被调用的事件。
2 {
3 log.Add(e.Gamer.Gamertag+"joined the current session");
4 }
这个网络会话可以唤醒别的事件,你可以监听它。这里包括GamerLeft事件和GameStarted和GameEnded事件,它表明当会话从大厅转换到游戏模式(参看8-7节),以及SessionEnded和HostChanged事件。
SessionEnded事件被激发,当主机退出这个会话,同时AllowHostMigration被设置为false或者当主机调用这个Dispose方法在网络会话上。这个HostChanged事件被触发当主机退出这个会话,同时AllowHostMigration被设置成true。
下面的代码将会坚听这个GamerJoined,GamerLeft,和HostChanged事件的激发通过网络会话,并且打印一个相应的行到屏幕上:
2 {
3 log.Add("Listening for session events");
4 networkSession.GamerJoined+=GamerJoinedEventHandler;
5 networkSession.GamerLeft+=GamerLeftEventHandler;
6 networkSession.HostChanged+=HostChangedEventHandler;
7 }
8 void GamerJoinedEventHandler(object sender,GamerJoinedEventArgs e)
9 {
10 log.Add(e.Gamer.Gamertag+"joined the current session");
11 }
12 void GamerLeftEventHandler(object sender,GamerLeftEventArgs e)
13 {
14 log.Add(e.Gamer.Gamertag+"left the current session");
15 }
16 void HostChangedEventHandler(object sender,HostChangedEventArgs e)
17 {
18 log.Add("Host migration detected");
19 NetworkSession eventRaisingSession=(NetworkSession)sender;
20 if(eventRaisingSession.IsHost)
21 log.Add("This machine has become the new Host!");
22 }
确保你直接调用这个HookSessionEvents方法在你已经创建你的会话之后。这就是CreateSession状态在Update方法应该看起来象这样:
2 {
3 networkSession=NetworkSession.Create(NetworkSessionType.SystemLink,4,8);
4 networkSession.AllowHostMigration=true;
5 networkSession.AllowJoinInProgress=false;
6 log.Add("New session created");
7 HookSessionEvents();
8 currentGameState=GameState.InSession;
9 }
这个会话被创建,AllowHostMigration和AllowJoinInProgress值被设置,并且程序正在监听每个触发的事件通过这个会话。
Updateing the Network Session(更新网络会话)
一旦你连接了一个会话,你应该更新它在定期的时间内。一个明显的地方要做到这个是在你的游戏的更新循环中。现在,这是唯一的事情,它被完成在InSession状态时期:
2 {
3 newworkSession.Update();
4 }
5 break;
代码
在这里,你可以找到最终的Update方法。这个程序将开始于SignIn状态,在一个会话被创建在CreateSession状态中。程序结束在InSession状态。
2 {
3 if(GamePad.GetState(PlayerIndex.One).Buttons.Back==ButtonState.Pressed)
4 this.Exit();
5 if(this.IsActive)
6 {
7 switch(currentGameState)
8 {
9 case GameState.SignIn:
10 {
11 if(Gamer.SignedInGamers.Count<1)
12 {
13 Guide.ShowSignIn(1,false);
14 log.Add("Opened User SignIn Interface");
15 }
16 else
17 {
18 currentGameState=GameState.CreateSession;
19 log.Add(Gamer.SignedInGamers[0].Gamertag+"logged in -proceed to CreateSession");
20 }
21 }
22 break;
23 case GameState.CreateSession:
24 {
25 networkSession=NetworkSession.Create(NetworkSessionType.SystemLink,4,8);
26 networkSession.AllowHostMigration=true;
27 networkSession.AllowJoinInProgress=false;
28 log.Add("New session created");
29 HookSessionEvents();
30 currentGameState=GameState.InSession;
31 }
32 break;
33 case GameState.InSession:
34 {
35 networkSession.Update();
36 }
37 break;
38 }
39 }
40 base.Update(gameTime);
41 }
42
(完)