XNA Framework の最大の売り文句は Windows と Xbox 360 とのクロスプラットフォームですが、すべてにおいて同じコードが通用するわけではありません。確かに、大部分は同じコードで同じ振る舞いを期待できますが、Windows と Xbox 360 では、システムの性能や基盤となっている .NET Framework のサポート範囲が大きく異なります。
Xbox 360 では、Xbox 360 用にカスタマイズされた .NET Compact Framework が用いられています。よって、Windows と Xbox 360 の双方のプロジェクトで同じコードをビルドする場合、.NET Compact Framework の範囲しか使うことができません。Windows のリッチな .NET Framework すべての機能を使う場合は、コードを Windows 用に書き加える必要があるでしょう。
より大きな問題はパフォーマンスです。Xbox 360 は、ゲームに特化したハードですが、Windows PC のような汎用性はありません。一方の Windows PC は、個体差が大きく、極めてスペックが低いものから、Xbox 360 を優に凌ぐ最新のマルチコア CPU と GPU を装着しているハイエンド機まで存在します。スペックの低い PC では、複雑な効果処理を省略するなどの対策が必要になります。こうした判断を行うには、ゲームを実行するシステムの情報が必要になります。
Windows 用のプロジェクトと Xbox 360 用のプロジェクトでコードが大きく異なる場合は、それぞれのプロジェクトで個別にソースファイルを用意した方が簡単です。しかし、XNA Framework が提供する機能は、マウスなどの一部を除いて Windows と Xbox 360 で共通なので、コードの大部分は同じになるでしょう。数行の違いのためにソースファイルを別に用意するのは、管理の都合上、効率的ではありません。修正を重ねるうちに、どちらか一方のコードが古くなってしまうのは火を見るより明らかです。このような場合は、プリプロセッサを使った条件付きコンパイルや、ゲームの実行環境で処理を分岐させる方法が便利です。
同一のソースコードの一部を Windows PC と Xbox 360 で分けるには、コンパイル時に判断する方法と、実行時に判断する方法に分けることができます。多くの場合は、プリプロセッサ ディレクティブを使ってコンパイル時に処理した方が効率的です。特に、Windows のみで使えるクラスやメソッドを呼び出しているコードは Xbox 360 用のプロジェクトではビルドできないため、条件付きコンパイルでプロジェクトごとに分別する必要があります。例えば、Windows 向けのゲームの場合にのみ、Windows フォームと組み合わせてウィンドウにメニューバーを追加するようなコードを書くときに有効です。
Xbox 360 用のプロジェクトには、XBOX 及び XBOX360 というシンボルが定義されています。#if ディレクティブで XBox 360 用のプロジェクトかどうかを調べ、コンパイルするコードを決定できます。
#if XBOX360
//Xbox 360 専用コード
#else
Windows 専用コード
#endif
これは、コンパイルするコードを決定するもので、実行時に判定されるものではありません。これによって、ソースファイルの一部分を Windows 用のコードと
Xbox 360 用のコードで分けて書くことができます。
■ Sample01
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
public class Test : Microsoft.Xna.Framework.Game
{
private GraphicsDeviceManager graphics;
private SpriteBatch sprite;
private SpriteFont font;
private string text;
public Test()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
#if XBOX360
text = "This code is for Xbox 360.";
#else
text = "This code is for Windows PC.";
#endif
}
protected override void Initialize()
{
sprite = new SpriteBatch(GraphicsDevice);
base.Initialize();
}
protected override void LoadContent()
{
font = Content.Load<SpriteFont>("TestFont");
base.LoadContent();
}
protected override void UnloadContent()
{
Content.Unload();
base.UnloadContent();
}
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);
}
static void Main(string[] args)
{
using (Test game = new Test()) game.Run();
}
}
■ 実行結果

Sample01 は、条件付きコンパイルを使って Windows 用のプロジェクトと Xbox 360 用のプロジェクトで text フィールドに文字列リテラルを代入する文を切り替えています。実行結果は Windows で実行したスクリーンショットですが、Xbox 360 で実行した場合は "This code is for Xbox 360." が表示されます。
実行時の判定
プリプロセッサ ディレクティブによるコードの分岐は、ビルドに評価されるものです。実行時に if 文で判定するのに比べ、コンパイル時にコードを決定していた方が効率的です。Windows 用のゲームと Xbox 360 用のゲームは、異なるプロジェクトとしてビルドしなければならないため、特に理由がない場合は、上記の条件付きコンパイルでコードを分けるべきです。
しかし、実行時にシステムの情報を取得する方法も .NET Framework によって用意されています。システムの名前やバージョンを詳細に取得し、それによって処理を分岐させたい場合に必要です。同じ Windows でも XP や Vista などのバージョンの違いがあります。また、実行している .NET Framework の共通言語ランタイムのバージョンも存在します。こうした情報を取得し、if 文で実行するコードを分岐させることができます。
実行環境の情報は .NET Framework の System.Environment クラスの OSVersion プロパティが返す OperatingSystem オブジェクト
から取得します。OperatingSystem クラスは、アプリケーションを実行しているシステムのプラットフォームやバージョンを提供します。これらの機能は XNA Framework でもサポートされているため、Xbox 360 でも使えます。
■ Sample02
using System;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
public class Test : Microsoft.Xna.Framework.Game
{
private GraphicsDeviceManager graphics;
private SpriteBatch sprite;
private SpriteFont font;
private string text;
public Test()
{
graphics = new GraphicsDeviceManager(this);
Content.RootDirectory = "Content";
text = Environment.OSVersion.Platform + " ver " + Environment.OSVersion.Version + "\n";
text += "Processor Count: " + Environment.ProcessorCount + "\n";
text += "CLR Version: " + Environment.Version + "\n";
}
protected override void Initialize()
{
sprite = new SpriteBatch(GraphicsDevice);
base.Initialize();
}
protected override void LoadContent()
{
font = Content.Load<SpriteFont>("TestFont");
base.LoadContent();
}
protected override void UnloadContent()
{
Content.Unload();
base.UnloadContent();
}
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);
}
static void Main(string[] args)
{
using (Test game = new Test()) game.Run();
}
}
■ 実行結果

Sample02
は、プラットフォームの種類とバージョン、プロセッサ数、共通言語ランタイムのバージョンをテキストで表示するプログラムです。このプログラムは、ビルド時ではなく実行時にシステムの情報を取得するため、システムの詳細情報を取得して表示することができます。Xbox 360 で実行した場合は、次のような結果が得られます。
Xbox ver 2.360.0
Processor Count: 6
CLR Version: 3.5.7318.0
この結果から、Xbox 360 でも実行時に動的にシステムの情報を得られていることが確認できます。
プラットフォームの種類は、PlatformID 列挙型で表されます。この列挙型には、Unix や WinCE メンバなども用意されていますが、XNA Framework ゲームで返される値は、事実上 Win32NT または Xbox のいずれかです。
Environment クラスの ProcessorCount プロパティは、プロセッサの数を返します。現在のようなマルチコア CPU が主流の時代には、プロセッサの数によってスレッド数を変更するなど、並列処理を導入することでパフォーマンスの改善を期待することができます。近い将来、一般的なデスクトップ PC でも 4 コア、8 コアが当たり前になることが想定されます。Xbox 360 の CPU は 3 コアのマルチコアで、各コアは 2 スレッドを実行することができます。そのため、Xbox 360 で Sample02 を実行するとプロセッサ数に 6 が得られます。