<前文>
今週は、日本人の英語と韓国人の英語と中国人の英語の違いについてちょっとだけ語りたいと思います。最近、BLM運動で日本人も英語で結構な議論をしているのをネットのあちこちで見かけました。それぞれに色々な立場や考え方がある中でかなり激しい議論を日本人同士が英語で議論しているのをみて、正直「あれ、日本人ってこんなに英語得意だったっけ?」とかなり驚きました。
それは別にいいのですが(因みに私が作っている英語の音素の区別がつくゲームはそういう在米何十年のレベルの方でも、小学生の時に移民しない限りは聞き分けられない微妙な音素の区別が、遊んでいるだけで誰でも出来るようになる滅茶苦茶凄い効果のあるゲームです。)議論している人の中に日本人じゃないのに日本人として参加している人がいました。その人が書く英語を読んですぐに分かりました。日本人の英語と韓国人の英語と中国人の英語って同じようでかなり違う部分があるんです。
まあ、私は傍観者(あくまで日本人同士の不毛な議論に対しての傍観者という意味です。BLM運動自体は勿論支持しています。)だったのでどうでも良かったんですが、その議論している人の誰もがその事に気が付かないのはどうなの?とちょっと思ってしまいました。
アメリカに何十年住んでもbとv の区別が付かない人もいますから、どんなに英語が上手くなっても、日本人の英語と韓国人の英語と中国人の英語の違いが分からない人もいるんでしょうね。ネットでバトルするなら相手の素性は怪しいと思うべきで、それを確認する方法は研究しておくべきでしょう。
一個だけ簡単な例をここで公開します。中国人の場合ですがuから始まる単語がaなのかanなのかの区別が出来ません。日本人なら中学生でアイウエオはan、それ以外ならaと覚えると思います。のでunderdogならアンダードックだからan、unicornならユニコーンだからaと英語学習の初心者でも間違える事はほとんどありません。これが中国人の英語になると相当な上級者でもuの前のaとanは間違えていたりします。
まあ、こんな感じである程度は書かれている英語から相手の素性を見極める技術もネットでバトルするなら磨いておいた方がいいんじゃない。とお節介ながら思いました。
それでは今週の勉強を始めます。
<本文>
1. 先週の直し
1. テキストがボックス内に表示されるようにする。
今のテキストは表示された文字が消える事はありません。ので最終的には文字がボックスからはみ出してしまいます。“読みましたボタン”を押したら、表示されている文章は消えるように変更します。
まあ、簡単ですが、これで“読みましたボタン”を押したら、表示されている文章は消えるようなりました。ただこれだけだと次の文章の最初が、2段目から始まるようになるのでそれも直します。
文章が終わったら、段落を変えるようにします。これだけです。
テストします。
“読みましたボタン”を押しました。
消えていますね。
2. テキスト文の推敲など
コメント欄に表示される文章が微妙におかしいです。
以下に示したのは最初の画面ですが、次のフェーズに移行するためには、プレイヤーは攻撃、魔法、道具、逃げるの4つのボタンから選択する必要があります。
しかし、青色のテキストボックスでは、“KUMOは次の行動を考えています。”とだけ表示されていて、プレイヤーが具体的に何をすれば良いのかは分かりません。
「プレイヤーは攻撃、魔法、道具、そして逃げるのどれかを選択してください。」ぐらいは表示されないと意味不明になりますね。
よし、そのセリフを表示させましょう。
やり方は簡単です。
RPGGameModeBaseBPのEventBeginMakeDecisionの最後に以下の部分を付足します。
ただしGameCharacterクラスのisPlayer変数はBPからアクセス出来ないので以下のように変更しました。
ビルドします。
テストします。
綺麗に表示されていますね。
攻撃ボタンをクリックします。
あれ?ボタンの表示が何か変ですね。どうしたんでしょうか?
以下にボタンの作成方法を示します。
これを見ると、攻撃対象のモンスターを表示するwidgetを作成する時に、パラメーターとして変数をパスしていません。その直後に変数にアサインしています。この少しの差がボタンを作成した時に敵のモンスターの名前が分からない事態を生んでいると思います。
以下のように作り替えてみました。
これで試してみます。
今度はゴブリンと表示されました。
2. TextBoxの更なる改良
やっている事は1.と変わらないんですが、先週の直しではないので新しい節に変えました。
1.RPGGameModeBaseBPのReportExecuteAction()が実行された後も“読みましたボタン”を押すまでは先のフェーズに進まないで待ってほしい。
まず、GameCharacterクラスのExecuteAction() 関数の実装を以下のように変えました。
更に、RPGGameModeBaseBPのEventReprotExecuteActionに
以下に示したコードを追加しました。
一応、理論上はこれで良いはずなのでテストします。
文章の表示が止まっています。戦闘のフェーズも停止しているようです。
“読みましたボタン”を押します。
今度は、ゴブリンのアクションに対しての報告が表示されました。
うん。出来ているみたいです。
ここまで見てるとCombatEngineのIDecisionMakerクラスとICombatActionクラスを分ける必要があるのか疑問になって来ました。一個のクラスにしてCombatUIWidgetに継承させればもっと簡単にBPとUEC++を繋げられそうな気がします。
2. 戦闘終了時のコメントが表示されない。
今度はこれを追加します。
現状、戦闘が終了した時には以下のコメントがログに表示されています。
この関数を、以下に示すようにRPGGameModeBaseクラスのTick()関数内から呼びます。
この関数を、以下に示すようにRPGGameModeBaseクラスのTick()関数内から呼びます。
GameOverの場合はfalse、Victoryの場合はtrueをパスします。
以下に示すように、RPGGameModeBaseBP内でReportFightIsOver()関数の実装を行います。
単に、勝った時は、勝ちました。負けた時は負けましたとコメント欄に表示されるようにしただけです。
テストします。
何も表示されずに戦闘が終わってしまいました。
これは多分ですが以下に示すRPGGameModeBaseクラスのTick()関数内のコードが先に実行されたせいでしょう。
更に関数と変数を追加して“読みましたボタン”をクリックするまでこれらのコードが実行されないようにしましょう。
まず、RPGGameModeBaseクラスに以下の関数と変数を
追加しました。
HadReadFightIsOver()関数は以下に示したように実装しました。
変数は、TestCombat()関数内で、以下に示したように
Assignしました。
更にTick()関数内を以下に示したように改造しました。
最後にRPGGameModeBaseBPのEventReportFightIsOverの実装を以下に示したように変えました。
EventReportFightIsOverはパラメーターとしてCharacterをパスしないのでRPGGameInstanceBPクラスからMyYourHeroをSelectedCharacterとしてセットします。更に最後にEvent confirm button is clicked にバインドした全てのイベントを外します。
これで戦闘が終わった後の結果についてのコメントが青色のコメント欄に表示されるはずです。
テストします。
敗北したと表示されました。そして“読みましたボタン”をクリックすると
GameOver画面に映りました。完璧ですね。
今度は勝利した場合をテストします。YourHeroClassesのDataシートの値を以下に示したように
変えてテストします。
今度はKUMOは勝利しました。
勝利した後は何事もなかったかのようにゲームが続行されます。
完璧に機能していますね。
3. もう少しだけ文章の推敲
かなり良くなったのですが、もう少しだけ良くしたいです。
戦闘中は青色のボックスには以下に示したようなコメントが表示されています。
- 戦闘が開始しました。
- KUMOは次の行動を考えています。
- (プレイヤーは攻撃、魔法、道具、逃げるから一つを選択してください。)
と一気に表示されています。
- 戦闘が開始しました。
のみが表示される。
“読みましたボタン”をクリック。
- KUMOは次の行動を考えています。
- (プレイヤーは攻撃、魔法、道具、逃げるから一つを選択してください。)
が表示される。
“読みましたボタン”をクリック。
が表示される。
位の方が分かり易いですね。
“”は次の行動を決定しました。ですね。
これは簡単に直せるので今直してしまいます。
直しました。
決定した行動が何なのかもっと具体的な内容がほしいですね。「KUMOはゴブリンへ攻撃した。」みたいな。ついでに言えば、攻撃してどうなったのかの情報もほしいです。例えば「ゴブリンは10のダメージを受けた。」と言った感じです。
そういう意味では「KUMOは次の行動を決定しました。」も「KUMOはゴブリンを攻撃する事を決定しました。」の方が分かり易いですね。
最後の勝利した後ですが、「金貨を何枚得た」とか「宝箱が取れた」とかの情報もほしいですね。
金貨とかアイテムのInventory systemはこのプロジェクトでは作成していませんが、表示位は出来る様にしたいです。
4. 推敲した部分を直していく
4.1 戦闘開始の部分の直し
結構考えましたが以下の方法でやって見ます。
まず、RPGGameModeBaseクラスのTick()関数をFightIsStartIsRead変数がtrueの時だけ実行されるようにします。
勿論、FightIsStartIsRead変数をtrueにする関数も作成します。
今度は、UE4Editorに移り、UIWidgetの真ん中の部分(以下の図で選択されている箇所)が表示されない様にします。
最後に“読みましたボタン”を押したらFightIsStartIsRead変数をtrueにする関数が呼ばれるようにします。
この方法だと“読みましたボタン”を押すたびにFightIsStartIsRead変数をtrueにする関数が呼ばれますが、多少動作が遅くなる意外は問題ないので、取りあえずはそのままにしておきます。
それではテストします。
戦闘が開始してもプレイヤーが選択出来るボタンは表示されていません。“読みましたボタン”を押します。
プレイヤーに攻撃、魔法、道具、逃げるから一つを選択して下さいとコメント欄に表示されると同時に攻撃ボタン、魔法ボタン、道具ボタン、そして逃げるボタンが表示されました。
3.では、コメント欄に「プレイヤーは攻撃、魔法、道具、逃げるから一つを選択して下さい。」と表示されてから“読みましたボタン”を押したら、攻撃ボタン、魔法ボタン、道具ボタン、そして逃げるボタンが表示と書きましたが、これも良い感じなのでこのままにします。
次のターンも問題なく続いています。
出来ました。
4.2 「KUMOは次の行動を決定しました。」を「KUMOはゴブリンを攻撃する事を決定しました。」に変える。
いきなり「KUMOはゴブリンを攻撃する事を決定しました。」に変更するのは大変なので、以下のように変更してみました。
攻撃ボタンがクリックされた場合、以下に示されたコードが実行されます。
更に、対象になるモンスターを選択した場合、AttackTargetOption widgetより以下のコードが実行されます。
テストします。
攻撃ボタンを押すと以下のようなコメントが追加されます。
更に攻撃対象としてゴブリンを選択すると
が追加表示されます。
全体としては以下のような文章になっています。
まだまだ推敲が必要ですね。しかしこういう状況によって表示するコメントが変わる場合のもっと根本的な仕組み自体を考える必要がある気がするのでこの辺で止めておきます。
4.3「KUMOはゴブリンへ攻撃した。」みたいな具体的な行動の内容をコメントする。
現状、行動を実行した場合のコメント欄での説明は以下のようになっています。
これに
- “KUMO”は“ゴブリン”に攻撃した。
- “ゴブリン”は10のダメージを受けた。
のような表現を追加したいです。
一見すると「“KUMO”は“ゴブリン”に攻撃した。」の方が簡単そうですが、「“ゴブリン”は10のダメージを受けた。」はUE4C++のコードでダメージを与えてる箇所からBlueprintImplementableEventな関数を呼べば良いだけなのでこちらを先にやります。
ムムム…
キャラクターにダメージを与えているUE4C++のコードを見つけたら、Combat Engine内のTestCombatActionクラスの関数でした。Combat Engineは単なるC++で書かれたengineなのでUE4C++の機能を使用してBlueprintImplementableEventな関数を作成する事は出来ません。
ちょっと考えます。
こんな感じで作ってみました。
まず、二つの関数をRPGGameModeBaseクラスとGameCharacterクラスにそれぞれ作成しました。
RPGGameModeBaseクラスに作成したBlueprintImplementableEventな関数、ReportCharacterHPisDamaged()。
GameCharacterクラスに作成した単なるC++の関数、ReportDamageHPtoRPGGameModeBase()。
まず、TestCombatActionクラスのBeginExecuteAction()関数内でCharacterにダメ―ジが発生したら、以下に示めすように
ダメージが発生したキャラからReportDamageHPtoRPGGameModeBase()関数を呼びます。
ReportDamageHPtoRPGGameModeBase()関数は、RPGGameModeBaseクラスのBlueprintImplementableEventな関数、ReportCharacterHPisDamaged()を呼びます。
最後にRPGGameModeBaseBP内にReportCharacterHPisDamaged()の実装を行いました。
テストします。
出来ましたね。
何かBPとUE4C++と生のC++の正しい関係が見えて来ました。後できちんとまとめますが、忘れないためにちょっとだけここにも書いて置きます。
まず生のC++とBPですが関係を持つ事は出来ません。この二つが連絡したり一緒に行動したりするためには必ずUE4C++の助けが必要になります。UE4C++とBPは関係を持つ事が出来ますが、その関係は対等ではなく政府(government )と一般人(people)みたいな上下の存在する関係です。UE4C++からBPへの連絡はほとんどが命令ですがBPからUE4C++に命令する事はほとんど出来ません。その唯一の例外がBlueprintImplementableEventを使用した関数で、これはBPで指定した内容をUE4C++で実行します。なのでC++からBPに連絡したりBPからC++に命令したりするためには、ちょっとした工夫が必要になります。
うん。これだけ書いておけば後で忘れる事はないでしょう。残りはこのブログの最後でまとめます。
今度は、「“KUMO”は“ゴブリン”に攻撃した。」を表示させます。
以下の方法で試してみます。
まず、新しい変数CommentForExecteActionをWidgetUI内に作成します。
WidgetUI内のAttackedButtonがクリックされた時、
以下に示されたコードが実行されます。
これにより「“敵のモンスター名”を攻撃した。」と言うコメントがCommentForExecteAction変数内に保持されます。
更にRPGGameModeBaseBP内でEven tReportBeginExecuteActionが発生した時に、
以下に示したコードが実行されるようにしました。
これにより、プレイヤーがコントロールするキャラが行動を実行した場合のみ、「“プレイヤーの操作しているキャラ名”が“敵のモンスター名”を攻撃した。」とコメント欄に表示されるはずです。
テストします。
「“KUMO”がゴブリンを攻撃した。」と具体的に表示されるようになりました。
敵のモンスターに関してはどのような攻撃をするかなどはまだ全くかんがえていませんので、このままにしておきます。
これで一応3.で述べた部分は直し終わりました。
5.「…した。」と「…ました。」を統一します。
以下に示したように「…した。」と「…ました。」が適当に使用されています。全て「…ました。」に統一します。
直しました。
こちらの方が読みやすいですね。
6. “読みましたボタン”を必要な時だけ表示させる。
これ結構重要なんですが、今まで忘れていました。
まず、“読みましたボタン”を押したら、必ず“読みましたボタン”の表示は消えるようにしました。
次にRPGGameModeBaseBPの全てのBindEventtoConfirmButtonIsClickedノードの前にボタンを表示するようにしようとしたら
RPGGameModeBaseBPからConfirmedButtonもSetVisiblity関数も呼び出せませんでした。
のでWidgetUI内で以下に示した関数
を作成してその関数をRPGGameModeBaseBPから呼び出しました。
テストします。
戦闘が開始しましたが“読みましたボタン”が表示されています。ので“読みましたボタン”をクリックします。
“読みましたボタン”が消えて、代わりに4つの攻撃、魔法、道具、そして逃げるボタンが表示されました。
攻撃を選び、ゴブリンを選択すると上記のコメントが表示され更に“読みましたボタン”が表示されました。
全部記録しても意味がないので残りは書きませんが、最後まで上手く行きました。
今週の予定していた部分はもう終わってしまいましたがまだまだ時間が空いているのでどうしようかと思っています。
3. C++とUE4C++とBPの関係についての考察
2.の4.3で少しだけ書きましたが、C++とUE4C++とBPの関係がイメージとして具体化出来たのでそれをここにまとめる事にします。
UE4でゲームを作成する時に、BPで作成するのが良いのかUE4C++で作成するのが良いのかの議論がありますが、UE4C++の方が速く処理出来る以外の有効な情報がなくて、結局どっちでも良いんじゃないみたいな話になってしまっています。このイメージを理解すると、この問題についてもある種の解決策を得る事が出来ると思います。
まず、UE4C++とBPの関係ですが対等ではありません。上下関係があります。UE4C++が上でBPが下です。政府(government )と一般人(people)に例えるとしっくりします。UE4C++が政府(government )で、BPが一般人(people)です。政府(government )は一般人(people)に命令出来ますが、一般人(people)は政府(government )に命令出来ません。一般人(people)が政府(government )に対して出来るのは基本的にはお願いだけです。
同じ関係性がUE4C++とBPにもあります。UE4C++はBPに命令出来ますが、BPからUE4C++には命令は出来ません。唯一の例外は今週使用したBlueprintImplementableEventな関数で、これはBP側からUE4C++にこれをやれと命令出来ます。出来ますが、この関数でさえいつどこで行うのかはUE4C++側が決定します。
現実の世界でも一般人(people)が政府(government )に命令出来る時は僅かですがあります。例えば110番や119番通報は、必ず警察や消防車が駆けつけなければならないのでお願いではなく命令です。ただしこれはどちらかと言えばBlueprintCallableな関数と同じで、BPから呼び出せますが、やる内容はBP側で決定する事は出来ません。
更にUE4C++ではBPに特別な関数を追加したり、基本的な関数を使用させないようにしたりする事も出来ます。これも政府(government )が特定の人々だけに特別な許可(医者が医療行為を出来る。など)を与えたり、特定の人々の権利を制限したり(犯罪者を刑務所に収容とか)するのに似ています。
次に生のC++とBPの関係ですが、生のC++ はBPと関係を持つ事は出来ません。BPに何か命令したい場合はUE4C++を通す必要があります。これは何でしょうか?国連か何かに似ていると思えばそこそこしっくりしそうですね。国連が治安維持部隊を派遣したいと思ってもあなたに直接、従軍しろと命令は出来ませんよね。まあ日本では絶対ないでしょうが、国連が政府に命令してその命令に基づいて政府があなたに従軍するように命令する感じでしょうか?
このイメージは結構、C++とUE4C++とBPの関係を正確に表している気がします。例えばあなたが原っぱで野球を友達とやるとします。政府に許可を貰いますか?貰わないですよね。つまり原っぱで友達と野球をするようなプロジェクトはBPのみで作成した方が良いと言う事です。では、貴方が近所の池にブラックバスを放して繁殖させたいと思った時はどうでしょうか?これがその池を管理している役所にお願いして許可をもらうとか、ひょっとすると議会で新しい法律を作成してもらう必要があるかも知れませんし、そういう政府との交渉をしないといけないでしょうね。これをゲーム制作に例えると、UE4が基本的には提供していない機能を追加する時や、UE4に元々ある機能を停止したいときだと思います。このようなゲームを制作する場合はUE4C++から作成すべきとなります。
最後にC++で作成した流体のシミュレーションをUE4を使って可視化したい。何で場合は、まさしく国連と政府とあなたの関係みたいになるんでしょうね。
今週はC++(combat engine)とUE4C++とBPを行ったり来たりしていたのでこんなイメージが具象化したのだと思います。正直この説明が一番分かり易いと言えるほど自信はありません。社長、部長、一般社員(貴方)で説明した方が分かり易い気もしています。部長は貴方に命令出来ますが、貴方が部長に対して出来るのはお願いだけです。しかし貴方が社長にお願いする事で、社長が部長に命令して、間接的ですが、貴方が部長に命令する事も出来ます。みたいにまとめた方が分かり易いかもしれなかったです。BlueprintImplementableEventな関数だって実際は実装をBP側で行うだけで、その実装を工夫する事で、BPからUE4C++に命令するような事を実現しているわけですから。
このアイデアは今まで誰も考えた事がない事なので内容が粗削りなのは仕方ないかもしれません。これから精製して発展させたいと思います。
4. コメント欄のセリフの管理方法について
Treeを使った管理が必要
コメント欄のセリフですが、攻撃、魔法、道具、逃げるの4択からそれぞれ更に細分化された選択が存在しその一つ一つに対応したセリフがあります。これらのセリフを個別に管理する事は不可能です。一か所でエクセルのようなフォーマットで管理しないといずれどのセリフがどこにあるのかが分からなくなります。
ここで思ったのですが、エクセルで管理するよりもUE4のAIみたいなTreeを使用した管理の方が更に分かり易いと思いました。分岐に分岐を重ねる訳ですからエクセルでも最後は追えなくなる可能性がありそうです。UE4のAIみたいなTreeを使用した管理ならその見やすさから後から直す時に混乱して訳わからなくなる事が起きないと思いました。
5. まとめと感想
今週はコメント欄に表示するテキストを表示するためのプログラミングを作成しました。普段より結構多めにやったように見えますが実際にはより少ない時間で終わりました。来週はこれにアニメーションを追加します。