UE4の勉強記録

UE4の勉強の記録です。個人用です。

「Unreal Engine 4.xを使用してRPGを作成する」の足りない部分を作成する 新しい機能を追加する2

f:id:kazuhironagai77:20200830201127p:plain

<前文>

Vtuberは新たな日本の輸出品になれるのか?

先週初めてvtuberを見ましたがこんなに面白い物とは思いませんでした。「絵が動いて声優がしゃべっているだけでしょう。」と思っていましたし実際そうなんですが、受ける印象が全く違います。何が違うのかと言うとアイドルと一緒に遊んでいる錯覚に捕らわれるんです。しかもVRと比較にならない位の没入感があります。

こんなの日本だけじゃなくてアメリカでも大受けだろうと思ったら実際に英語をしゃべるvtuberも結構いるみたいです。ただ私が調べた限りではアメリカのマッチョ信仰のせいなのか、英語圏vtuberは総じてアイドル感が足りない感じでした。何か女戦士と冒険してる感じでした。これならアメリカ人も日本のvtuberを見ると思います。

そしたら既にバイリンガルvtuberなる存在がある事を知りました。日本語と英語をチャンポンで話し英語しか分からなくてもアイドル(vtuber)と一緒に遊んでいる錯覚が失われない様にしています。更に英語圏の視聴者からは本物の日本語の勉強にもなる。との評価まで出ています。もうこれは自動車に代わる新たなmade in Japanの主力輸出品になるんじゃないのかと期待すらしています。

ただ一気に現実に引き戻される場面もありました。それはあるvtuber英語圏ではかなりsensitiveな内容をペロッと言った時に、共演していたバイリンガルvtuberが滅茶苦茶焦って、結局そのセリフだけ英語に訳さないでやり過ごしたのを見た時でした。勿論vtuberは可愛いのでそういう内容をしゃべっても全然許さる場合が多いかもしれませんし、本人が信念を持って発言している場合は、無理に意見を変える必要もないです。しかし英語圏におけるsensitiveな内容は知っておいた方が無駄な争いは避けれますし、場合によっては触れない方が賢明だとの判断もつけられます。

私は機械学習や深層学習をバカにしていましたが、実際はそれらの技術のおかげで自動翻訳技術、並びに自動朗読技術が格段に向上しています。英語の全くしゃべれない日本人vtuberでもこれらの翻訳機を使用して英語でアメリカ人と会話出来る日は直ぐそこまで来ています。その時に問題にならないように10年アメリカに住んでいた私が知る限りでアメリカ文化におけるsensitiveな話題を集めてみました。

人間として扱ってもらえないLevel

  • 犬を虐める。(猫は問題ない)
  • 馬を食べる。クジラを食べる。(牛、豚は問題ない。馬刺しを食べたよ。は言ってはいけない。)
  • ロリコン(アニメを見る人もここに分類される場合があるので注意!最悪警察に捕まる可能性も)
  • 人種差別的な発言、行動を取る。

二度と口を聞いてもらえないLevel

  • 軽はずみに人種差別されたと断言する。
  • 羨ましい時にenvyを使用する。憎らしい相手にGod damn youと言うなど。(十戒に相手を妬んではいけない。憎んでもいけない。と書かれているせいか、アメリカ人は妬まれたり、憎まれたりする事に慣れていない。非常に嫌がる。)
  • 性的なジョークを言う。
  • 奴隷制などの触れてほしくない話題を振る。(政治、宗教、人種も含む。)
  • 英語を間違える。
  • 怒る、怒鳴る。(最悪警察に逮捕される。上司が部下に怒鳴るのも×。)

顔には出さないが内心凄い嫌がっているLevel

  • 聞いているだけで返事をしない。
  • 親しさを表すために差別的な表現を敢えて使う。
  • 挨拶、握手をしない。
  • 込み入っている状況の時に、話しかけられると困るので他人のふりをする。もしくは見てないふりをする。
  • 誰かが話している時に割り込む。(日本人特に多い。滅茶苦茶礼儀知らずに思われる。反対意見があっても相手が話し終わるまで待つ。それから発言する。)
  • 納豆食べた後会話(めっちゃ匂っています。西洋人には納豆はゴミ箱の匂いなんです。)

実際にやってしまった場合は、その人との好意的な関係を修復するのは無理なのでズバッと諦めましょう。そして次に同じ間違いを繰り返さないようにしましょう。

それでは今週の勉強を始めます。

<本文>

先週から色々考えたんですが、兎に角、RPGを一本完成させようと思います。

そのためには

  • 3Dモデルはかなりおかしくても市販の物で代用する。Blenderから作成していたら時間がかかってゲームも3Dモデルも完成しない内に飽きてしまう可能性があるので。
  • ストーリーは適当でいい。
  • 音楽は後付け

で取りあえずゲームを完成させます。

1.アセットの確認

今持っているアセットで使えそうなのを確認します。

f:id:kazuhironagai77:20200830201348p:plain

これは魔法のエフェクトに使用出来ますね。

f:id:kazuhironagai77:20200830201404p:plain

これらはマップとして追加出来るみたいですね。ちょっとリアル過ぎるかもしれませんが候補としておきます。

良く考えたらCategoryでEnvironmentにセットすればマップに使用出来るアセットだけ表示されるでした。

f:id:kazuhironagai77:20200830201420p:plain

現時点で以下に示した分だけ所有していました。

f:id:kazuhironagai77:20200830201441p:plain

何点か非常に使えそうなのがあります。

f:id:kazuhironagai77:20200830201455p:plain

f:id:kazuhironagai77:20200830201501p:plain

f:id:kazuhironagai77:20200830201509p:plain

f:id:kazuhironagai77:20200830201516p:plain

f:id:kazuhironagai77:20200830201524p:plain

この辺から見てみます。

f:id:kazuhironagai77:20200830201544p:plain

これだけ使用すれば何とかなりそうな感じですね。

f:id:kazuhironagai77:20200830201600p:plain

こっちは凄いですがリアル過ぎますかね。

f:id:kazuhironagai77:20200830201616p:plain

これは完璧でしょう。

f:id:kazuhironagai77:20200830201910p:plain

これもかなり凄いですね。

f:id:kazuhironagai77:20200830201924p:plain

これも凄そうです。

決めました。

新しいプロジェクトを作成してそれにこれらのアセットを追加して観察してみます。

名前はTestEnvironmentsにしました。

追加します。

そう言えばそれぞれのアセットのサイズとか考えていませんでした。PCなら関係ないかもしれませんが、携帯電話ならサイズも考えないといけませんね。

Medieval Kingdomだけ容量が7.83GBもありました。これはそのままでは使用出来ないですね。

それではそれぞれのアセットを見てみます。

まず、Platformer Starter Packからです。

f:id:kazuhironagai77:20200830201944p:plain

滅茶苦茶凄いじゃないですか?

f:id:kazuhironagai77:20200830202001p:plain

f:id:kazuhironagai77:20200830202011p:plain

もうこれだけでいいやって感じです。

f:id:kazuhironagai77:20200830202035p:plain

Overviewです。Level designerならこれでマップを作成するんでしょうがそこまでは自分ではやりたくないですね。

念のために他のも見てみます。

Stylized desert environmentです。

f:id:kazuhironagai77:20200830202103p:plain

これはサンプルマップ内で動けるようには作成されていないみたいです。カメラが7か所に設置されているのでそれぞれからの風景が見れるはずですが操作の仕方が分かりません。

f:id:kazuhironagai77:20200830202303p:plain

こんなアクターが使用出来るみたいです。

まあいいです。次を見ましょう。

次はWatermill Environmentです。

f:id:kazuhironagai77:20200830202323p:plain

あれ。Overviewを開いていました。

Medieval Kingdomを見てみます。

f:id:kazuhironagai77:20200830202342p:plain

多すぎてどれ見ればいいのか分かりません。取り敢えずmap1を見てみます。

f:id:kazuhironagai77:20200830202412p:plain

凄いですが、PCのうねり声も凄くなりました。他のマップも大体同じみたいです。

確かにそれぞれ凄いですが、私はlevel designerになる気はないんで、なるべくなら一括で全部そろっている方が良かったです。

うーん。しょうがないLevel designも自分で作成しますか。

作成に必要な要素を絞ります。

街、村、城です。その中には、道具屋、武器屋、宿屋、教会、一般人の家が必要です。

その外には、草原、森、山、砂漠、雪原が欲しいです。

3Dモデルはここにある奴を使用する事にします。

f:id:kazuhironagai77:20200830202442p:plain

全部のアセット内のStatic meshはそれぞれ単体で使用出来る事は確認出来ました。

2.建物の作成

もう武器屋、道具屋、宿屋、教会、一般人の家はこれで良いです。

f:id:kazuhironagai77:20200830202522p:plain

https://docs.unrealengine.com/en-US/Engine/QuickStart/index.html

それよりデザインばっかりやっているとプログラム本当に忘れてしまう事を思い出しました。これからはデザインが主になる時が多いと考えられますが、必ずプログラムも書く事にします。

まず、壁用のmeshですが、Medieval Kingdomに良さそうなのがありました。

f:id:kazuhironagai77:20200830203308p:plain

そしたら裏が透けています。

f:id:kazuhironagai77:20200830203326p:plain

直します。

使用しているマテリアルのTwo Slidedに

f:id:kazuhironagai77:20200830203347p:plain

Checkを入れます。

このチュートリアルによるとMeshのDouble Sided Geometryにチェックを入れろとありますが、

f:id:kazuhironagai77:20200830203630p:plain

Collisionにしかその項目がありません。一応入れておきます。

f:id:kazuhironagai77:20200830203649p:plain

後ろからも透明でなくなりました。

出来ました。

f:id:kazuhironagai77:20200830203705p:plain

f:id:kazuhironagai77:20200830203713p:plain

中はこんな感じです。

f:id:kazuhironagai77:20200830203753p:plain

f:id:kazuhironagai77:20200830203801p:plain

f:id:kazuhironagai77:20200830203809p:plain

ちょっとリアル過ぎますが、上出来でしょう。

同じ物をアクター内に作成して移動しやすくします。

f:id:kazuhironagai77:20200830203829p:plain

f:id:kazuhironagai77:20200830203836p:plain

何故か中がひどく明るいです。

f:id:kazuhironagai77:20200830203901p:plain

アクター内のStaticMeshのMobilityをStaticに変更したら直りました。

f:id:kazuhironagai77:20200830203919p:plain

f:id:kazuhironagai77:20200830203930p:plain

作って行くうちにZ-fightingが大量に発生しました。

Z-fightingを避ける為にmesh同士が重ならない様にしたら今度は隙間が気になります。

f:id:kazuhironagai77:20200830203947p:plain

Actor内で使用しているstatic meshらが重なった時z-fightingを起こさないようにする方法が分かりません。

というか普通の3D-Graphics programming (OpenGL)で2つ以上のメッシュが完全に同じ位置に存在した時に起きるz-fightingの防ぎ方も知らないです。Rasterizationかfragment programmingの段階でz-fightingが起きないように事前に防げそうですがね。

この問題は後で考えます。

3.ちょっとだけプログラミングもやります

思い出したんですが、UE4のデザインばかりやっているとプログラミングの方を直ぐ忘れるんです。流石に1,2週間なら大丈夫でしょうが、1カ月経つと完全に忘れます。自分が書いたコードも他人が書いたコードと同じです。更に問題なのが何でそんな書き方をしたのかが分からなくなる事です。

これからはデザインを大量にやる必要が出て来ますが、毎週必ずプログラミングもやる事にします。

f:id:kazuhironagai77:20200830204013p:plain

今週はこの部分を直す事にします。これはLevel BPに書かれたコードで、ある特定の場所でキーボードのEを押した場合に実行されるコードが書かれた部分です。直したい事は幾つかあります。

一つ目はユーザーのinputとキャラの行動を管理するクラスは、ThirdPersonCharacterなのでこのコードをLevel BPからThirdPersonCharacterに移します。

2つ目はifの連続になっているのでSwitchを使用して見易くします。更に条件にEnumを使用する事でこれから増える条件にも対応出来るようにします。

3.1 コードの直し

まず、RPGGameInstance内で作成したBoolean変数を一括して管理出来るようにします。

f:id:kazuhironagai77:20200830204035p:plain

現時点では以下に示したようにバラバラで管理しています。

f:id:kazuhironagai77:20200830204053p:plain

f:id:kazuhironagai77:20200830204100p:plain

まずGameInstanceクラスで管理する必要があるか何ですが、お店の中で別なレベル(マップ)に移動する事は絶対ないので、GameInstanceクラスで管理する必要はないです。

GameModeクラスで管理します。

次にUE4C++で管理するかBPで管理するかですが、UE4C++で管理します。理由はUE4C++で管理する方が難しいからです。難しい事に慣れておけば簡単な事に対応する事はすぐ出来るからです。

まず、Enumを作成します。

UE4C++でのEnumの作成方法を忘れてしまいました。調べます。

Googleでは、お馴染みの教科書であるUnreal Engine 4 Scripting with C++ CookbookのEnumのページが一番最初に出て来ました。

f:id:kazuhironagai77:20200830204132p:plain

Sherif, William. Unreal Engine 4 Scripting with C++ Cookbook (Kindle Location 4135). Packt Publishing. Kindle Edition.

何か変ですね。普通は公式のページが最初に出てくるんですが。

次に見つかったのがこのサイトです。

f:id:kazuhironagai77:20200830204230p:plain

こんな風に作成していました。

f:id:kazuhironagai77:20200830204337p:plain

更にYouTubeUnreal Engine C++ Training Series - UENUMでUENUMの作成方法が説明されていました。

f:id:kazuhironagai77:20200830204412p:plain

このビデオによると純粋なc++の問題としてenumと宣言するのは古いやり方で、より安全に宣言するにはenum classとした方が良いらしいです。Cppreference.comのEnumeration declarationにこの二つの違いについての詳しい解説が載っていましたが、これを読んでいるとC++の勉強になってしますので止めます。ざっと見た感じでは普通に使用している限りは問題ないように思えます。それよりもこのビデオでuint8の方の意味も説明されていました。Uint8の場合、1 byte分、つまり255個?のenumeratorsが作成出来るみたいです。

こんな感じで作成しました。RPGGameModeBase.h内に作成しました。RPGGameModeBaseクラスで使用するので、手頃な場所でしょう。

f:id:kazuhironagai77:20200830204433p:plain

GRPGameModeBaseクラス内に変数も作成します。

f:id:kazuhironagai77:20200830204451p:plain

更に念のために初期化もしておきます。

f:id:kazuhironagai77:20200830204506p:plain

ビルドします。

f:id:kazuhironagai77:20200830204524p:plain

出来ました。

次にこの変数にBPからアクセス出来るか試してみます。

f:id:kazuhironagai77:20200830204541p:plain

道具屋の主人のボックス内にプレイヤーの操作するキャラが侵入したらGRPGameModeBaseクラス内の変数、myPlaceForEventsの値がPE_ItemShopに変更されます。逆にそのボックスから出る時はPE_Noneに戻ります。

f:id:kazuhironagai77:20200830204602p:plain

f:id:kazuhironagai77:20200830204619p:plain

出来ますね。

今度はボックス内にプレイヤーの操作するキャラがいる時はあるキーを押す事でイベントが発生する事にしましょう。

ボタンはdo somethingの意味でキーボードのdを押した時に発動する事にします。

まずCharacterクラス内のSetupPlayerInputComponent()関数内にBindAction()関数を追加します。

f:id:kazuhironagai77:20200830204635p:plain

そしてDoSomething()関数を作成します。

f:id:kazuhironagai77:20200830204708p:plain

と言ってもDoSomething()関数の実装はBPでするつもりなので宣言だけです。

これで上手く行くのでしょうか?取りあえずビルドします。

f:id:kazuhironagai77:20200830204725p:plain

ビルドは成功しましたので続行します。

InputのAction MappingsにDoSomethingを追加しDを選択します。

f:id:kazuhironagai77:20200830204748p:plain

ThirdPersonCharacterクラス内にDo Somethingの実装をしました。

f:id:kazuhironagai77:20200830204805p:plain

テストします。

Playボタンを押してゲームを開始し、Dを押すと

f:id:kazuhironagai77:20200830204823p:plain

ThirdPersonCharacterBP内に書いたDo Something()関数の実装部分が実行されました。

出来ているようですので次に進みます。

f:id:kazuhironagai77:20200830204840p:plain

最初のIsValid()関数は0でない限り承認してしまったような気もしますが取りあえずはこれでやってみます。

残りは、Level BPに書かれているのと全く同じです。

f:id:kazuhironagai77:20200830204855p:plain

テストします。

道具屋の主人のボックス内に侵入してDを押しました。

f:id:kazuhironagai77:20200830204916p:plain

普通にウィジェットが開かれています。問題無いみたいですね。

同様に武器屋の場合も作成します。

やり方は道具屋と全く同じなので省略します。

テストも成功しました。

今度はアイテムを拾う場合を実装します。

f:id:kazuhironagai77:20200830204935p:plain

スペルが間違っている。Droppedですね。直します。

f:id:kazuhironagai77:20200830204952p:plain

こっちも間違っていました。直しました。これはPathも直さないと駄目みたいです。

色々弄りました。多分直ったでしょう。

これだけ分かりません。DropedItemsフォルダーの名前をDroppedItemsに変更したらDropedItemsフォルダーとDroppedItemsフォルダーの2つフォルダーが作成されたのでDropedItemsフォルダーを消そうとしたら出て来ました。

f:id:kazuhironagai77:20200830205010p:plain

分からないので今は残しておきます。

変な所で時間を食ってしまいました。

PE_PickUpの先を実装します。

f:id:kazuhironagai77:20200830205027p:plain

基本的には同じです。DroppedItemBaseのインスタンスはRPGGameModeBaseBP内に新たに変数を作成してそこに保持する事にしました。それ以外はLevel BPで実装していた時と同じです。

後、ここも直しました。

f:id:kazuhironagai77:20200830205044p:plain

DroppedItemBaseのボックス内にプレイヤーの操作するキャラが侵入した時RPGGameModeBaseBPのDroppedItemContentにselfをセットするようにしました。

テストします。

f:id:kazuhironagai77:20200830205105p:plain

出来ているみたいです。

後はNPCの老人との会話だけです。

Level BPの丸コピーですが行けるでしょう。

f:id:kazuhironagai77:20200830205126p:plain

テストします。

f:id:kazuhironagai77:20200830205143p:plain

出来ました。

これで完成ですが、やはりDは押しにくいのでEに変更します。

Level BPのEを外して、

f:id:kazuhironagai77:20200830205208p:plain

Action MappingのDoSomethingをDからEに変更します。

f:id:kazuhironagai77:20200830205223p:plain

テストしたら正常に動きました。

要らない変数やコードを消します。

と思ったのですが一応念のために1週間検討してから消す事にします。Githubを利用していないので消すと取り返すが付かないのです。今は無料で非公開のGithubが利用出来るはずなので使った方が便利です。そろそろ使用を考えます。

4.まとめと感想

今週はこれで終わりです。

あまり関係ない話ですが、スクリーンショットを取るときshift + F11で撮影するんですが、そのスクリーンショット用のソフトを開くのを忘れてshift + F11を押してしまう事が良くあります。そうするとUE4EditorがTool Barの前に飛び出して来て非常に使いにくくなります。これがどうやっても元に戻す方法が分からなくて、こうなった時は一端エディターを閉じていたんですが最近その直し方が分かりました。なんともう一回、shift + F11を押せば良かったんです。