11.5 セッションイベント
11.5.1 参加や退室時の通知
セッションは、ゲームに他のゲーマーが参加してくるタイミングを事前に把握することはできません。セッション参加時に、他の参加者とのデータの同期などが必要なであれば、セッションに誰かが参加した時点で初期化処理を実行する必要があります。このような、突然のセッションへの参加や中断を対処するには NetworkSession クラスが公開しているイベントを使います。
例えば、現在のセッションにゲーマーが参加すると GamerJoined イベントが発生します。
public event EventHandler<GamerJoinedEventArgs> GamerJoined
このイベントに設定するデリゲートは、パラメータに Microsoft.Xna.Framework.Net.GamerJoinedEventArgs クラスのオブジェクトを受け取ります。
public class GamerJoinedEventArgs : EventArgs
セッションに参加したゲーマーは Gamer プロパティから取得できます。
public NetworkGamer Gamer { get; }
このプロパティは、セッションに参加したゲーマーを表す NetworkGamer オブジェクトを返します。
これらの機能を使うことで、誰かかセッションに参加した瞬間にプレイヤーに対して「~さんが参加しました」というようなメッセージを表示するといった処理が可能です。ホストがゲーム全体を集中管理しているクライアントサーバー型の通信構造であれば、新しいゲーマーが参加した時にホストとデータの同期や、何らかの登録手続きなどの処理を実行できるでしょう。
ゲーマーがセッションから抜け出すと GamerLeft イベントが発生します。
public event EventHandler<GamerLeftEventArgs> GamerLeft
このイベントに登録するデリゲートは、パラメータからセッションを抜け出したゲーマーの情報を提供する GamerLeftEventArgs クラスのオブジェクトを受け取ります。構造は GamerJoinedEventArgs クラスと同じで Gamer プロパティからセッションを抜けたゲーマーを表す NetworkGamer オブジェクトを取得できます。
同じように、ホストがゲームを開始すると GameStarted イベントが発生し、ゲームを終了すると GameEnded イベントが発生します。
public event EventHandler<GameStartedEventArgs> GameStarted
public event EventHandler<GameEndedEventArgs> GameEnded
ゲーム開始時の初期化処理の実行や、ゲーム終了時にメニュー画面に復帰する処理などの機能に、これらのイベントを利用することができます。
using Microsoft.Xna.Framework; using Microsoft.Xna.Framework.Input; using Microsoft.Xna.Framework.Graphics; using Microsoft.Xna.Framework.GamerServices; using Microsoft.Xna.Framework.Net; public class Test : Game { public static void Main(string[] args) { using (Game game = new Test()) game.Run(); } private GraphicsDeviceManager graphicsDeviceManager; private NetworkSession session; private AvailableNetworkSessionCollection sessions; private SpriteBatch sprite; private SpriteFont font; private string text, eventLog; public Test() { graphicsDeviceManager = new GraphicsDeviceManager(this); Components.Add(new GamerServicesComponent(this)); eventLog = ""; } protected override void LoadContent() { sprite = new SpriteBatch(GraphicsDevice); font = Content.Load<SpriteFont>("Content/TestFont"); base.LoadContent(); } protected override void Update(GameTime gameTime) { GamePadState state = GamePad.GetState(PlayerIndex.One); if (state.Buttons.Back == ButtonState.Pressed) Exit(); SignedInGamer gamer = Gamer.SignedInGamers[PlayerIndex.One]; if (gamer == null) { text = "Please sign in as player one."; if (!Guide.IsVisible) Guide.ShowSignIn(1, true); } else { if (session != null) UpdateSession(state); else if (sessions != null) UpdateFindSession(state); else UpdateMenu(state); } base.Update(gameTime); } private void UpdateMenu(GamePadState state) { text = "A BUTTON: Create a network session\n"; text += "X BUTTON: Find a network session\n\n"; if (state.Buttons.A == ButtonState.Pressed) { session = NetworkSession.Create(NetworkSessionType.SystemLink, 1, 16); eventLog = ""; //イベントにデリゲートを登録 session.GamerJoined += session_GameJoined; session.GamerLeft += session_GamerLeft; session.GameStarted += session_GameStarted; session.GameEnded +=session_GameEnded; } else if (state.Buttons.X == ButtonState.Pressed) sessions = NetworkSession.Find(NetworkSessionType.SystemLink, 1, null); } private void session_GameJoined(object sender, GamerJoinedEventArgs e) { eventLog += "Gamer joined:" + e.Gamer.Gamertag+ "\n"; } private void session_GamerLeft(object sender, GamerLeftEventArgs e) { eventLog += "Gamer left:" + e.Gamer.Gamertag + "\n"; } private void session_GameStarted(object sender, GameStartedEventArgs e) { eventLog += "Game started\n"; } private void session_GameEnded(object sender, GameEndedEventArgs e) { eventLog += "Game ended\n"; } private void UpdateSession(GamePadState state) { text = "Sesssion state=" + session.SessionState + "\n"; if (session.IsHost) { text += "A BUTTON: Game start\n"; text += "X BUTTON: Game end\n"; if (state.Buttons.A == ButtonState.Pressed && session.SessionState == NetworkSessionState.Lobby) session.StartGame(); else if (state.Buttons.X == ButtonState.Pressed && session.SessionState == NetworkSessionState.Playing) session.EndGame(); } text += "B BUTTON: Dispose a network session\n\n"; text += eventLog; session.Update(); if (state.Buttons.B == ButtonState.Pressed) { session.Dispose(); session = null; } } private void UpdateFindSession(GamePadState state) { text = "Network session search results\n"; text += "B BUTTON: Return to menu\n\n"; if (state.Buttons.B == ButtonState.Pressed) sessions = null; else if (sessions.Count == 0) text += "Session not found"; else { session = NetworkSession.Join(sessions[0]); sessions = null; } } protected override void Draw(GameTime gameTime) { GraphicsDevice.Clear(Color.White); sprite.Begin(); sprite.DrawString(font, text, Vector2.Zero, Color.Black); sprite.End(); base.Draw(gameTime); } }
コード1は、各セッションのイベントが発生すると、発生したイベントの情報を表す文字列を eventLog フィールドに書き加えます。Draw() メソッドでは eventLog フィールドのテキストを表示しているので、セッションに他のゲーマーが参加するか抜け出すと、文字列が追加されてイベントが発生していることを確認できます。同様に、ホストがゲームを開始したり終了したりするとイベントが発生します。