WisdomSoft - for your serial experiences.

11.3 セッションへの参加

セッション検索で取得した有効なセッションに参加します。ホスト以外のユーザーは、セッションを検索して、得られた有効なセッションのいずれかに加わることで、ホストや他の参加者と通信します。

11.3.1 検索で得られたセッションに入る

Find() メソッドを使ってネットワーク上の接続可能なセッションを検索し、AvailableNetworkSession オブジェクトを得ることができれば、対象のセッションに Join() メソッドで参加できます。

NetworkSession クラス Join() メソッド
public static NetworkSession Join (
         AvailableNetworkSession availableSession
)

availableSession パラメータには、Find() メソッドの結果から得られた接続先となる AvailableNetworkSession オブジェクトを指定します。メソッドは、接続先となる NetworkSession オブジェクトを返します。

ここで得られる NetworkSession オブジェクトは、Create() メソッドで生成した NetworkSession オブジェクトとは異なり、ホスト権限はないことに注意してください。後述するゲームの開始や終了といった、ホスト権限が必要な操作を行うと例外が発生してしまいます。

NetworkSession オブジェクトがホストであるかどうかは IsHost プロパティから調べられます。

NetworkSession クラス IsHost プロパティ
public bool IsHost { get; }

このプロパティは、セッションがホストである場合は true を、そうでなければ false を返します。

セッションに参加しているゲーマーは AllGamers プロパティから取得できます。ここから、セッションに参加している人数や、参加ゲーマーのゲーマータグなどを取得できます。

NetworkSession クラス AllGamers プロパティ
public GamerCollection<NetworkGamer> AllGamers { get; }

このプロパティは、セッションに参加しているゲーマーのコレクションとなる GamerCollection オブジェクトを返します。このコレクションは、ネットワーク上のゲーマーを表す Microsoft.Xna.Framework.Net.NetworkGamer クラスのオブジェクトを提供します。

Microsoft.Xna.Framework.Net.NetworkGamer クラス
public class NetworkGamer : Gamer

このクラスは Gamer クラスを継承し、ネットワークで繋がっているゲーマーを表します。このクラスのオブジェクトから、セッションに参加している他のゲーマーの状態を取得できます。

例えば、対象のゲーマーがホストであるかどうかは IsHost プロパティから得られます。

NetworkGamer クラス IsHost プロパティ
public bool IsHost { get; }

ゲーマーがセッションのホストである場合は true が、そうでなければ false が返されます。

また、AllGamers プロパティが返したゲーマーのコレクションには、自分自身も含まれています。得られた NetworkGamer がローカルマシンにサインインしているゲーマーなのか、リモートのゲーマーなのかを把握するには IsLocal プロパティを使います。

NetworkGamer クラス IsLocal プロパティ
public bool IsLocal { get; }

ローカルマシンにサインインしているゲーマーであれば true が、そうでなければ false が返されます。

ホストの場合は、Create() メソッドで生成した NetworkSession オブジェクトから他のプレイヤーと繋がり、それ以外のプレイヤーは Join() メソッドが返した NetworkSession オブジェクトから他のプレイヤーと繋がります。ホストも参加者も、接続後は NetworkSession オブジェクトを介してセッションに参加しているゲーマーと通信するという点は同じです。

コード1 (Win, Xbox 360)
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;

    public Test()
    {
        graphicsDeviceManager = new GraphicsDeviceManager(this);
        Components.Add(new GamerServicesComponent(this));
    }

    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);
        else if (state.Buttons.X == ButtonState.Pressed)
            sessions = NetworkSession.Find(NetworkSessionType.SystemLink, 1, null);
    }

    private void UpdateSession(GamePadState state)
    {
        text = "Network session is available\n";
        text += "B BUTTON: Dispose a network session\n\n";

        session.Update();

        foreach (NetworkGamer gamer in session.AllGamers)
            text += gamer.Gamertag +
                (gamer.IsHost ? ", HOST" : "") +
                (gamer.IsLocal ? ", LOCAL" : "") + "\n";

        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 実行結果

コード1は、ゲームを起動するとセッションを作成してホストとなるか、セッションを検索して参加するかを選択します。セッションを作成するか、セッションに参加することで得られた NetworkSession から、同じセッションに参加しているゲーマーを AllGamers プロパティから取得して表示します。

UpdateMenu() メソッドは、セッションの作成や検索を行うための処理を行います。UpdateSession() メソッドでセッションに参加している状態の処理を実行し、UpdateFindSession() メソッドでセッションの検索結果を表示する処理を実行します。Update() メソッドでは session フィールドが null でなければ有効なセッションに参加していると判断し UpdateSession() メソッドを呼び出します。そうでなければ sessions フィールドが null かどうかを調べ、null でなければ UpdateFindSession() メソッドを呼び出して検索結果の処理を実行します。

検索結果をリストとして表示し、プレイヤーにどのセッションに参加するかを選択させる流れも考えられますが、このプログラムでは検索結果から得られた最初のセッションに自動的に参加するように処理しています。