8月, 2011 のアーカイブ

C#とXnaでxmlファイルを読み込むにはSystem.xml内のクラスをを使う事もできますが、xnaにはコンテントパイプラインを使い、xmlの読み込みと書き込みをほぼ自動に行う機能が付いているので、それについてメモります。

*注意:大熊猫は英語版のVisual Studio 2010を使っているので、説明と画像には英語の部分が偶にあります。

 

コンテントパイプラインを使ってのxml操作は、IntermediateSerializerを使うと楽に出来ます。IntermediateSerializerには、xmlの書き込み時に自動的にオブジェクトの内容をコンテントパイプラインに合わせた書き方をしてくれるという利点があります。読み込み時にも、最短1行で読み込めると言う利点があります。

 

IntermediateSerializerを使うにはまず、プロジェクトにMicrosoft.Xna.Content.Pipelineを足す必要が有ります(プロジェクト内の参照を右クリックして ”Add Reference…”を選択)。もし.NETのタブ内に見つからない場合、dllを直接探して足してください(私の場合はC:\Program Files\Microsoft XNA\XNA Game Studio\v4.0\References\Windows\x86 に有りました)。

Dllを足したら、プロジェクトのプロパティを開き、「アプリケーション」のタブ内で、”Target Platform”を “.Net Framework 4 Client Profile” から”.Net Framework 4”に変更してください。この設定を変更しないとIntermediateSerializerを使えないので、必ず変えてください。

プロジェクトの設定を変更し終えたら、まずxmlに保存するクラスを書きます。


class Person
{
public Vector2 Position;
public string Name;
int m_id;

public Person()
{
this.Position = Vector2.Zero;
this.Name = "";
this.m_id = -1;
}

public Person(Vector2 position, string name, int id)
{
this.Position = position;
this.Name = name;
this.m_id = id;
}

public int ID
{
get { return m_id; }
set { m_id = value; }
}

//-----ココから保存されない------//

public int GetOnlyID
{
get { return m_id; }
}

public int SetOnlyField
{
set { }
}
}

xmlに保存するクラスには幾つか注意するところがあります:

–          必ずパラメーター無しのコンストラクタが必要

–          メンバ変数は、Public設定以外は保存されない

–          アクセサはGetとSetの両方がある場合のみ、保存される

 

次は実際にxmlファイルにPersonクラスのインスタンスを保存します:


string fileName = "test.xml";
string filePath = System.IO.Directory.GetCurrentDirectory() + "\\" + fileName;
Person person = new Person(new Vector2(100.0f, 25.0f), "Ookumaneko", 100);

System.Xml.XmlWriterSettings setting = new System.Xml.XmlWriterSettings();
setting.Indent = true;

using (System.Xml.XmlWriter writer = System.Xml.XmlWriter.Create(fileName, setting))
{
                // xmlファイルに書き込む
IntermediateSerializer.Serialize<Person>(writer, person, filePath);
}

これでIntermediateSerializer.Serializeメソッドの第3引数で設定したパスにxmlファイルが作られます:


<?xml version="1.0" encoding="utf-8"?>
<XnaContent>
<Asset Type="XmlTest.Person">
<ID>100</ID>
<Position>100 25</Position>
<Name>Ookumaneko</Name>
</Asset>
</XnaContent>

次は書き込んだxmlファイルの読み込みです。これには二つの方法が有ります。まずはIntermediateSerializerを使用した方法です:


string fileName = "test.xml";
string filePath = System.IO.Directory.GetCurrentDirectory() + "\\" + fileName;
Person person;

System.Xml.XmlReaderSettings setting = new System.Xml.XmlReaderSettings();
using (System.Xml.XmlReader reader = System.Xml.XmlReader.Create(filePath, setting))
{
// xmlを読み込み、保存する
person = IntermediateSerializer.Deserialize<Person>(reader, null);
}

次はコンテントパイプラインを使用し、テクスチャアなどの読み込みと同じ方法です。この方法を使うには、プロジェクト上のコンテントプロジェクトにxmlファイルの追加してください。この方法を使用しての読み込みをするには、コンテントプロジェクトに読み込むクラスがあるプロジェクトに参照を通す必要が有ります。その際、プロジェクトが一つしかない場合、コンテントパイプラインとゲームプロジェクトがお互いを参照しあう事になるので、新たなプロジェクトを作る必要が有ります。(もっと楽な方法があるかただいま検索中・・・)


Person person = Content.Load<TestLib.Person>("test.xml");

テストプロジェクト:
http://www.mediafire.com/download.php?a40q8t24ae2uszj

このメモはXNA3.1とVisual Studio 2008でXBOX 以外のコントローラーを使う方法を説明します。

XNAではXinputでサポートされている種類以外のコントローラー(例えばPS2コントローラー)は使えません。コレにより、PC用のゲーム開発はマウス、キーボード、XBOX用コントローラに限定されるので少し面倒になります。それを解決するには基本的に、3種類の方法があります。

–          SlimDX等のライブラリを使う

–          Managed Directx(Direct Input)を使う

–          XBOX 360コントローラーのエミュレーターを使う

このメモでは、外部ライブラリを何となく使いたくなかったのでManaged Directxを使用しての再利用性のあるクラスを作る方法を残します。

 

まず、プロジェクトにMicrosoft.DirectX.DirectInputSystem.Windows.Formsの参照を足してください(System.Windows.FormsはMicrosoft.DirectX.DirectInput.Deviceクラスを初期化するために必要です)。

参照を足した後はまず、コントローラーへの参照を得るための初期化コードを書きます:

Device _pad;
JoystickState _padStates;

// 接続されている全てのゲーム用入力デバイスを獲得する
DeviceList deviceList = Manager.GetDevices( DeviceClass.GameControl, EnumDevicesFlags.AttachedOnly );

//接続されているジョイパッドを探し、保存する

foreach ( DeviceInstance i in deviceList )
{
_pad = new Device( i.InstanceGuid );
if ( _pad )
break;
}

もしコントローラーの参照を得られれば、アナログスティックの戻り値の最高値を決めます:

// アナログスティックの戻り値の最高値を決める
foreach ( DeviceObjectInstance devObjIns in pad.Objects )
{
if ( ( devObjIns.ObjectId & (int)DeviceObjectTypeFlags.Axis ) != 0 )
    {
_pad.Properties.SetRange(ParameterHow.ById, devObjIns.ObjectId, new InputRange( -100, 100 ) );
}
}

デバイス(コントローラー)の設定を終了し、デバイスへのアクセスを取得します:

// セットアップ
_pad.Properties.AxisModeAbsolute = true;
_pad.SetCooperativeLevel( window.Handle, CooperativeLevelFlags.NonExclusive | CooperativeLevelFlags.Background );
_pad.Acquire();

コントローラーの設定が終了した後、フレーム毎にコントローラの状態を更新し、保存するのを忘れないようにしてください(これが入力判定に使われるので):

public void Update()
{
 _pad.Poll();
 _padStates = _pad.CurrentJoystickState;
}

入力のテスト:


if ( _padStates.GetButtons()[0] != 0 )
{
  message = "ボタン 0 が押されています"
}

コレで動かすための基本的な事は終わりですが、この時点でプログラムを実行すると例外が投げられ、ちゃんと動きませんでした。

この例外はMDA(Managed Debugging Assistant)の一部に有るLoaderLockによって投げられたものです。詳しい事は今のところわからないのですが、この例外はManaged Directxが原因みたいです。この例外を回避するには、Visual Studio上でLoaderLockを無効にします。無効にするにはメニュー上から「デバッグー>例外・・・」に行き、LoaderLockの部分のチェックを外します。

これらが全て終わったら、動くはずです(今の所PS2コントローラーでのみ確認済み)。

 

ちなみに、コントローラー用のクラスを書いた時に実際に行った作業は結構省きましたので、クラスの中身に興味が有る方はプロジェクトへのリンク置いておくので(主にバックアップ用ですが)見てみてください。あと、プロジェクト内に有るクラスは複数のコントローラーをサポートする用に書きましたが、実際にコントローラーが一つしか無かったので、今の所はテストしていません。

プロジェクトへのリンク:

http://www.mediafire.com/download.php?ew06bbiz08drcp9

追記:sourcecodeと/sourcecodeを使用してソースコード貼り付けた時のインデント方法を知っている方が居たらコメントください m_ _m