<前文>
英語発音まとめ
このブログに記載しているプロジェクトとは別に、日本人に区別が出来にくい英語の音素をminimal pairを使用して練習する事で区別が出来るようになる学習ゲームも作成しています。
そのソフトを作成するためかなり英語の発音について勉強しました。
その勉強成果をここにまとめておきます。
ただし最初に断っておきますが、私は10年以上アメリカで暮らしていましたが、言語学は全く勉強した事はありません。のでここから書く事は全くの独学です。専門家の人から見れば常識な事が書かれていたり、間違っている事もあるかもしれません。しかし私にとってはこれが正しいと思われる内容になります。
- minimal pairで練習してもあるタイプのL とRの区別は限定的にしか出来ない。
のっけから否定的ですがminimal pairを使用する学習方法もSilver bulletではないと言う事です。非常に効果の高い学習方法ですが常識の範囲で使用する必要があります。
この区別が付かないタイプのLとRの場合も二つの単語の音を交互に聞いて、テストするとある程度の練習を積めば誰でも正解を選べます。しかし時間を置いてテストすると全く分からなくなります。
これは日本人が分からない音のもう一つの代表であるThと全く違う結果です。
ThはSやSHとminimal pairを使用して音の違いを学習すると大人でも完璧に分かるようになります。そして一端分かるようになると、自転車の乗り方を覚えたら生涯忘れないのと同じようにThの音そのものをずっと覚えています。他の日本人が英語をしゃべっている(通訳とか)のを聞いて「この人、THをチの音で代用しているわ。」とか「英語下手と思ったけどTHの音しっかり発音している。」みたいな事まで分かるようになります。
この結果を元に、私が考えてるのはLとRの究極的な区別は絶対音感的な物が関わっているのではないか?と言う事です。音楽が専門の人によると、大人になってからどんなに音楽の練習をしても絶対音感は付かないそうです。その差は年齢だそうで、ある程度の年齢に達すると絶対音感を身に付ける事は出来ないそうです。これに近いものが、LとRの究極的な区別にはあるような気がします。
- /ʌ/の音はイギリス英語とアメリカ英語で違う
発音記号のもっとも重要な取り決めは「一つのアルファベットに一つの音」です。これは平仮名が言葉の基本単位である日本人には当たり前過ぎる事ですが、英語では、一つのアルファベットに沢山の発音方法があり、また同じ発音を別のアルファベットで共有したりしてるため、アルファベットで音を表す事が出来ません。
その弊害を無くすために開発された発音記号ですので、絶対に「一つのアルファベットに一つの音」の原則は守らなくてはいけないはずなのに、もっとも基本的な音の一つである/ʌ/の音がイギリス英語とアメリカ英語で違います。
- 発音記号は、音を以下の条件で定義している。ただし2と4は条件付きで、結構曖昧。
- 口の開ける大きさ、
- 舌の動かし方や位置、
- 唇の形、
- 息の吐き方(イントネーションやアクセントを含む)
日本人には違う音に聞こえるのに同じ音で表示されている英単語が沢山あります。逆に日本人には全く同じ音なのに違う音として定義されている発音記号もあります。上記の原則を理解しておくと英語圏の言語学者は、その上記の原則に照らし合わせて同じ音、違う音として認識しているんだと分かります。
- Schwa /ə/音について
アメリカ英語の発音指導の専門家の多くは/ə/と/ʌ/は全く同じ音で、/ʌ/は強く、/ə/は弱く発音するだけであると言っています。これは上記の発音記号の定義で、アメリカ英語の/ʌ/と/ə/を当てはめて考えると全くその通りです。
しかし日本人にとってはちょっと違う話で、/ʌ/はどの単語で使用される場合でも、ウに近いアに聞こえるのに対して、/ə/は単語によってはアに聞こえたりオやウに聞こえたりします。
そうなると実際のSchwa音が分からなくなり大変不安になります。
これについてですが、口を全く動かさないで、喉の奥だけでアイウエオと言うと結構アイウエオと聞こえる事と関係していると思っています。
もう少し詳しく説明すると、/ə/が実際の発音で使用されるときは、必ず元の音があって、それの退化した音として使用されます。だから実際に単語の中で/ə/が使用されている場合、口の開ける大きさ、舌の動かし方や位置、唇の形、息の吐き方は/ə/の発音になっていても、喉の奥で発する音は元の音に近い音が発せられていると思われます。
それが実際の単語内の/ə/の音がアに聞こえたりオやウに聞こえたりする理由だと考えています。
- /ɜ// ɝ //ɚ// ɜɹ// əɹ/は同じ音として扱う
これはRの音についてなんですが、日本語でアを伸ばすとアーになります。イギリス英語だと日本と全く同じで単に音を伸ばすだけなんですが、アメリカ英語だと音を伸ばす時に丸めるんです。音を巻くというともっと正確かもしれません。その巻いた音を日本語で表現するとア~となりますが、この音がアメリカ人にはRに聞こえるらしいんです。つまりアRと聞こえます。それで発音記号は二つのアルファベットで表すべきと考える人と、いやア~と一つの音が伸びているだけだから一つのアルファベットで表すべきと考える人たちがいます。更に単語によってアRと聞こえるものとア~と聞こえると主張する人もいます。
2つのアルファベットで表すべきと考える人は/ ɜɹ// əɹ/を使用しますし、一つの音で表すべきと考える人は/ ɝ //ɚ/を使用します。更に単語によって違うと主張する人達は、単語によって/ ɜɹ// əɹ/と/ ɝ //ɚ/を使い分けたりします。
更に混乱する要素として/ɜ/と/ɚ/はアメリカ英語だと同じ音だったりします。
前提としてイギリス英語だと、/ʌ/は/ə/とは全く違う音です。ので/ə/のストレス音が必要になります。それが/ɜ/らしいのです。しかしイギリス英語では/ɜ/は/ə/より強く発音するだけでなく長く伸ばして発音するらしいんです。つまりアメリカ英語なら丸くなる訳です。それで/ɜ/がストレスのある/ɚ/になる訳です。所がこの強弱ですがアメリカ英語の場合、ほとんど変わりません。つまり同じに聞こえます。
それじゃ最後に/ɜ/と/ ɝ /の違いは何ですかとなりますが、アメリカ英語にもイギリス英語の/ɜ/と同じ音がある。だからRで巻いた時は/ ɝ /を使うべきと言う人達です。彼らによるとBirdなんかはRで巻いていない。と言っています。言っていますがBirdをRで巻いて発音するアメリカ人はいくらでもいるでしょうし、その例えは、何か日本人でもカナダをキャナダと発音する人がいます。みたいなちょっと恥ずかしい感じがします。
これらの音は結局ERの音を表しています。HerとかMotherなどのerです。勿論“英語”ですのでアルファベットと実際の音は限定的にしか繋がっておらず、girlのirやhurtのurはこの場合のerと同じ音です。
ちなみにですが、この音とɑɹの音(例えばHurtとHeart)はどちらも日本語で「ア~」と聞こえますがMinimal Pairで練習すれば5分位でこの2つの音の区別がつけられるようになります。
- Lの発音はTHみたいに舌を噛んでする
これ、私ずっと疑問に思っていた事なんですが、アメリカ人にLの発音の仕方を聞くと、上歯の付け根に舌をタッチさせてと、所謂教科書的な説明をみんなします。それなのに実際の会話でLを発音する時には、THの時の様に舌を噛んで発音しているんです。
そしたら確認出来ました。沢山のアメリカ英語の発音の専門家がLの発音の時にTHのように舌を噛んで発音する方法もあると言っていました。
それらの専門家の話を聞くまで、この舌を噛んで発音するLはDark Lの音なのかな?とか思ったりもしたんですが、実際はもう少し複雑でした。
Dark Lの音は口の奥、喉側で出す音なので、舌の付け根の形だけが大切だそうです。ので舌を噛んでいてもいなくてもDark Lの音を出す事は出来るそうです。
そしてLight LはDark Lを前半で発音して後半に所謂教科書的な上歯の付け根に舌をタッチさせて発音するそうです。この時に舌の脇から息が抜けるとLの音になり、その時の舌の位置は歯の裏でも舌で歯を噛んでも関係ないそうです。
それで実際の発音の場合ですが、例えばGirlと発音する時はLはDark Lになります。Light Lの前半部分だけ発音する訳です。しかしGirl isと発音する場合は残り後半も発音するのでLight Lになるそうです。その時に最初から舌を噛んで発音するとDark Lの発音で止める事もそのままLight Lの発音に移行する事も舌の先を動かさないで出来るので楽に発音出来るらしいんです。
ふーん。って感じです。
- 二重母音について
[aɪ], [eɪ], [ɔɪ], [aʊ]のような音を二重母音( diphthong ) と言いますが、これってすごい不思議でした。だって単に母音が二つ並んでいるのと同じじゃないですか?日本語でアオとかアイとかをアイウエオとは別に習う必要はないですよね。なんでこれらの音は特別なんでしょうか?
ずっとその理由があると思っていたんですが無かったです。単にこれらの母音は二つ続けて発音する事が多いだけでした。
ただ気を付けないといけないのはこれらの母音の中に、/a/や/e/の音のように二重母音にしか存在しない音があります。
この辺はまだ勉強中ですが、/a/の音は日本語のアとほとんど同じで、/e/の音は日本語のエの音とこれもほとんど同じに聞こえます。Vowel Chartを見てもこれらの音と日本語のアとエは非常に近いか全く同じ位置に記されています。
- /ɑ/について
この音、日本語が喋れるアメリカ人で日本語のアの音と同じ音と言っている人達がいます。いますが、これそのまま信じるのはかなり危険だと思います。
私は/ɑ/の音はオの混じったアで単なるアとは違う音だと思います。
その理由は、/ɑ/と/ʌ/の音のMinimal Pair(duckとdock、hutとhot、nutとnotなどです。)で練習すると、日本人なら直ぐに実際の単語の発音では/ɑ/の音にはオが僅かですが完全に聞こえ、それ故に区別が容易につく事に気づくからです。
確かに中にはFatherのようなオが全く聞こえない単語もあります。しかしこれだけ沢山の/ɑ/の音を使用している単語が僅かながらオが聞こえるのですから実際はオに近いアだと思います。
更に言えばVowel chartの記載から見ても、/ɑ/の音は、日本語のアの音とはかなり違う音です。まず日本語のアは口の先で発音しています。それに対してこの/ɑ/の音は口のかなり後ろで発音します。それに日本語のアの音はかなり広い範囲のアの音で、あんまり口を開けないでしゃべるおとなしい女の子なんかはむしろ/ʌ/に近い音でアを発音しています。
もう一つ言うと、一般的な日本語のアに一番近い英語の音は、先程の二重母音に出て来た/a/の音だと思います。
まだまだ書く事はありますが、今週はこの辺で止めておきます。
それでは今週の勉強を始めます。
<本文>
1.今週の予定
以下の事をやっていきます。
- 対話システムとアドベンチャーゲーム本形式によるセリフの整理方法の考察
- Game Modeクラスの整理の続き
- バグの直し
- 勝利のポーズの時に剣が頭に刺さる。
- モンスターが後ろを向いているとプレイヤーの操作するキャラがすぐ後ろに立っていても気が付かない。
- 戦闘時の武器のモーションの追加
- 魔法の杖を装備したら名前が枠からはみ出て表示されていたのでそれを直す。
- 魔法のeffectを増やす。
- Levelデザイン
2.対話システムとアドベンチャーゲーム本形式によるセリフの整理方法の考察
先週、戦闘時における報連相のための対話システムを一から直しましたが、その際にNPCとの会話で考案したアドベンチャーゲーム本形式によるセリフの管理方法を採用しました。
このやり方は全てのセリフを一枚のData tableで管理出来るだけでなくData Tableを見ればそのセリフの前後関係も把握出来る優れたシステムです。
ここで思ったんですが、実際のゲームではどうやってセリフを管理しているんでしょうか?調べて見ます。
2.1 実際のゲームにおける対話システムの管理方法はどうなっているのかを調べる。
あんまりゲームにおける対話システムの管理方法についての記事がありませんでした。
あるにはあったんですが、何か高校生がまとめたみたい感じのサイトとか、ユーザー側に寄り過ぎてどうやってそのセリフを整理・管理しているかについては全く述べていないサイトばかりでした。
その中でWikipediaにDialogue Tree についての解説が載っていました。
このシステムは、私が採用したアドベンチャーゲーム本形式によるセリフの書き方をTree Diagramに表した方法でした。
やっぱりアドベンチャーゲーム本形式は商業レベルのゲームでも採用される優れたシステムだったんですね。
後、Tree Diagramにすると非常に見やすいです。
ここの説明によるとこの方法が最初に採用されたのは1941年と書かれていました。このやり方を現在のゲームでも採用し続けているのかそれとももっと優れた方法があるのかは書かれていませんでした。
後、ユーザー視点からですが、対話システムの進歩としてWe Should Talkと言うゲームが挙げられていました。
このゲームではNPCとの会話は、複数ある回答の中から一つを選ぶのではなく、文の一部を変更して自分で回答する文を作成するそうです。
確かに進歩と言えば進歩ですが、Tree Diagram が出来てから80年以上経っている訳ですから。革命的とまでは言えないですね。
もっと機械学習したAIが回答するみたいなのはないのでしょうか?
調べて見たら、論文は出て来るんですがゲームは出てこないですね。
何か、日本のゲームとか世界の先端を走っているイメージがあったんですが、大人数で開発しているようなゲーム会社でも80年以上前に開発された対話システムをそのまま使用しても何とも思わないでゲーム作っているんですかね。ちょっとがっかりです。
2.2 Not Yet Dialogue Plugin System について
Tree Diagramと言えば、UE4のplugInであるNot Yet Dialogue Plugin Systemは対話をTree Diagramで管理しています。
ゲームにおける対話システムの進歩について、あんまり考察する事もないみたいなので、このPlugInの使用方法をここにまとめる事にします。
3.Not Yet Dialogue Plugin Systemの使用方法の解説
Not Yet Dialogue Plugin SystemはUE4用のPlugInで対話のセリフを管理するのに上記で紹介されたDialogue Tree を採用しています。
3.1 無料版について
marketで売られているNot Yet:Dialogue Plugin Systemは5千円以上します。
しかしhttps://gitlab.com/NotYetGames/DlgSystemに行くと無料で公開されています。
これって勝手に使用して良いんでしょうか?と心配しながら、ここの説明文を読んだらBinaryファイルにするのに思っていたより手間がかかるので、Binaryファイルはマーケットで販売する事にした。しかしここにある分は完全にフリーで商業も可と説明してありました。
のでここからダウンロードして使用します。
3.2 使用方法のまとめ
公式のTutorial (Dialogue Plugin System - Create your first Dialogue Project Tutorial)で使用方法が説明されていますが、これでもかなり複雑です。こういう使い方の解説は、最低限の機能の紹介に徹するべきだと私は思います。
それで自分でまとめてみました。
- 準備編
- Actor クラスを使用したNPCの作成とDlg Dialogue Participantの継承、そしてParticipant Nameの指定
- ThirdPersonCharacterとDlg Dialogue Participantの継承、そしてParticipant Nameの指定
- 対話の作成とその対話をDialogue BPに落とし込む
- 本番編
- 作成したDialogue BPを使用する。
- 最初のセリフを表示する。
- 選択条件を表示する。
- 次のノードに移る。
本番と準備を分ける事で、このプラグインを使用するに当って最低限準備しなければならない事と、使用するに当たって本当に最低限知らないといけない事が区別して理解出来るはずです。
かなり分かり易い説明になると思っています。
3.3 準備編
Not Yet:Dialogue Plugin Systemを使用するためには3つの準備が必要です。
- Dialogue BP内に実際の対話を書く。
- 対話に必要なNPCを作成する。
- Playerの操作するキャラと作成したNPCにParticipant Nameをつける(そのためにはDlg Dialogue Participantの継承が必要)。
これらについて解説していきます。
3.3.1 ダウンロードしたDialogue systemをProjectから使用出来るようにする。
このブログを読んでいる人でダウンロードしたPluginの使用方法を知らない人はいないと思いますが一応書いておきます。
まずProjectを作成します。Template はいつも使用しているThird Personにします。
作成したProjectを開き、新しいFolderを作成します。名前は必ずPluginsとします。
先程ダウンロードしたファイルを解凍し、このフォルダー内に移します。
これだけでProjectから使用出来るようになります。
確認します。
いつもBPを作成する手順で、以下の選択肢を開くとDialogue Systemと表示されていたら、Dialogue systemが使用出来る様になりました。
3.3.2 Actor クラスを使用したNPCの作成
まずNPCを作成します。
Actorクラスから派生させたBPを作成します。
中を開きSkeletal Meshを追加します。
NPCが出来ました。
3.3.3 Dlg Dialogue Participantの継承
今度はDlg Dialogue Participantを継承させます。
ToolbarからClass Settingを選択します。
するとDetail欄にInterfaceが現れます。
Addボタンを押して、Dlg Dialogue Participantを選択します。
そうすると以下の様にDlg Dialogue Participantが表示されます。
これでDlg Dialogue Participantが継承出来ました。
3.3.4 Participant Nameの指定
次にParticipant Nameの指定をします。
以下に示した様に、My BlueprintのInterfaceにGet Participant Nameがあります。それをクリックして開きます。
それをクリックして開きます。以下の様になっています。
このNoneの箇所にこのNPCの名前を入れます。今回はMeNPCとします。
3.3.5 同様の方法でThirdPersonCharacterにDlg Dialogue Participantの継承を行い、Participant Nameを指定する。
しました。
3.3.6 セリフを作成する
Dialogue BPに記入するセリフが必要です。それを作成しました。
3.3.7 Dialogue BPを作成し、上記の会話を移す
作成した会話をNot Yet: Dialogue system内に落とし込みます。ほとんどカンで操作しても作成出来ますが、注意しなければならない箇所が幾つかあります。その辺は詳しく解説します。
まずDialogue SystemからDialogue BPを作成します。
このDialogue BPこそがNot Yet: Dialogue Systemにおいてセリフの管理を行うクラスです。
名前をMe_dialogueとしました。
開きます。
このStartノードから会話を作成していきます。
AIの作成で使用したBehavior Treeの時と同じようにこのノードから→を引っ張ります。そしてAdd Speech nodeを選択します。
Speech Nodeにセリフを追加します。
するとNode側もセリフが表示されます。
今度はこのセリフを言うキャラのParticipant nameを追加します。
するとセリフと同じようにMeNPCがノード側にも表示されます。
同様にPlayerのセリフも追加します。
更に会話を追加していきます。
この次は選択肢が表示されます。
選択肢は以下の方法で作成します。
まず選択肢の答えのためのノードを作成します。
矢印を選択します。
するとDialogue Graph Node内に以下の内容が表示されます。
ここからTextのNextの部分に選択肢の質問を書いて行きます。
最初の選択肢は「武器を買いに来た。」ですので、それを書き込みます。
同様に残り二つの選択肢も埋めていきます。
今度はそれぞれの選択肢が選ばれた場合のセリフを追加します。
ですので、
となります。
2と3を選択した場合のセリフも追加します。
これで全てのセリフをDialogue BPに書く事が出来ました。
Nodeの最後には、End Nodeを追加します。
最後にもう一つやる事がありました。
どのノードも選択しない状態でDialogueを見ると以下の様に表示されています。
Participant NameがそれぞれMeNPCとPlayerであるクラスの名前をParticipant Classに記入します。
Playerの方は既にThirdPersonCharacterが選ばれています。MeNPCのParticipant Classを選択します。
これで準備が完了しました。
3.4 本番編
ここから、今まで作成したモノを使用してゲーム中にセリフを表示させる方法を説明します。
3.4.1 作成したDialogue BP(Me_dialogue)を使用する。
3.3で作成したDialogue BP(Me_dialogue)を使用するためには、そのinstanceを作成する必要があります。
どのBPでもいいのですが、今回はLevel BP内で作成する事にします。dialogue BPのinstanceを作成する関数はStart Dialogueです。
Me_dialogueで使用されているParticipant nameを持つクラスのInsntanceをLevel上に配置します。
それらのInstanceをMake Arrayに繋げます。
3.4.2 最初のセリフを表示する
前節でDialogue BPのインスタンスの作成までは成功しました。そのインスタンスからどうやってセリフを取り出すのかをここで解説します。
取りあえずアクセスを簡単にするためにMe_dialogueのインスタンスは変数MeDialogueにセットします。
ここで突然ですがDialogue BPのActiveなノードと言う概念について説明します。
アドベンチャーゲーム本で考えると分かり易いと思うんですが、自分がゲームのどこをやっているのかを表すためには、今、自分が読んでいる文章の番号が必要です。誰か友達にどこまで進んだ?と聞かれたら「今、180でドラゴンと戦っている。」と答える訳です。
この時の180と言う番号は、考えようによっては、今自分が居る場所とも言えます。Dialogue BPでは、この今自分が居る場所をActiveな場所(ノード)と呼んでいます。
勿論、Dialogue BPは対話のセリフなので、Active Nodeは、今どのセリフを読んでいるのかを表します。
当然ですが、ActiveなノードはDialogue BP内で一個だけです。
Dialogue BPのインスタンスからセリフを取り出すためには、このActiveなノードにアクセスする必要があります。
Activeなノードにアクセスするために使用する関数はGet Active Nodeです。
アクセスしているNodeのテキストを読む関数はGet Node Textです。
I keyを押すとnodeに書かれたテキストをプリントする様にします。
すると、Iを押すたびに
とプリントされました。
これで現在のactiveなノードのセリフをゲーム画面に表示する事が出来ました。
3.4.3 次のノードに移る
最初のセリフが表示出来たら、今度は次のセリフを表示する必要があります。その為にはActive Nodeを次のノードに移す必要があります。
次のノードに移すための関数はChoose Optionです。
次のノードが1つ以上ある場合はOption indexに移動したいノードに着いている矢印の番号を記入します。矢印の番号は0から始まり左から数えていきます。
以下の様に実装してセリフが変化する様子を見てみます。
結果です。
Iを押すたびにActive nodeが前進して表示されるセリフが変わっています。
3.4.4 選択条件を表示する
最後に矢印に追加したセリフの表示方法を説明します。
そのために使用する関数はGet Optionです。
矢印の中から一個の矢印を選ぶのがChoose Option関数だから、矢印そのものを収得する場合はGet Option関数であるのは納得です。
正しこの矢印、Text以外にも沢山の情報を持っています。
のでその中からTextを選ぶ必要があります。
なので以下の様な実装になります。
これで矢印のテキストにもアクセスする事が出来ました。
テストします。
あれ。Nextってなんですか?
となるかもしれませんが、
矢印は何も指定しないとdefaultでNextが指定されているんです。
問題はそこじゃないんです。
「ここは武器屋です。今日はどんな御用ですか?」の後のセリフを見て下さい。
「武器を買いに来た。」しか選択肢が表示されていません。
選択肢は全部、表示されないと選択出来ませんよね。そこを次の節で直します。
3.4.5 選択条件を全て表示する。
選択肢を全部表示させる関数は…。残念ながらありません。普通のC++のように選択肢の数を調べてその分ループして表示します。
ノードが持つ選択肢の数を調べてくれる関数はGet Option Numです。
この関数を使用して以下の様に実装します。
結果を示します。
はい。選択肢が全て表示されました。出来ました。
3.5 Not Yet Dialogue Plugin SystemのTutorialの作成のまとめ
公式のTutorialをかなり参考にしましたが、自分で作成した初めてのTutorialです。
自分ではこのTutorialが分かり易いのか、あるいは途中で詰まって出来ない箇所があるのか、もしくは興味が持てるほど引き付けられる内容があるのかなどは、全然分かりません。
一応以下の事を考えて書きました。
Hooking (読者を引き付けるための口上)としてこの5000円以上するこのNot Yet Dialogueが無料で手に入る方法を教えています。
このpluginを使用するために必要な事と、使用するための準備に必要な事を、明確に分けるために準備編と本編に分けました。こうする事で読みやすいかどうかは分かりませんが理解はし易くなったと思います。
本編ではActive Nodeと言う考えを最初に説明してそのActive nodeに従ってセリフを抽出していく事を説明しています。この方が分かり易いと思ってそうしました。
更に覚えなければならない関数の数を最小にするためにStart Dialogue()、Get Active Node ()、そしてGet Option()の三つと、その補助としてGet Node Text()、Get Option Num()の二つだけに絞って説明しています。
4.Game Modeクラスの整理の続き
先週、RPGGame Mode BPを整理して思ったのがまだまだ整理出来そうでした。
なので今週の引き続き整理していきます。
4.1 MyGameInstance変数の整理
以下の様に整理しました。
こんな感じで全部直していきます。
4.2 Third Person Character BP変数の整理
次はThird Person Character変数を直します。
4.3 Combat UI変数の整理
Combat UI変数も直します。
CombatUI変数ですが戦闘中に同じウィジェットを三か所もセットしています。
既に外していますが、Action状態で二か所です。
戦闘中にDecision状態でセットされたウィジェットがAction状態になった途端に外れる事はないので、Action状態にあるSETは全部消します。
以下の様に整理していきます。
一応確認のためにテストします。
- 武器なし:負け
- 武器あり:勝ち
- 魔法あり:バグで表示されず。
魔法はレベル1では覚えないので、Mを押すと魔法を覚えるように設定していたのですが、下に示したThirdPersonCharachterBPのコードでもMを使用していてこれとぶつかっているみたいです。
このコードはワープの時に使用しているコードですが、Mでマップを開く必要ないのでMを外しました。
今度は使用可能になりました。
更に一個バグを発見しました。
罠に一回侵入してモンスターを発生させ、その後逃げ出します。するとモンスターが死んで死体が消えるのですが、消える前にもう一度、罠に入ります。
するとモンスターは発生しませんが、戦闘は開始します。
直します。
以下の様に改良しました。
もしSpawned Monsterに実体が在る場合は待つ事にします。モンスターが消えるアニメーションは1.2秒なので、その間は罠に侵入しても新しいモンスターは発生しないようにしました。
テストします。
何十回やっても死体が消えてから新しいモンスターが発生するようになりました。
直りました。
直りましたが、こんな僅かな一手間でバグが跡形もなく消えるのは正直、驚きです。
UE4C++でコードを書いていた時は「Buildに掛かる時間ウゼー、BP最高!」と思っていましたが、こうやって整理のためにBPを見直して見ると、BPは直ぐにスパゲッティコードになってしまっていますね。これを見やすいコードに戻すのはかなり難しいかもしれません。
5.バグの直し
先週見つけたバグを直していきます。
5.1 勝利のポーズの時に剣が頭に刺さる。
以下に示した様に剣が頭に刺さっています。
調べたら、武器を装備した状態用の勝利のポーズのアニメーションがありました。
武器を装備した時はこのアニメーションを使用する様にします。
テストします。
武器を装備している時は武器の勝利のポーズを取ります。
勿論、剣が頭に刺さる様な事はありません。
武器がない時は無い時のモーションを取ります。
5.2 モンスターが後ろを向いているとプレイヤーの操作するキャラがすぐ後ろに立っていても気が付かない。
現状のモンスターの視界の広さを示しています。特に狭いとは思えませんね。
視界をこの状態より広げればこの問題は解決しますが、それよりモンスターが辺りを見渡す動作を追加した方がリアルな気がします。
色々検討しましたが、回りを見渡すアニメーションがないとどうしても動作が機械的になってしまいます。
別な方法で解決しましょう。
モンスターの視界がかなり狭いみたいです。
モンスターの視界を1500から2500に変更しました。
単位が分からなかったから1500でも凄い気がしていましたが、15m先までしか見えてないって近眼でレベルじゃないでしょう。25m先まではプレイヤーの操作するキャラを認知出来るようにしました。
以下に示した緑のサークルがモンスターが認知出来る範囲です。
更にIsHeInTerritory Serviceでモンスターの縄張りを決定していますが、その範囲も2500に変更しました。
最後に休憩時間も2秒から0.5秒に変更しました。
これでテストします。
これだけ条件を厳しくするとモンスターの後ろに貼りつくのは無理になりました。
ただ、モンスターから見ると休憩時間が4分の一になってしまったので、かなりブラックな職場になってしまいました。
心なしかモンスター達も苛立っているように見えます。
私がモンスターの首を回して辺りの警戒をする方法が分からなかったばかりに、モンスター達のパトロールはかなりハードなものになってしまいました。何かブラックな職場が生まれる原因を見た気がします。
取りあえず解決です。
5.3 戦闘時の武器のモーションの追加
弓を装備した時も、剣の装備した時と同じモーションです。これを直します。
最初、攻撃モーションだけ直せば良いかと思い、それだけ直したんですが、攻撃以外のモーションが非常に不自然だったので全部のモーションを直します。
まず装備が弓と矢の場合とそれ以外を判別するための関数を作成しました。
CheckArrowBow()関数と名付けました。
この関数で武器や防具を装備するたびにその装備が弓矢かどうかをチェックします。弓矢の場合は専用のアニメーションを流すようにします。
以下の箇所で武器を装備していますので、その装備が弓矢かどうかをチェックします。
そして装備が弓矢だった場合は、MyThirdPersonAnimBPに新しいBoolean変数を作成して下の部分から更に分岐させます。
最初のSet Weapon Equipped()関数が呼ばれている箇所ですが、StartScreenで使用していました。
この時にCheckArrowBow()関数でチェックして、mapが変わったら全部消えてしまうので、ここでチェックする意味はありません。代わりにRPGGameModeBPのEvent Begin Playでチェックしましょう。
ついでにMy Third Person Anim BPに弓矢を装備した事を知らせる変数、Bow And Arrowも作成しました。
Anim Graphのdefaultでは以下のStateを追加しました。
弓と矢を装備した状態でも魔法を使用する事もあるので上記のような形になりました。
他のSet Weapon Equipped()関数が呼ばれている箇所も同様にします。
Weapon Widgetの場合です。
Is Weapon Equipped変数の後で、My Third Person Anim BPのwithWeapon変数の値をTrueに変更しているので、その後でCheck Arrow Bow()関数を呼びました。
次は、pause画面で武器や防具を外した時の場合です。(Pause Equipment ウィジェット)
武器と防具のどちらか一方でも外せばその時点で弓矢を装備していない事は確定なのでCheckArrowBow()関数を使用する必要はありません。
これで、新しいマップが開かれた時、武器を装備した時、武器を外した時に、弓矢を装備しているのかどうかをチェックします。
防具を装備した時、外した時の場合も上記のコードが、弓矢を装備しているのかどうかをチェックしますので、新しくコードを追加する必要はないはずです。
今度は、弓矢を装備している場合のアニメーションの作成をします。
武器を装備した状態のIdle、Walk、そしてRunのアニメーションを管理しているMyThirdPerson_IdleRun_2DwithWをDuplicateしてMyThirdPerson_IdleRun_2DwithBowArrowを作成し、中のアニメーションを弓矢のそれにします。
デモ画面では刀が頭に刺さっていますが、弓矢に交換したら直るんでしょうか?
作成したアニメーションをMy Third Person Anim BPのIdle/Run And Arrowから呼び出します。
弓矢で攻撃するモーションも追加します。
これで完成です。
テストします。
弓矢を装備します。
中々カッコイイですね。
装備を外します。
弓だけ装備します。
はい。弓だけだと弓矢のアニメーションにならないですね。出来ています。
矢だけでも同様です。同様ですが、矢の先が地面にめり込んでいます。このアニメーションは直す必要があります。後で直します。
この後、色々な条件で試しましたが、全部出来ていました。
今度は戦闘時のアニメーションをチェックします。
弓矢を装備した時は、弓矢のアニメーションになっています。
問題はこの状態で魔法を使用した時です。
魔法を試すために一端、ゲームを終了したら、Errorが出ている事に気が付きました。
これは武器や防具を片方だけ外した時に発生したエラーのようです。
エラーが発生した箇所のコードを見直すと、MyThirdPersonAnimBPにアクセス出来ていない事が判明しました。
直しました。
以下に示した黄色で囲った部分を追加しました。
これでエラーは出ないはずです。
テストして確認します。
片方だけ武器や防具を変更したり、外したり、装備したりしましたがerrorは出ませんでした。
直っています。
それでは魔法のテストをします。
まず弓矢を装備した状態で魔法を使用しました。
普通に使用出来ました。
魔法の使用後は、弓矢のモーションに戻っています。
今度は弓矢で攻撃します。
普通に弓矢で攻撃しました。
又、魔法で攻撃します。
出来ていますね。
ああ…
勝利のポーズが弓矢のそれではなかったです。
直します。
これで勝利のポーズも弓矢のそれになるはずです。
テストします。
手から弓が離れていますし、矢が地面に刺さっています。
これが本当に正しい勝利のポーズなんでしょうか?
デバックした限りでは正しい様です。
ここで流しているVictory_Bow_Animの元のアニメーションをチェックしましたが、モーションは同じでした。
多分合ってはいますね。
今回はここまでとして、アニメーションのおかしい所は、後で検討しましょう。
先週のブログを読み直したら、
と書かれていました。
これも後で検討します。
5.4 魔法の杖を装備したら名前が枠からはみ出て表示されていたのでそれを直す。
単純に後ろの絵を引き伸ばしました。
それよりもSoldierの表示はオカシイです。
こっちも直します。
はい。出来ました。
5.5 魔法のeffectを増やす。
今回は、魔法の炎(小)を作成するだけにします。
Effectは大変大きな分野で、バグの直しの一環で全部を勉強出来る訳はなかったです。
改めて時間を作って勉強する事にします。
更に今はParticle Systemで作成していますが、Niagaraを勉強すべき時が来ているのかどうかも調査しようと思います。
Fire Ballのサイズが小さいversionを作成しました。
実際に使用したら、何故か同じサイズの火の玉が飛び出してきました。ので以下の方法で炎(小)を作成しました。
FireBallをSpawnする時にそのサイズを指定します。炎(小)の時はサイズを0.25倍にしました。
炎(小)の場合、
炎(大)の場合はいつもと同じです。
6.Levelデザイン
以下の地図通りに作成します。
サイズはどうしましょうか?
先週のスピードに関する調査でマップの大きさも分かりました。
島の全体を見るのに歩いて1時間もかかったら面白く無くなります。精々10分で全体が見れるべきです。300m^2位にしますか。
調べて見た所、前回作成したLandscapeの大きさが127m^2でした。
町の大きさが127m^2で普通なのに、島の大きさが300m^2では小さすぎますね。
Landscape Technical Guideによるとお勧めのサイズは以下の様になっています。
1009m^2にしておきますか。
どっちを選択しましょうか。
Component Edge、Section Edgeそして Individual Quadについての軽い復習をしてから決める事にします。
2020-11-08のブログにLandscapeについてまとめがありました。
読んでみると結構重要な事が書かれていました。
最小単位は1㎝もしくは1 Unreal Unitなんでしょうか。
前回作成したLandscapeは一辺のサイズがだいたい130mでした。
そして以下の表の下のパラメーターで作成しました。
63x2=126で1を足して127、127mだとすると、最小単位は1mですね。
Component、Sectionについての解説がLandscape Technical Guideに載っていました。
それによるとComponentはrendering, visibility calculation, そして collisionを計算する単位だそうです。
RenderingとCollisionは分かりますが、Visibility Calculationは何を計算しているのでしょうか?
直接、Visibility Calculationが何を指しているのかを説明しているサイトは見つからなかったですが、色々なサイトを読んで総合的に判断するとCullingのような事を指しているみたいです。
後、もう一つ大切な事は、一つのComponentが一つのHight Map用のTextを保持しています。これはSectionの数とPerformanceに影響します。
SectionはLandscape LOD calculationの単位みたいです。LODはLevel of Detailsの事です。
このSectionの数を増やすと、1枚のテキストで対応するHight Mapの大きさも増えます。つまりパフォーマンスが向上します。
なるほど。
良く分かりました。
後、Epic社はComponentの数は1024 以下にすべきと忠告しているそうです。
ちょっと時間が無くなってしまったので今週はここまでとします。
7.まとめと感想
今週は以下の事をやりました。
- 対話システムとアドベンチャーゲーム本形式によるセリフの整理方法の考察
- Not Yet Dialogue Plugin Systemの使用方法の解説
- Game Modeクラスの整理の続き
- バグの直し
- Levelデザイン
対話システムに関してはこれ以上現状ではやる事は無いです。
Game Mode BPクラスの整理はほぼやり尽くしましたが、沢山あるWidgetクラスも同様に整理する必要があります。こっちもやって行こうと思います。
バグの直しでeffectはとてもバグの直しの範囲では対応出来ないので別に枠を作ってやる事にします。
Level デザインは来週やります。
来週やる事は、
- Level デザイン
- Widget内のBPの整理
- Effectの勉強と作成
です。