キャラクターに動きをつけよう!
鉄は熱いうちに打たないとやる気をなくしそう。
ということで連続でQiitaに前回の続きを書いてみます。
前回はコチラ。
是非見てくださいね♪
何だかんだ見ていただいたりすることは、とても嬉しいです!
今回は、キャラクターの動きを表現します。
キャラクターの動作について
今回の作成において、メインキャラクターの画像は下記の通り用意しております。
- characterの画像
Imageの名前 | 画像の種別 | メモ |
---|---|---|
front | 静止画 | 前向き |
back | 静止画 | 後ろ向き |
right | 静止画 | 右向き |
left | 静止画 | 左向き |
frontM | GIF画像 | 前向き |
backM | GIF画像 | 後ろ向き |
rightM | GIF画像 | 右向き |
leftM | GIF画像 | 左向き |
合計8件 ※命名ルールは読者の価値観で決めてください
動いているときは、GIF画像
動いていないときは、静止画
上記のような定義で決めていきます。
「動いている」という条件を定義する
さて、何をもって動いている状態
と定義するか。
Button コントロール
のPressed
という値で定義します。
Pressed – コントロールが押されている間は true 、それ以外の場合は false。`
※learnより
ゲームボーイのボタン押しっぱなしのような状態を、まさにキャラクターが動いていると定義します。
課題になるのはいつ
評価するか
Power Appsの処理は、Button コントロールを押す(OnSelect
)といったイベントがもとになります。
しかしながら押しっぱなしで、仮にGIF画像にデータを変更する、ということはできても、
継続的に動き続けるという表現は難しくなります。
これを可能にするコントロールをがTimer コントロール
です。
下記のブログが大変参考になります。
とてもPower Appsを中心に凄いアウトプットを沢山出されていらっしゃる方です。
二番煎じになりますが、荒っぽく書くと
メッチャ短いスパンでタイマー開始OnTimerStart
イベントを発火させて、高速で状態を評価し、動きを実現しているという方法です。
全く思いつかなかった方法なので、目から鱗でした👀💦
本当に参考になるので、是非上👆のブログを読んでいただきたいです。
Timer コントロールの設定
言葉だけだと、全く意味がわからないかもしれないので、プロパティ
を列挙します。
- Timerコントロール
プロパティ | 訳 | 値 |
---|---|---|
Duration | 期間 | 400 |
Repeat | 繰り返し | true |
AutoStart | 自動開始 | true |
OnTimerStart | タイマーの開始時 | 関数を記載 |
Duration
の部分は、1000 = 1秒と該当するので、
400 = 0.4秒です。
0.4秒繰り返し続けて、開始時に関数
が発火します。
この時の状態に応じて、関数が適用されるので、動きが達成されているわけです。
本当に良く思いつくなと圧巻でした💦
関数の部分
先にOnTimerStart
の関数を書きます。
長いです。
// ボタンコントロールのいずれかが真 trueの場合
Switch(true,
// 上ボタンを押している場合
ButtonUp.Pressed,
// _meという画像用の変数をGIF画像にアップデート、移動する方向を数値で決める
UpdateContext({_me:backM,Direction:-1});
// 動いた場合の値を先に求める
UpdateContext({_next:_index + Direction});
// メインキャラクターが動けない、またはギャラリーコントロールの総数より多いレコード数の場合
// 移動はできないとする
If(Or(_next in disableArea, _next > CountRows(maps)),
UpdateContext({_next:_index});
);
// 移動後と移動前の値が異なるとき
If(_next <> _index,
// 移動前のマスの画像を無色透明の画像にする
Patch(moves,
First(Filter(moves,index=_index))
,
{obj:_null}
);
// 移動後のマスにキャラクターのGIF画像にする
Patch(moves,
First(Filter(moves,index=_next))
,
{obj:_me}
);
// 移動前を表す変数を移動後の値に変更する
UpdateContext({_index:_next});
),
// 上記のコメント同様 左バージョン
ButtonLeft.Pressed,
UpdateContext({_me:leftM,Direction:-8});
UpdateContext({_next:_index + Direction});
If(Or(_next in disableArea, _next > CountRows(maps)),
UpdateContext({_next:_index});
);
If(_next <> _index,
Patch(moves,
First(Filter(moves,index=_index))
,
{obj:_null}
);
Patch(moves,
First(Filter(moves,index=_next))
,
{obj:_me}
);
UpdateContext({_index:_next});
),
// 上記のコメント同様 右バージョン
ButtonRight.Pressed,
UpdateContext({_me:rightM,Direction:8});
UpdateContext({_next:_index + Direction});
If(Or(_next in disableArea, _next > CountRows(maps)),
UpdateContext({_next:_index});
);
If(_next <> _index,
Patch(moves,
First(Filter(moves,index=_index))
,
{obj:_null}
);
Patch(moves,
First(Filter(moves,index=_next))
,
{obj:_me}
);
UpdateContext({_index:_next});
),
// 上記のコメント同様 下バージョン
ButtonBack.Pressed,
UpdateContext({_me:frontM,Direction:1});
UpdateContext({_next:_index + Direction});
If(Or(_next in disableArea, _next > CountRows(maps)),
UpdateContext({_next:_index});
);
If(_next <> _index,
Patch(moves,
First(Filter(moves,index=_index))
,
{obj:_null}
);
Patch(moves,
First(Filter(moves,index=_next))
,
{obj:_me}
);
UpdateContext({_index:_next});
)
);
コメントに書きましたが整理すると
- ボタンを押している場合
- _meという画像用の変数をGIF画像にアップデート、移動する方向を数値で決める、
そして動いた場合の値を先に求める - メインキャラクターが動けない、またはギャラリーコントロールの総数より
多いレコード数の場合、移動はできないとする - 移動後と移動前の値が異なるとき、
- 移動前のマスの画像を無色透明の画像にする
- 移動後のマスにキャラクターのGIF画像にする
- 移動前を表す変数を移動後の値に変更する
といったコトを行っています。
合わせて変数を解説すると以下の通りです。
変数 | 型 | メモ |
---|---|---|
_me | Image | メインキャラクターの画像 |
_obj | Image | メインキャラクター以外のマスの画像 |
_index | 数値 | メインキャラクターの位置 |
_next | 数値 | 動いた場合に位置する場所 |
move | コレクション | 画像とインデックスを制御 |
disableArea | 配列 | 移動できない数値の配列 |
大事な部分であるPatch関数
Patch関数は、コレクションの更新のために利用しています。
UpdateContext関数だけでは、ギャラリー内の画像に変化は起きません。
都度Patch関数
を使うことでギャラリーによる、表現を達成しているという論理になります。
静止画に戻す
それぞれのボタンのOnSelect
には、下記の様な関数を書いています。
// 画像を静止画にする
UpdateContext({_me:back});
// ギャラリーを更新する
Patch(moves,
First(Filter(moves,index=_index))
,
{obj:_me}
);
これで動きのStopが表現できます。
OnSelect
とOnTimerStart
の評価のタイミングは非同期です。
別々のタイミングで評価され、関数が発火します。
こういった関数をそれぞれのButton コントロールに配備することで実現しているわけですね。
高速でイベントを起こすってなんじゃそりゃ!? と書きながら改めて驚愕ですが、
これが実現できるPower Apps最高です!
改めて動画を紹介
キャラクターはそれぞれ、マス目に合わせて配備しています。
動けない部分はdisableArea
に配置したりと、結構力業になってます・・・が、
実現できることが何よりうれしい!
ということで、Power Apps RPG紹介 を締めくくりたいと思います!
それでは皆様!良いPower Lifeを!