次の方法で共有


Windowsストア アプリ 作り方解説 Line Attack編 第4回 ~点滅セルの設定と合否判定~

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

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

[今回のプロジェクトファイル]
今回公開するプロジェクトは、宝石を置くべきところの四角いセルの設定と、宝石が四角いセルの上にすべて乗ったかどうかの判定を行っています。
今回のプロジェクトを実行すると、宝石だけではなく点滅する四角が表示され、すべての宝石が同じ色の四角の上に乗ったときに点滅が速くなります。

[宝石を置くべき位置の設定]
ゲーム開始時の宝石の位置は、StageDataという配列に入れました。
宝石を置くべき位置として、新たにStageResultDataという配列を用意し、そこにデータを入れます。
第1回の記事で説明した宝石の位置のときと同様に、置くべき位置も文字列を使用して以下のように定義します。
そして、新たに作成したLineDataToStageResultDataというメソッドで、StageResultDataに変換しています。

lineData[0] = "++++++";
lineData[1] = "+2++2+";
lineData[2] = "++++++";
lineData[3] = "++++++";
lineData[4] = "+1++1+";
lineData[5] = "++++++";

LineDataToStageResultData(stage, lineData);

[点滅する四角の表示]
点滅する四角を表示させるために、ResultPieceというImageコントロールの配列を作ります。
以下はResultPieceを定義している部分です。

public const int MaxResults = 30;
public int ResultsCount = 0;
public Image[] ResultPiece = new Image[MaxResults];

現段階では点滅する四角の数の上限を30に設定していますが、最終版では36に変更しています。
ResultCountは、四角の数を入れるためのフィールドです。

このResultPieceをMainPanel上に配置するために、SetPanelメソッドに以下のコードを追加しています。

for (y = 0; y < MaxColumn; y++)
{
    for (x = 0; x < MaxColumn; x++)
    {

(中略)

        if (StageResultData[stage, x, y] != 0)
        {
            ResultPiece[ResultsCount].Source = PCBitmapImage[StageResultData[stage, x, y] + 10];

            Grid.SetColumn(ResultPiece[ResultsCount], x + MaxColumn);
            Grid.SetRow(ResultPiece[ResultsCount], y + MaxColumn);

            ResultPiece[ResultsCount].Visibility = Windows.UI.Xaml.Visibility.Visible;

            ResultsCount++;
        }
    }
}

for (i = ResultsCount; i < MaxResults; i++)
{
    ResultPiece[i].Visibility = Windows.UI.Xaml.Visibility.Collapsed;
}

6x6のセルを一つずつ調べていき、点滅する四角を置くべきときに行と列を指定して、画像データを表示させています。
表示させるとき、ResultPiece配列を順番に使用しています。
使用しなかったResultPieceについては、VisibilityプロパティにCollapsedを指定して、表示しないようにしています。

[四角を点滅させるには]
四角を点滅させる方法として、画像データの透明度を一定の間隔で変更する方法を使用しています。
一定の間隔で透明度を変更させるには、一定の間隔で呼ばれるメソッドを用意し、その中に透明度を変更するコードを実装します。
一定の間隔で呼ばれるメソッドを作るには、DispatcherTimerを使用します。
ここでは、以下のようにTimerというフィールドを作成しました。

DispatcherTimer Timer = new DispatcherTimer();

これだけではDispatcherTimerは動かないので、コンストラクターに以下の黄色くマーカーした部分を追加します。
追加するときに、真ん中の行を入力するときには、

Timer.Tick +=

と入力した後にTabキーを2回押すと、Timer_Tickというイベントハンドラーが自動的に生成されます。

public MainPage()
{
    this.InitializeComponent();

    Timer.Interval = new TimeSpan(0, 0, 0, 0, 33);
    Timer.Tick += Timer_Tick;
    Timer.Start();
}

このコードで、IntervalプロパティにTimeSpan(0, 0, 0, 0, 33)を代入しています。
TimeSpanが5つの引数を取るときは、第1引数から日にち、時間、分、秒、ミリ秒を設定します。
ここでは、33ミリ秒を設定しています。
Intervalプロパティに設定した間隔にしたがって、Timer_Tickが呼ばれます。
つまり、33ミリ秒ごとにTimer_Tickが呼ばれるように設定しています。

四角を点滅させるために、Opacityという透明度を設定するプロパティを使用します。
Opacityプロパティが1のときには全く不透明になり、画像データがそのまま表示されます。
Opacityプロパティが0.5のときは半分透明になり、背景が透けて見えます。
Opacityプロパティが0のときは完全に透明になるため、画像データが見えなくなります。

ここでは、以下のようにResultsOpacityというフィールドをつくり、そこに現在の透明度を入れます。
ResultsOpacityDirectionには、現在の透明度からTimer_Tickが呼ばれるたび、すなわち33ミリ秒ごとに変化する値を入れています。
初期値として-0.03が入っていますので、33ミリ秒ごとに透明度に-0.03が加えられます。

public double ResultsOpacity = 1;
public double ResultsOpacityDirection = -0.03;

Timer_Tickイベントハンドラーには、以下のコードを入れています。

void Timer_Tick(object sender, object e)
{
    int i;

    for (i = 0; i < ResultsCount; i++)
    {
        ResultPiece[i].Opacity = ResultsOpacity;
    }

    ResultsOpacity += ResultsOpacityDirection;

    if (ResultsOpacity < 0.2)
    {
        ResultsOpacity = 0.2;
        ResultsOpacityDirection = -ResultsOpacityDirection;
    }

    if (ResultsOpacity >= 1)
    {
        ResultsOpacity = 1;
        ResultsOpacityDirection = -ResultsOpacityDirection;
    }
}

表示されている四角の画像データのOpacityプロパティに、ResultOpacityの値を代入しています。
そして、ResultOpacityDirectionの値をResultOpacityに加算することにより、点滅しているように見せることができます。

[ゲーム完了の検知]
すべての宝石が同じ色の四角の上に乗ったかどうかの判定は、宝石を動かした直後であるGamePage_PointerReleasedで行っています。
コード上はJudgeResultという判定を行うメソッドを作り、GamePage_PointerReleasedからJudgeResultを呼んでいます。

private bool JudgeResult()
{
    int x, y;

    for (y = 0; y < MaxColumn; y++)
    {
        for (x = 0; x < MaxColumn; x++)
        {
            if((int)Piece[x + MaxColumn * 1, y + MaxColumn * 0].Tag != StageResultData[StageNumber, x, y])
                return false;
        }
    }

    ResultsOpacityDirection = 0.2;

    GameStatus = 2;

    return true;
}

6x6のマスを順番に判定していき、現在の宝石の位置と四角の位置が違っていたら速攻このメソッドを抜けます。
6x6のマスのすべての判定が一致していれば、ゲーム終了です。
そのときは、ResultOpacityDirectionの値を大きめの値にすることにより、点滅を速くさせています。

ここで、新たにGameStatusというフィールドを使用しています。

public int GameStatus = 0; // 0 - before game, 1 - gaming, 2 - game complete

GameStatusには、ゲームの状況を入れています。
0が入っているときは、ゲームを始める前の状況です。
ゲームを開始すると1を入れます。
ゲームが完了すると2を入れています。

このGameStatusはPointer系のイベントハンドラーの中でも使用し、ゲームが完了した後で宝石が動くことがないようにしています。

[その他の注意事項]
- 今回追加したMaxResultsのように、とりあえず値を入れてしまっているものがあります。最終的には、ちゃんとしたプログラムに修正しています。

[前後の記事]
第3回 宝石をちゃんと止める
第5回 ステージの追加とアプリバーによる切り替え

マイクロソフト
田中達彦
 

Pazzle_idea1_201301171759_judgement.zip