コルネの進捗や備忘録が記されたなにか

進捗や成果物や備忘録てきななにかを雑に更新していきます。

【Power Apps】ボンバーマンを作ってみよう! ステージを作成する


スポンサードリンク

本ブログは【Power Apps】ボンバーマンを作ってみよう! プレイヤーを配置するの続きとなります。
まだ上記記事を見ていない方は先にそちらをみることをお勧めします。

このセクションで紹介すること

このセクションではステージの作成を行いたいと思います。
今回のゴールは、ステージを作成し、前回のブログで作成したキャラクターがステージの地形にあわせて移動できるようにするところまで作成したいと思います。

1. ステージを画面上に配置する

まずはステージの素材を読み込みたいと思います。
前回と同じように、アプリが開かれたら用意していたSVGが読み込まれるようにします。
AppのOnStartに以下のように記載します。

App.OnStart

// 地形イメージのロード 
ClearCollect(_Obj, 
{ID:0, href:"'data:image/png;base64,....'"},
{ID:1, href:"'data:image/png;base64,....'"},
{ID:2, href:"'data:image/png;base64,....'"},
{ID:3, href:"'data:image/png;base64,....'"}
)

IDに対応したステージの素材イメージは下記のようにしています。

ID イメージ
0 ステージ内にある破壊不能ブロック
1 ブロック
2
3 ステージ外にある破壊不能ブロック

もし、素材を自身で用意される方は、上記を参考に作成して頂ければと思います。

続いて、上記イメージを用いて、ステージを構成していこうと思います。
Screen1のOnVisibleにて下記のようにステージの構成を設定します。

Screen1.OnVisible

ClearCollect(stage, 
{ID:1, X:0, Y:0, Width:48, Height:48, type:3}, 
{ID:2, X:48, Y:0, Width:48, Height:48, type:3}, 
{ID:3, X:96, Y:0, Width:48, Height:48, type:3},
...
{ID:223, X:576, Y:476, Width:48, Height:48, type:3}, 
{ID:224, X:624, Y:476, Width:48, Height:48, type:3}, 
{ID:225, X:672, Y:476, Width:48, Height:48, type:3} 
)

それぞれの要素について簡単に説明したいと思います。

要素 解説
ID ステージの通し番号になります。
後に使用します。
X 対象のイメージのX座標の値になります。
Y 対象のイメージのY座標の値になります。
Width 対象のイメージの幅になります。
Height 対象のイメージの高さになります。
type 対象のイメージの表示される画像になります。
_ObjのIDに対応しています。

それでは作成したコレクションを実際に画面に表示していきましょう。
「挿入」より、「ギャラリー」を選択して、「縦方向(空)」選択します。
アイテムには先ほど作成した"stage"を使用します。
名前はわかりやすいように"StageGallery"としておきましょう。

ステージは真ん中に表示させたいため、以下のように設定します。

StageGallery.X

Screen1.Width / 2 - StageGallery.Width / 2

StageGallery.Y

Screen1.Height / 2 - StageGallery.Height / 2 - 5

"StageGallery.Y"にて、"-5"としているのは微調整のためです。

続いて「[挿入]ペインから項目を追加」を選択して、「挿入」>「メディア」>「画像」を選択し、画像をギャラリー内に追加します。
画像のImageには、上記で設定した画像を設定したいため以下のように設定します。

Image1.Image

"data:image/svg+xml;utf8, " & EncodeUrl(
    "
    <svg version='1.1' id='Layer_1' xmlns='http://www.w3.org/2000/svg' xmlns:xlink='http://www.w3.org/1999/xlink' x='0px' y='0px' width='32px' height='32px' viewBox='0 0 32 32' enable-background='new 0 0 32 32' xml:space='preserve'>  <image id='image0' width='32' height='32' x='0' y='0'
    href=" & LookUp(_Obj, ID = ThisItem.type).href & "/>
</svg>
    "
)

これで、画像が表示されたかと思います。

次に、画像が指定した座標に表示されるように設定したいと思います。
ギャラリー内の画像を指定した座標に表示するために、TemplateSize=0の手法を用いたいと思います。
こちらの手法について、@h-nagaoさんがQiitaにて解説を行っているわかれば簡単! #PowerApps のTemplateSize=0の手法が大変わかりやすいと思いますので、是非参考にしてください!

まずはギャラリーの設定を変更していきます。
StageGalleryを選択してそれぞれ下記のように設定します。

StageGallery.TemplateSize

0

StageGallery.TemplatePadding

0


次にギャラリー内にある画像の設定を変更していきます。
Image1を選択してそれぞれ下記のように設定していきます。

Image1.X

ThisItem.X

Image1.Y

Mod(15 - ThisItem.ID, 15) + ThisItem.Y

Image1.Width

ThisItem.Width

Image1.Height

ThisItem.Height

Yについてのみ、設定してある数値をそのまま使用していませんが、これはギャラリーのTemplateSizeを0に設定しても、0にはならず1になってしまうためです。
そのため、補正のためにこのような式となっております。

これでステージの設定ができました!

2. キャラクターをステージの地形に合わせて移動できるようにする

まずはキャラクターの位置をギャラリー内に設定しようと思います。
その前に、キャラクターのイメージをステージより前面に設定しましょう。
ツリービューよりPlayerImageの「・・・」を選択して「再配置」>「最前面へ移動」を選択します。
そしてPlayerImageを以下のように設定します。

PlayerImage.X

_playerX + StageGallery.X - PlayerImage.Width / 8

PlayerImage.Y

_playerY + StageGallery.Y

こうすることで、ステージの左上端から2マス目に配置されたかと思います。

しかしこのままでは、プレイヤーがステージ外へ移動することができてしまいますし、ブロックなども無視して移動できてしまいます。
なので、次はプレイヤーの行動範囲を制限したいと思います。
UpButtonのOnselectのプレイヤーが移動するための処理を以下のように変更します。

UpButton.Onselect

If(CountIf(
    Filter(stage, RoundDown(_playerX / 48, 0) * 48 = X ||
                  (RoundDown(_playerX / 48, 0) + RoundUp(Mod(_playerX, 48) / 100, 0)) * 48 = X,
                  RoundDown((_playerY - 12) / 48, 0) * 34 = Y ||
                  (RoundDown((_playerY - 12) / 48, 0) + RoundUp(Mod((_playerY - 12), 48) / 100, 0)) * 34 = Y),
    type <> 2) = 0,
    UpdateContext({_playerY:_playerY - 12})
);

急に複雑な式になってきましたね...
順番に解説を行っていきます。
まずは"Filter"部分の解説です。
Filterはstageに対して行っています。問題のフィルター対象ですが、

RoundDown(_playerX / 48, 0) * 48 = X ||            
(RoundDown(_playerX / 48, 0) + RoundUp(Mod(_playerX, 48) / 100, 0)) * 48 = X

こちらでは、X座標に対するフィルターを行っています。
上の式はなんとなくわかるかと思います。現在のマスのX座標を取得していますね。
下の式は、プレイヤーが2マスにまたがっているときのための判定式です。
ボタンを1回押したときは、12だけ座標が変わるようにしていたかと思います。
そのため、プレイヤーが2マスにまたがっているときは2マス分の座標を取得して判定してあげる必要があります。

続いて、Y座標に対して行っているフィルターをみてみましょう。

RoundDown((_playerY - 12) / 48, 0) * 34 = Y ||
(RoundDown((_playerY - 12) / 48, 0) + RoundUp(Mod((_playerY - 12), 48) / 100, 0)) * 34 = Y)

X座標に対するフィルターの式と似ていますが、"- 12"が追加されていますね。
こちらは上ボタンを押したとき、プレイヤーは上に移動するので、その移動後の座標をフィルターするために追加しています。

CountIf(
    Filter(stage, RoundDown(_playerX / 48, 0) * 48 = X ||
                  (RoundDown(_playerX / 48, 0) + RoundUp(Mod(_playerX, 48) / 100, 0)) * 48 = X,
                  RoundDown((_playerY - 12) / 48, 0) * 34 = Y ||
                  (RoundDown((_playerY - 12) / 48, 0) + RoundUp(Mod((_playerY - 12), 48) / 100, 0)) * 34 = Y),
    type <> 2) 

こちらでは、フィルターされた結果の"type"が2以外の数をカウントしています。
"type"が2以外...つまりマップが床以外のものをカウントしています。
移動先が床以外であれば移動してはいけないので、"Countif() = 0"のときのみ移動するようにしています。

同様に下、右、左についても上記のような変更を施します。
参考までに、右の変更を記載しておきます。

RightButton.Onselect

If(CountIf(
    Filter(stage, RoundDown((_playerX + 12) / 48, 0) * 48 = X ||
                  (RoundDown((_playerX + 12) / 48, 0) + RoundUp(Mod((_playerX + 12), 48) / 100, 0)) * 48 = X,
                  RoundDown(_playerY / 48, 0) * 34 = Y ||
                  (RoundDown(_playerY / 48, 0) + RoundUp(Mod(_playerY, 48) / 100, 0)) * 34 = Y),
    type <> 2) = 0,
UpdateContext({_playerX:_playerX + 12})
);

こちらはX軸に移動するので、X座標のフィルターに"+ 12"の式がありますね。

以上でステージの作成は終了です!
お疲れさまでした!!
ここまでの作成で、以下のような画面になっているかと思います。

f:id:koruneko:20200308112115p:plain

おまけ
バ美肉してPower Apps の当たり判定の実装方法についての紹介動画を作成しました!
まだまだ至らない点が多々あるかと思いますが、是非見て頂けると嬉しいです。
もしよろしければ、ご意見・ご相談や、チャンネル登録、高評価して頂けると幸いです。

youtu.be


スポンサードリンク