マイクロソフトの田中達彦です。
本連載では、Windowsストアアプリとして作成したパズルゲームである、Line Attackのプログラムを解説します。
Line Attack : http://apps.microsoft.com/webpdp/app/f11e327c-6228-4c8f-8245-ea57d65e0f09


[注意事項]
- この連載で提供するプロジェクトファイルは、サンプルとして提供しています。
- 毎回の記事で提供するプロジェクトファイルは、その時点でのソースコードです。最終バージョンのソースコードと異なる場合があります。


[今回のプロジェクトファイル]
それぞれのステージをクリアするまでに、何回ラインを動かしたかという回数と時間を記録しておき、もしそれらの記録を更新したらメッセージを表示させるようにしています。


[ハイスコア用フィールド]
ハイスコアを判定するためのデータとして、以下のようにラインの移動のカウントと、経過時間用のフィールドを用意します。

int MoveLineCount = 0;
int PreviousMoveLine = -1;

DateTime StartTime;
int MoveHighScore = 0;
TimeSpan TimeHighScore = new TimeSpan(0);

MoveLineCountには、現在プレイしているステージで、既に動かしたラインの数を代入します。
PreviousMoveLineには、直前に動かしたラインの番号を代入します。
もしユーザーが、1つ前に動かしたラインをもう一度動かしたときに、ラインを2回動かしたとカウントせずに、1回しか動かしていないことにするためです。
以下のコードは、縦方向にラインを動かしているときの判定の部分です。
押している宝石のX座標とPreviousMoveLineに入れている値が違うときだけ、ラインを動かした回数を+1しています。

if (PressedPieceX != PreviousMoveLine)
{
    MoveLineCount++;
    PreviousMoveLine = PressedPieceX;
}

横方向にラインを動かしているときは同じくPreviousMoveLineを使用していますが、PreviousMoveLineに20を足して横方向という目安にしています。

if (PressedPieceY + 20 != PreviousMoveLine)
{
    MoveLineCount++;
    PreviousMoveLine = PressedPieceY + 20;
}

このようなコードは、将来機能を追加したときにバグを誘発する可能性があるので、あまりお勧めできません。
きれいなコードとしては、PreviousMoveLineを縦方向と横方向の2つのフィールドに分けるのがよいでしょう。


[時間の計測]
Windowsストアアプリは、DateTimeという構造体で時間を表すことができます。
SetTimeメソッドで、以下のようにStartTimeフィールドに現在の時間を入れています。
DateTime.Nowは、現在の時間を示しています。

StartTime = DateTime.Now;

時間の計算は、TimeSpan構造体を使います。
以下はJudgeResultメソッドに記述しているゲーム開始からの経過時間を計算しているところです。
TimeSpan gameTime = DateTime.Now - StartTime;
ここでは、現在の時間から開始時の時間を引くことで、経過時間を計算しています。


[ラインの移動数と経過時間の表示]
ラインの移動数やハイスコアはDrawAllTextというメソッドで、プレイ中の経過時間はDrawTimeTextというメソッドで画面に表示させています。
時間を表示させているところは、以下のようにToString("000")というコードで実装しています。

textTime.Text = gameTime.TotalSeconds.ToString("000") + "sec";


int型などの数値を文字列に変換するためのメソッドとして、ToStringというメソッドが用意されています。

ToStringをそのまま使えば、数値を文字列に変換できます。
その引数を指定することで、特定のフォーマットの文字列に変更できます。
ここでは引数に"000"と指定することによって、3桁以上の文字列に変換しています。
数値が100以下の場合でも、百の位や十の位に0という文字列を入れた文字列を生成するのです。


[ハイスコアを記録する]
Windowsストアアプリは、アプリごとに独自の記憶領域を持っています。
その記憶領域には、ファイルのほかに何らかの値を覚えさせることができます。

以下のコードはSetPanelメソッドの中に追加した、記憶領域に書き込んだ値を読み込んでいる場所です。

value = AppData.LocalSettings.Values["Time" + StageNumber.ToString("0000")];
if (value == null)
    TimeHighScore = new TimeSpan(0);
else
    TimeHighScore = (TimeSpan)value;

value = AppData.LocalSettings.Values["Move" + StageNumber.ToString("0000")];
if (value == null)
    MoveHighScore = 0;
else
    MoveHighScore = (int)value;

AppDataは、以下のように定義しているフィールドです。

ApplicationData AppData = ApplicationData.Current;

ApplicationDataを使用するときには、using節にWindows.Storageも追加しておきます。

using Windows.Storage;

例えばステージ12の記録は、それぞれTime0012とMove0012という設定値として記録しています。
Valuesの後の[]に入る文字列は、自分で任意の文字列を設定できます。
ハイスコアを出したときの値は、JudgeResultメソッドで以下のように記憶させ、新記録であることを表示しています。

if (MoveHighScore == 0 || (MoveHighScore > MoveLineCount))
{
    textMove.Foreground = brushRed;
    AppData.LocalSettings.Values["Move" + StageNumber.ToString("0000")] = MoveLineCount;
    updateRecord |= 1;
}

TimeSpan gameTime = DateTime.Now - StartTime;
if(TimeHighScore.TotalMilliseconds == 0 || (TimeHighScore > gameTime))
{
    textTime.Foreground = brushRed;
    AppData.LocalSettings.Values["Time" + StageNumber.ToString("0000")] = gameTime;
    updateRecord |= 2;
}

if (updateRecord > 0)
{
    textRecord.Text = "New Record!";
    textRecord.Visibility = Windows.UI.Xaml.Visibility.Visible;
}


[前後の記事]
第5回 ステージの追加とアプリバーによる切り替え
第7回 日本語と英語への対応

マイクロソフト
田中達彦