WisdomSoft - for your serial experiences.

11.1 セッションの作成

XNA Framework から Xbox LIVE に接続し、ユーザー同士を接続してリアルタイムに対戦や協力ができるマルチプレイ対応ゲームを作成できます。

11.1.1 マルチプレイ

XNA Framework が提供するネットワーク機能を使えば、Xbox LIVE アカウントでゲームにサインインしているプレイヤー同士を接続して、簡単に通信することができます。インターネットを介したグローバルな通信はもちろんですが、LAN で接続されているゲーム間で通信することも可能です。Windows 用のゲームと Xbox 360 用のゲームで通信することも可能です。

XNA Framework が提供するネットワーク機能は LAN 内のゲームを接続するシステムリンクと Xbox LIVE だけを対象としたもので、Web への接続はできません。生のパケットを扱えないため、独自のゲームサーバーを使ったオンラインゲームは作れません。よって、XNA Framework では MMORPG の開発は絶望的です。もちろん、Windows 専用ゲームであれば .NET Framework の通信機能を用いることで Web にアクセスできますが、この場合 Xbox 360 で実行することはできません。

Zune においても、Windows や Xbox 360 と同じように XNA Framework の通信機能を利用できますが、LIVE ネットワークをベースとした通信は行えません。近距離の Zune 同士を接続させるシステムリンクによる通信のみ可能で、Windows や Xbox 360 の XNA Framework ゲームとの通信はできません。本書内のサンプルコードは,主に Windows と Xbox 360 ゲームを通信させるために作られたものであり Zune での動作はサポートしませんが、Zune でも通信は可能です。

基本的に XNA Framework の通信機能は、テーブルゲームやアクションゲームの通信対戦に非常に適しています。IP やパケットを意識する必要がないので、プロトコルを意識せずにゲーム間の接続と通信に集中できます。LIVE ネットワークを介しているため、通信の品質やセキュリティなどもフレームワークに委ねられます。開発者は、他のプレイヤーの検索や接続、データの入出力といった部分に集中でき、泥臭い低水準な処理は XNA Framework に任せられるのが大きな利点です。

11.1.2 通信の仕組み

XNA Framework による通信は、ネットワークに接続しているプレイヤーの誰かが他のプレイヤーの親となるホストになるところから始まります。ホストは、他のプレイヤーが接続するのを待機するためにセッションと呼ばれる部屋を作成します。他のプレイヤーは、参加可能なセッションを検索し、得られた情報から参加するセッションを選択できます。

図1 セッション概念図
図1 セッション概念図

同じセッションに参加しているプレイヤー同士は、互いのゲーマータグを認識してデータを交換できます。このとき、ホストがサーバーになるといった制約はありません。ホストは、セッションの管理権限があるというだけで、ネットワークモデルがクライアントサーバーである必要はありません。セッションに参加しているすべてのゲーマーは、特定のゲーマーだけにデータを送信することも、全員にデータを送信することも可能です。アプリケーションによってクライアントサーバー型の通信も、ピアーツーピア型の通信も実現できます。

例えば、データは必ずホストに送信して、ホストによってデータを処理して他のプレイヤーに再送されるような制約を与えればクライアントサーバーモデルになります。一方、セッションに参加しているゲームが必要に応じて自由にデータを送受信し合う環境であれば P2P に近いネットワークモデルとなります。

11.1.3 セッション

LIVE ネットワーク上の他のプレイヤーと接続するには、セッションを作成してホストとなるか、セッションを検索してセッションに参加するかの 2 つの方法があります。セッションが存在しなければ、検索しても参加するべきセッションは見つかりません。まずは、誰かがセッションを作成しなければなりません。

セッションを作成するには Microsoft.Xna.Framework.Net.NetworkSession クラスを使います。

Microsoft.Xna.Framework.Net.NetworkSession クラス
public sealed class NetworkSession : IDisposable

このクラスの静的な Create() メソッドを呼び出すことで、新しいセッションを作成できます。このメソッドの呼び出すにはサインインが必須です。プレイヤーがサインインしていない状態で Create() メソッドを呼び出すと例外が発生します。このメソッド以外でも、ネットワークに関連する処理を実行するにはプレイヤーがサインインしている必要があります 。

NetworkSession クラス Create() メソッド
public static NetworkSession Create (
         NetworkSessionType sessionType,
         int maxLocalGamers,
         int maxGamers
)

sessionType パラメータには、セッションの種類を表す Microsoft.Xna.Framework.Net.NetworkSessionType 列挙型のいずれかのメンバを指定します。maxLocalGamers パラメータには、セッションに参加できるローカルゲーマー数を指定します。maxGamers パラメータには、このセッションに参加できる全体のゲーマー数を指定します。メソッドは、パラメータに指定された条件のセッションを作成し NetworkSession オブジェクトとして返します。

Microsoft.Xna.Framework.Net.NetworkSessionType 列挙型
public enum NetworkSessionType

この列挙型には、ネットワークへの接続を行わずに同じゲーム内の複数のプレイヤーで通信を行うことを表す Local メンバ、 LAN 内のコンピュータや Xbox 360 を接続することを表す SystemLink メンバ、Xbox Live によるインターネット経由で接続することを表す PlayerMatch メンバ、ランク付けによって実力の近いプレイヤーを接続する Ranked メンバが定義されています。Ranked メンバが表すランク付けは、商業タイトル向けに提供されるサービスなのでコミュニティゲームでは利用できません。Xbox Live Arcade ゲームの開発で使用できます。

テスト段階では SystemLink メンバを使ってセッションを作成し、LAN 上で複数の Windows PC や Xbox 360 を接続する方法が簡単でしょう。ゲーマーサービスを利用しているゲームは、同時に複数のプロセスを起動できないため Windows 用のゲームでも、複数台の PC を用意してテストする必要があります。

Create() メソッドは、セッションが作られるまで制御を返しません。多くの場合、セッションは一瞬で作られるため問題になることはありませんが、ネットワークの状態によっては時間がかかることもあります。一瞬でもゲームを停止させることが問題であれば、非同期メソッドである BeginCreate() メソッドと EndCreate() メソッドが用意されているので、こちらを使ってください。

セッション作成後にプレイヤーがサインアウトした場合、セッションは自動的に終了状態となります。他のプレイヤーと通信中だった場合、他のプレイヤーにとってはホストがゲームを終了させたように処理されます。

XNA Framework ゲームの開発者が、互いのセッションを認識するための通信や、セッションの情報を交換するといった、セッションの通信を管理するコードを書く必要はありません。セッションを維持するための処理は、セッションを更新する Update() メソッドの内部で行われます。

NetworkSession クラス Update() メソッド
public void Update ()

このメソッドは、セッションが他のゲームと正しく通信を行うために、常に呼び出され続けなければなりません。通常は Game クラスの Update() メソッドの工程で呼び出します。このメソッドが呼び出されなくなると、セッションが応答不能となってしいます。他のゲームからセッションが見つからなければ Update() メソッドが正しく呼び出されているかどうか調べてさい。

コード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 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
        {
            text = "A BUTTON: Create a network session\n";
            text += "B BUTTON: Dispose a network session\n\n";
            if (session == null)
            {
                if (state.Buttons.A == ButtonState.Pressed)
                    session = NetworkSession.Create(NetworkSessionType.SystemLink, 1, 16);
            }
            else
            {
                text += "Network session is available.";
                session.Update();
                if (state.Buttons.B == ButtonState.Pressed)
                {
                    session.Dispose();
                    session = null;
                }
            }
        }
        base.Update(gameTime);
    }

    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は、セッションを作成するだけの単純なプログラムです。セッションの作成にはサインインが必須なので、第 1 プレイヤーがサインインしていない状態であれば、強制的にサインイン画面を表示させ、それ以外の操作はできないように仕組んであります。

第 1 プレイヤーがサインインしている状態であれば、A ボタンを押してセッションを作成することができます。作成したセッションは B ボタンで破棄できます。定期的に NetworkSession オブジェクトの Update() メソッドを呼び出すことを忘れないでください。

このプログラムはセッションを作成しているだけなので、当たり前ですが誰かと通信を行うことはありません。他のゲームと通信するには、別のゲームからセッションを検索して参加する必要があります。