本記事はFIXERが提供する「cloud.config Tech Blog」に掲載された「Power Apps でゲームを作る~アニメーション編~ #Power Platformリレー」を再編集したものです。
こんにちは! Power Appsのキャンバスアプリの可能性を信じる男、サトハルです。
「Power Appsって何ができんの?」って聞かれたときには「意外となんでもできるよ」って答えてることにしています。
今回はそんなPower Appsの可能性を探るべく、本来の用途(ローコードDX)からほど遠いグラフィカルなゲームアプリの作成に挑もうと思います。
千里の道も一歩からということで、先ずはベーシックな「ブロック崩し」を作ります。
本記事ではそのなかでも更にベースになる「アニメーション」部分にフォーカスして解説をしたいと思います。
必要なコンポーネントを用意する
今回のアニメーションを作るにあたって必要なものは以下のようになります。
それぞれを詳しく見ていきましょう。
1. Container
普段はコンポーネントをまとめる用途で用いるContainerですが、今回はボールが跳ね返る枠としての役割を担っています。
Containerのなかに入っているコンポーネントはContainerのなかだけの座標系になるのがとても都合が良いです。
このことについては後で詳しく解説します。
また、BorderThicknessプロパティを5にしておくことで枠線を表現する役割も果たしています。
2. Circle
Power Apps標準の丸いアイコンです。
こいつのXとYプロパティに変数を指定することでボールの動きを表現しています。
ここで、先ほどContainerの所で触れた座標系についての補足をしたいと思います。
わかりやすいように一旦CircleのXとYを0にします。
すると、ScreenではなくContainerの端っこに表示されていることがわかります。
これが Container の中だけの座標系ということです。
「ボールの座標が0以上であれば少なくとも左と上にはみ出ることがない」と言い換えるととってもハッピーなことがわかりますね。
また、Circleのx,y座標はCircle コンポーネントの円を囲う四角形の左上の角の座標であることもわかります。
3. Label
今回は単純にボールの座標を表示しているだけです。
4. Timer
アニメーションの要となるコンポーネントです。
画面上のどこにおいてもいいですが、Visibleプロパティはfalseにしておきましょう。
ロジックを追加する
ボールが移動する仕組みは非常に単純です。
1. Timer コンポーネントが数えた周期毎にボールの速度変数を座標変数に足す
2. 「壁に当たった」と判定したら速度変数の符号を反転させる
この2つをx方向とy方向のそれぞれに行なえばOKです。
0. 事前準備
速度変数と座標変数はページを表示する瞬間に初期化します。
ScreenのOnVisibleプロパティ上でUpdateContext 関数を使って変数を設定しましょう。
今回は以下のように設定しました。
UpdateContext({
ball_vx:20,
ball_vy:10,
ball_posx:15,
ball_posy:20
});
1. Timer コンポーネントが数えた周期毎にボールの速度変数を座標変数に足す
Timerコンポーネントが数える周期はDurationプロパティで設定できます。
単位はミリ秒になります。
とりあえず今回は30にしておきました。
続いて、Timerコンポーネントが指定したカウントを数え終えた瞬間に実行される関数はOnTimerEndプロパティに書きます。
UpdateContext(
{
ball_posx: ball_posx + ball_vx,
ball_posy: ball_posy + ball_vy
}
);
ここでは本当に単純に足し算をしてるだけになります。
2. 「壁に当たった」と判定したら速度変数の符号を反転させる
OnTimerEndプロパティのなかに上記の内容に加えて、壁で反射する処理も追加します。
x軸に注目すると、まず左端に当たっているかどうかを判定します。
前述の通り、x座標が0未満であれば壁に当たっている(厳密にははみ出しているけど今回は簡単のためそれも良しとしています)と判定できます。
左端に当たっていない場合、続いて右端に当たっているかを判定します。
Circleのx座標は円の左端なので幅の分を考慮する必要があります。
また、上限はContainerの幅を使って指定すればよいでしょう。
左右どちらかに関係なく、当たっている場合は速度を反転します。
この一連の流れをy軸と上下の端に対しても行なえば壁で反転する仕組みの実装は完了です。
If(
ball_posx < 0,
UpdateContext({ball_vx: -ball_vx}),
If(
ball_posx + Circle1_1.Width >= Container1.Width,
UpdateContext({ball_vx: -ball_vx})
)
);
If(
ball_posy < 0,
UpdateContext({ball_vy: -ball_vy}),
If(
ball_posy + Circle1_1.Height >= Container1.Height,
UpdateContext({ball_vy: -ball_vy})
)
);
まとめ
簡単なロジックにしたがってアニメーションさせただけですが、それっぽい動きをしているのではないでしょうか。
Timerコンポーネントを非表示で追加する所はPower Apps特有って感じで面白い所です。
今回はボールを跳ねさせましたが、文字列を流したり画像を動かしたりもできるので意外と使いどころがあるかもしれません。
本記事でPower Appsの可能性を感じて頂けていたら幸いです(?)
(おまけ)
OnTimerEndプロパティの全文
UpdateContext(
{
ball_posx: ball_posx + ball_vx,
ball_posy: ball_posy + ball_vy
}
);
If(
ball_posx < 0,
UpdateContext({ball_vx: -ball_vx}),
If(
ball_posx + Circle1_1.Width >= Container1.Width,
UpdateContext({ball_vx: -ball_vx})
)
);
If(
ball_posy < 0,
UpdateContext({ball_vy: -ball_vy}),
If(
ball_posy + Circle1_1.Height >= Container1.Height,
UpdateContext({ball_vy: -ball_vy})
)
);
参考
Power Apps のタイマー コントロール – Power Apps | Microsoft Docs
佐藤 晴輝/FIXER
フロントからバック、ネットワークまである程度触れるガジェットオタクです。
好きな言語はC#でIoTと画像処理が得意です。