PowerAppsでバトルゲームを作ろう！（その２：戦闘画面）

# 前回記事
こちらをどうぞ！
[PowerAppsでバトルゲームを作ろう！（その１）](https://qiita.com/rnakamuramartiny/items/bffe2aa96e7989949c98)

# ダメージ計算式の設計
バトルゲームっていうのは、相手に攻撃した時の
ダメージ量によりHPを削っていき、最終的に相手のHPを0にした方が勝ち
というルールです。
したがって、画面を作る前にダメージ計算式を設計する必要があります。

## ダメージ(ATP)算出計算式
自分の攻撃力=OAP
自分の防御力=ODF
自分の運=OLK
敵の攻撃力=EAP
敵の防御力=EDF
敵の運=ELK
攻撃時補正値倍率(RTM)=OLK-ELK （0以下の場合は0.5）
ATP = (OAP-EDF) + (乱数（0~5）×RTM)

## 素早さの使い道
こちらは先行・後行の判定で使用します。
※命中率の計算式でも使えると思いますが割愛。

# では、引き続き作っていきます！

## 戦闘画面(Battle_Screen)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/269159/6277cc55-19aa-70e3-9c4f-fb7d8ae3a70e.png)

### 変数の作成
この画面で作成する変数は以下の通りです。

|変数名|変数種別|説明|初期値|
|:--|:--|:--|:--|
|1P_Current_HP|UpdateContext|1Pの現在HP|1P_MAX_HP|
|2P_Current_HP|UpdateContext|2Pの現在HP|2P_MAX_HP|
|1PTurn|UpdateContext|1Pのターンかどうか|1P_SPD>2P_SPD:true|
|2PTurn|UpdateContext|2Pのターンかどうか|2P_SPD>=1P_SPD:true|
|1P_Rand_Times|UpdateContext|1PのRTM|※計算式参照|
|2P_Rand_Times|UpdateContext|2PのRTM|※計算式参照|
|1P_Attack_Ponit|UpdateContext|1PのATK|Blank()|
|2P_Attack_Ponit|UpdateContext|2PのATK|Blank()|

変数はBattle_ScreenのOnVisibleプロパティにて宣言します。

```bash:Battle_Screen(OnVisible)
UpdateContext({'1P_Current_HP':1P_MAX_HP,'2P_Current_HP':Var_2P_Max_HP});
If(1P_SPD>2P_SPD,UpdateContext({'1PTurn':true,'2PTurn':false}),UpdateContext({'1PTurn':false,'2PTurn':true}));
UpdateContext({'1P_Rand_Times':If((1P_LCK-2P_LCK)<0,0.5,(1P_LCK-2P_LCK))});
UpdateContext({'2P_Rand_Times':If((2P_LCK-1P_LCK)<0,0.5,(2P_LCK-1P_LCK))});
UpdateContext({'1P_Attack_Ponit':Blank(),'2P_Attack_Ponit':Blank()})
```

## 1P画面の作り方
![image.png](https://qiita-image-store.s3.amazonaws.com/0/269159/3ce5e5e0-6826-760c-1e8d-3e095e13df0d.png)

###①HP表示エリア（1P_HP_Display）
ここは以下のように設定します。

```bash:1P_HP_Display(Text)
If('1P_Current_HP'>0,Round('1P_Current_HP',0)&"/"&1P_MAX_HP,"0/"&1P_MAX_HP)
```

###②HPゲージ（1P_HP_Gage）、(1P_HP_Gage_Frame)
現在HPが減るにつれて、最大HPとの割合をゲージにて表現します
また、HPが50%未満で色が黄色に
HPが30%未満で赤色という感じで表現しています。

ここは実は二つのオブジェクトが存在しています。
外枠で使用する1P_HP_Gage_Frameと
実際の表示部分である1P_HP_Gageです。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/269159/ff37e3ae-44bd-b2df-f3d1-aa1a12e76125.png)

実際に様々な関数を入れていくのは、1P_HP_Gageになります。
関数を入れるプロパティはHeight,Width,X,Y,Fillの5つです。

```bash:1P_HP_Gage(Height)
'1P_HP_Gage_Frame'.Height-('1P_HP_Gage_Frame'.BorderThickness*2)
```

```bash:1P_HP_Gage(Width)
('1P_HP_Gage_Frame'.Width-('1P_HP_Gage_Frame'.BorderThickness*2))*('1P_Current_HP'/1P_MAX_HP)
```

```bash:1P_HP_Gage(X)
'1P_HP_Gage_Frame'.X+('1P_HP_Gage_Frame'.BorderThickness)
```

```bash:1P_HP_Gage(Y)
'1P_HP_Gage_Frame'.Y+('1P_HP_Gage_Frame'.BorderThickness)
```

```bash:1P_HP_Gage(Fill)
If(('1P_Current_HP'/1P_MAX_HP) >= 0.5,LightGreen,
	If(('1P_Current_HP'/1P_MAX_HP) >= 0.3,Yellow,Red))
```

###③1P攻撃ボタン（1P_ATK_Button）
このボタンこそ、まさにバトルシステムの演算コントロールそのものとなります。
押せるのは、1P_TurnがTrueの時のみです。
また、1Pもしくは2PのHPが0以下になったら非表示にする必要があります。
なので、Visible及びOnSelect　の2つのプロパティを設定します。

```bash:1P_ATK_Button(Visible)
If('2P_Current_HP'<=0,false,If('1P_Current_HP'<=0,false,'1PTurn'))
```

```bash:1P_ATK_Button(OnSelect)
UpdateContext({'1P_Attack_Ponit':(1P_PWR-2P_DFS)+Round((Rand()*5)*'1P_Rand_Times',0)});
If('1P_Attack_Ponit'>0,UpdateContext({'2P_Current_HP':('2P_Current_HP'-'1P_Attack_Ponit')}),"");
UpdateContext({'1PTurn':false,'2PTurn':true})
```
####補足説明
1行目で、ATK値を算出しています。
Rand関数は0~1の数値からランダムで設定されますので、これを5倍すると0~5の数値からランダムで設定されることになります。
なお、Round関数を使用したのは、整数に丸めないと数値が小数点10何位までになってしまうため割合が非常に多岐に渡ってしまう為です。
2行目で、2Pの現在HPから算出したATKを引いています。ただし、ATKは0以下になる場合がありますのでその場合は何もしないように設定しています。
3行目でターンを1Pから2Pに切り替えます。

## 2P画面の作り方
1P画面と一緒です。

## メッセージウィンドウ（Battle_Message）
この部分です。
![image.png](https://qiita-image-store.s3.amazonaws.com/0/269159/9739d648-80b7-53c7-609e-afed7887c3cd.png)

こちらは単純なラベルを使っていて、Textプロパティに関数をセットしています。
ダメージが15以上は会心の一撃と表現しています。
また、ダメージが0以下の場合はダメージを与えられないという表現もしています。

```bash:Battle_Message(Text)
If(And(IsBlank('1P_Attack_Ponit'),IsBlank('2P_Attack_Ponit')),"",
	If('1P_Current_HP'<=0,"2Pの勝利！",
	If('2P_Current_HP'<=0,"1Pの勝利！",
	If(And('1P_Attack_Ponit'>15,'2PTurn'),Concatenate("1Pは2Pに会心の一撃！2Pは",Text('1P_Attack_Ponit',"[$-ja-JP]####"),"のダメージ"),
	If(And('1P_Attack_Ponit'>0,'2PTurn'),Concatenate("1Pは2Pにこうげき！2Pは",Text('1P_Attack_Ponit',"[$-ja-JP]####"),"のダメージ"),
	If(And('1P_Attack_Ponit'<=0,'2PTurn'),"1Pは2Pにダメージを与えられない！",
	If(And('2P_Attack_Ponit'>15,'1PTurn'),Concatenate("2Pは1Pに会心の一撃！1Pは",Text('2P_Attack_Ponit',"[$-ja-JP]####"),"のダメージ"),
	If(And('2P_Attack_Ponit'>0,'1PTurn'),Concatenate("2Pは1Pにこうげき！1Pは",Text('2P_Attack_Ponit',"[$-ja-JP]####"),"のダメージ"),
	"2Pは1Pにダメージを与えられない！"))))))))
```

## 戦闘終了ボタン(Battle_End_Button)
![image.png](https://qiita-image-store.s3.amazonaws.com/0/269159/55ac8f8a-0947-26d2-4de0-647dfb737000.png)
1Pもしくは2PのHPが0以下になれば戦闘は終了になり表示されます。
なので、Visible及びOnSelectプロパティを設定します。

```bash:Battle_End_Button(Visible)
If('2P_Current_HP'<=0,true,If('1P_Current_HP'<=0,true,false
```

```bash:Battle_End_Button(OnSelect)
Navigate('Player_Param_Set',ScreenTransition.Cover)
```

これで、戦闘画面の作成は完了です！

# まとめ
ゲーム作るの楽しいですｗｗｗｗｗ
というか意外に戦闘システムっていうのを作るのが結構大変なんだというのが分かって
結構有意義になったこと。
そして、ゲーム作りを通して、PowerAppsの作成技術がさらに上がった！（ような気がする・・・）

# そして伝説（カスタマイズ）へ・・・
<blockquote class="twitter-tweet" data-lang="ja"><p lang="ja" dir="ltr"><a href="https://twitter.com/hashtag/Powerapps?src=hash&amp;ref_src=twsrc%5Etfw">#Powerapps</a> のみで<a href="https://twitter.com/hashtag/%E3%83%90%E3%83%BC%E3%82%B3%E3%83%BC%E3%83%89%E3%83%90%E3%83%88%E3%83%A9%E3%83%BC?src=hash&amp;ref_src=twsrc%5Etfw">#バーコードバトラー</a><br><br>バーコードの読み取り形式を変えて認識率を上げたのと<br>計算式を変更して、いい感じのバトルになるように変えてみました。<br><br>今は攻撃しかできないので防御とか薬草とかも入れてみたいですが、そこまでいくとノンコーディングと言えるか怪しいかも。 <a href="https://t.co/t4AWJH5fNM">pic.twitter.com/t4AWJH5fNM</a></p>&mdash; りなたむ@steed400 (@R_t_A_n_M) <a href="https://twitter.com/R_t_A_n_M/status/1038780809866428416?ref_src=twsrc%5Etfw">2018年9月9日</a></blockquote>
<script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>