‫こんにちは､ お帰りなさい｡
‫それでは､ マウスを使ってタレットを回転させましょう｡
‫そして､ そのヒット位置は､ 前の動画で行ったトレースヒットから｡
‫だから､ マウスカーソルを動かしていると､ 砲台が回転してマウスカーソルの方向を向くんだ｡
‫また､ ビューポートでクリックしてプレイを開始しても､ マウスカーソルを動かして砲台を回転させたり､
‫方向を設定したりすることができますね｡
‫これによって､ 弾丸を発射する能力があるときに､ 狙いを定めることができるようになるのです｡
‫なるほど｡
‫そのためには､ 砲塔を向けたい方向を見つける必要があります｡
‫そして､ その方向が決まれば､ あとはタレットのメッシュの回転を設定すればいいのです｡
‫さて､ 砲塔の向きを決めるには､ 少しベクトル計算をする必要があります｡
‫探しているのは､ 戦車の砲塔から追跡したヒット位置までのベクトルです｡
‫これで､ 戦車やその構成部品の位置､ 例えば戦車の砲塔の位置などを簡単に取得できるようになりました｡
‫この場所を､ タレット､ ロケーションと呼ぶことにします｡
‫そして､ トレースヘッドの位置を知る方法もわかっています｡
‫これをトレースヒット位置と呼ぶことにする｡
‫ここで気になるのは､ 砲塔の位置からトレースヒット位置までのベクトルです｡
‫このベクトルをターゲットと呼ぶことにする｡
‫さて､ ターゲットに到達するためのベクトル計算は､ 実はとてもシンプルです｡
‫始点から終点までのベクトルを得るには､ 常に終点から始点を引いた値になります｡
‫つまり､ トレース､ 命中位置から砲塔位置のベクトルを引くと､ その結果得られるベクトルはターゲットになります｡
‫さて､ 2つの目標方向ベクトルができたら､ それを回転に変換して､ 戦車の砲塔の回転を設定したいと思います｡
‫そして､ ベクトル型にはrotationという関数が内蔵されている｡
‫つまり､ ターゲットへのベクトルに対してrotationを呼び出すと､ その方向に対応するFローテータが返されることになる｡
‫さて､ ここで気をつけなければならないことがあります｡
‫トレースヒット結果は床に落ちることが多く､ 戦車の砲塔からトレースヒット結果へのベクトルは地面と平行にはなりません｡
‫つまり､ 戦車の砲塔の回転をその方向ベクトルから得られる回転子に設定すると､ 砲塔が地面に向かって下向きになるようなものが得られますが､
‫戦車の砲塔を下向きに回転させたいわけではありません｡
‫まだ前を向いていてほしいのです｡
‫つまり､ これが私たちの望む結果なのです｡
‫つまり､ 戦車の砲塔の回転のうち､ Ya成分だけを変えたいのです｡
‫そうすれば､ 正しい方向を向きつつも､ 地面と平行を保つことができるのです｡
‫今回はヨーのみを変更しましたので､ VSコードに戻り､ 戦車の砲塔を回転させる関数を作成しましょう｡
‫これから戦車の砲塔を回転させますが､ 敵のタワーの砲塔も回転させたいと思います｡
‫タワーはすぐにポン基底から派生して作られるので､ 砲塔の回転関数を作れば､ ポン基底クラスのここに置くことができるということです｡
‫そうすれば､ タンクとタワーの両方がこの機能を継承することになります｡
‫タワーとタンクの両方で使う予定なので､ この機能をプロテクトにすればいいのです｡
‫そこで､ protectedセクションを追加して､ protectedセクションに配置した関数や変数は､ これらの子クラスではアクセスできますが､
‫他のクラスではアクセスできないようにします｡
‫つまり､ プライベート変数とほぼ同じ制約があるわけです｡
‫これで､ この関数はvoidを返すことができるようになりました｡
‫これを回転式タレットと呼ぶことにします｡
‫そして､ 砲塔を回転させるためには､ 見るべき先のようなものが必要になってきますね｡
‫これはfベクトルで､ これをルックアットターゲットと呼ぶことができる｡
‫つまり､ ある関数にワールド内のある種の場所を渡すと､ その場所に向かって砲塔が回転するようになるというアイデアです｡
‫それでは､ タレットを回転させるための関数定義を行ってみましょう｡
‫そこで､ このベースポーンCPのコンストラクタのすぐ下に､ タレットの回転を実装することにします｡
‫そしてもちろん､ ベースとなるポーン・クラス名とスコープ解決演算子がここに必要です｡
‫さて､ タレットを回転させたところで､ これをどのように実装するか考えてみましょう｡
‫まず､ ターゲットベクトルですが､ これはマウスカーソルの下にあるタレット成分からトレースヒット結果までのベクトルです｡
‫つまり､ これはtargetに呼ばれるローカルFベクトルで､ ベクトル計算の結果と等しくなるように設定することができるのです｡
‫出発地から目的地を引いたところになることを忘れないでください｡
‫そして､ 行き先はlook at targetで､ 出発点は戦車の砲塔の位置､ つまり砲塔のメッシュの位置となる予定です｡
‫つまり､ タレットメッシュと言えば､ タレットメッシュの位置が分かるわけです｡
‫さて､ あるコンポーネントのワールドロケーションを取得する方法は､ このget component locationという関数で行います｡
‫使用シーンコンポーネントクラスに属します｡
‫すべてのシーンコンポーネントが持っているわけです｡
‫そこで､ タレットメッシュからコンポーネントの位置の取得を呼び出すことにします｡
‫つまり､ 目標物から砲塔メッシュの位置を引くと､ 砲塔メッシュから見張り目標物までのベクトルが得られます｡
‫さて､ 先ほど述べたように､ Fベクトル回転関数を使って､ ターゲットからEFローテータを得ることができます｡
‫Fローテータを作成し､ これをlook at rotationと呼び､ これをtarget dot
‫rotationに等しく設定します｡
‫それがファンクションコールです｡
‫つまり､ このターゲットへの方向ベクトルに対応する回転子ができたわけです｡
‫しかし､ 私たちはYAにしか関心がないことです｡
‫ピッチや役割を変えたくはないのです｡
‫タレットはz軸の周りに回転させ､ 地面と平行になるようにしたいだけです｡
‫さて､ この方法はいくつもあります｡
‫ひとつは､ 回転､ ピッチを見て､ それをゼロにすることです｡
‫つまり､ ゼロに等しい値を設定します｡
‫また､ ローテーション・ドット・ロールを見て､ これもゼロにすることができます｡
‫さて､ ピッチとロールをゼロにした後､ 欲しい回転は､ コンポーネントだけです｡
‫これもひとつの方法です｡
‫もう一つは､ F ローテーター コンストラクターのオーバーロードの一つを使用することです｡
‫f rotatorとカッコ付きで言って､ 1つ目にゼロ点Fなどの値を渡すと､ ポップアップでその1つ目の入力がピッチであることを教えてくれています｡
‫そして､ 回転をターゲットにするために使用できるヤ｡
‫そうですね｡
‫そして､ 役にはゼロドットFを使うことができます｡
‫これで､ ピッチがゼロ､ ロールがゼロ､ 2つのターゲット回転が返すローテータの成分を持つ新しいFローテータが作成されることになります｡
‫つまり､ これで返される値は､ この3行で行ったのと同じ結果になるのです｡
‫このようにF rotatorコンストラクタを呼び出すことで､ F
‫rotatorから返される回転ベクトルを初期化することができます｡
‫そこで､ この下の行を削除することにします｡
‫そして､ 今度は回転です｡
‫さて､ この関数で最後に行うことは､ タレットマッシュの回転を設定することです｡
‫ここで､ 与えられたコンポーネントの回転を設定するには､ この関数set world rotationを使用します｡
‫ローカルな回転オフセットを追加するのではなく､ セットワード回転を使用する理由は､
‫ワールド空間での回転があるためです 2 ターゲットはワールド空間の方向ベクトルです｡
‫タレットメッシュの位置をワールド空間に取り込み､ ワールド空間のターゲット位置のルックアットを差し引いています｡
‫つまり､ これは世界空間の演出なんですね｡
‫したがって､ ルックアットの回転は､ 世界空間の回転である｡
‫そこで､ タレットメッシュのワールドローテーションを設定することにします｡
‫そこで､ タレットメッシュと言い､ ワールドローテーションを設定し､ ルックアットローテーションを渡すことにします｡
‫これで､ 世界中のどんなターゲットでも､ タレットメッシュを回転させて見ることができる関数ができましたが､
‫メッシュを下向きに回転させることはできません｡
‫ヨーが変わるだけなので､ 戦車の砲塔が回転するような形で回転することになります｡
‫ということで､ 砲台を回転させる機能が出来上がりました｡
‫その砲塔の回転を設定するために､ 戦車クラスのrotate turret関数を呼び出すことに挑戦します｡
‫これは保護された機能です｡
‫だから､ タンククラスはアクセスできるんです｡
‫回転砲塔はFベクトルを取り､ 標的を見るので､ ライントレースから得たFヒット結果にその着弾点を使うつもりだ｡
‫そこで､ コードの中でこの関数を呼び出す正しい場所を見つけるのは､ あなたにお任せすることにします｡
‫そこで､ 動画を一時停止して､ タレットの回転機能を配置します｡
‫戦車クラスで呼び出す｡
‫なるほど｡
‫それでは､ タレットを回転させる関数を用意し､ 呼び出す準備ができました｡
‫タンクアップに入り､ プレイヤーコントローラrefのifチェック内のtick関数を紹介します｡
‫ヒット結果を持っていて､ カーソル下のヒット結果取得が呼ばれた後､ ヒット結果には有効なデータが含まれます｡
‫実は､ そのヒット結果のインパクトポイントを使って､ デバッグ用の球を描いているんです｡
‫これでデバッグ球を描く必要がなくなったので､ 先にそれを削除しておきます｡
‫そして､ その代わりにプロテクトされた関数rotate turretを呼び出すことにします｡
‫そして､ ルックアットターゲットでは､ ヒットリザルト・ドットインパクトポイントでパスすることにしています｡
‫これで､ 毎フレーム､ タレットをヒット結果のインパクトポイントに向かって回転させることになります｡
‫さて､ これをコンパイルする前に､ もうドローデバッグヘルパーは使わないので､ 先に進んでそのヘッダーファイルを削除しておきます｡
‫なるほど｡
‫これで､ コンパイルの準備ができました｡
‫なるほど｡
‫この編集部に戻ってきました｡
‫さっそく再生ボタンを押して確認してみましょう｡
‫これはすごいことです｡
‫まだまだ転がせます｡
‫マウスを動かしても､ マウスカーソルを動かした先で砲台が回転しているんです｡
‫だから､ これはすごいことなんです｡
‫さて､ この話を終える前に､ 2つほど問題点を指摘しておきたいと思います｡
‫これをきれいに磨いて､ 見栄えをよくしてほしいのです｡
‫さて､ 最初の問題は､ マウスカーソルを水槽の中心に近づけてから通過させたときに起こります｡
‫ある時､ そのローテーションが急激に崩れるのがわかると思います｡
‫また､ マウスを無造作に動かしても､ あまり見栄えがよくありません｡
‫折れている｡
‫スムーズな動きができないのです｡
‫それがひとつの課題ですね｡
‫さて､ もうひとつの問題は､ クリックして転がりながら端まで行くと､ マウスカーソルを上に移動させたときに､
‫タレットが別の方向にスナップすることです｡
‫では､ どうなっているのでしょうか？
‫さて､ 確かめてみましょう｡
‫VS Codeに戻り､ デバッグスフィアを取り戻したいと思います｡
‫Tankに戻り､ タレットを回転させる直前のtick関数で､ もう一度､ draw
‫debug sphereを呼び出します｡
‫今､ 私は世界を取得するために渡している 中心は､ 私はヒット結果ドットインパクトポイントを使用します
‫半径は25ドット Fセグメントは12にすることができ､ 色はFカラー赤 永続的な線は偽にすることができ､ 寿命は負の1にすることができます｡
‫だから､ 以前と同じこと｡
‫だから､ このお知らせは保存しておこうと思います｡
‫デバッグヘルパーはデフォルトで含まれているので､ 技術的には必要ないのですが､ ヘッダーファイルを追加し直していません｡
‫エディターでジャンプを保存して､ コーディングのライブキックオフを行い､ 再生ボタンを押すだけです｡
‫これでデバッグスフィアができたわけです｡
‫では､ 世界の端まで行って､ そのマウスカーソルを奈落の底に落ちるところまで動かしてみましょう｡
‫そして､ そこに問題があるのです｡
‫カーソルが上に移動しても､ カーソルの下にヒット結果がないのは､ ヒット結果を得るためのものがそこにないからです｡
‫そのため､ 私たちのインパクトポイントは定義されていません｡
‫そこで必要なのは､ そのライントレースがヒットするものです｡
‫さて､ アンリアル・エンジンには､ 使えるツールがたくさんあります｡
‫ここでドロップダウンをクリックして､ プレースアクターのパネルを開き､ ボリュームと書かれたアイコンを選択して､
‫ブロックボリュームを取得することができます｡
‫ここでブロッキング量です｡
‫そのまま1本引きずります｡
‫だから今､ このブロッキングボリュームがあるんです｡
‫さて､ デフォルトでは､ ブロックボリュームは不可視であるはずです｡
‫詳細パネルでコリジョンまでスクロールすると､ コリジョンプリセットがInvisible
‫Wallになっており､ ほぼすべてをブロックしているように見えます｡
‫ブロックしていないのは可視性チャンネルだけで､ ライントレースはたまたま可視性チャンネルをトレースしています｡
‫私たちの世界で可視性チャネルをブロックしているものはすべて､ 私たちのライントレースにヒットします｡
‫しかし､ この巻はそうではないだろう｡
‫見えないはずのものです｡
‫コリジョンのプリセットで､ ドロップダウンを開き､ カスタムを選択します｡
‫これを変更することで､ コリジョンレスポンスをビジビリティチャンネルに設定することができますね｡
‫ブロックなんです｡
‫つまり､ 私たちのような可視性チャンネルに対してトレースするライントレースは､
‫このボリュームにヒットすることになります｡
‫そこで私ができることは､ このブロッキングボリュームを取り出して､ それをスケールアップすることです｡
‫壁の向こう側にセットする
‫実際､ この壁の境界線に置くことができますし､ 壁と重なるように少し下げます｡
‫そして､ この見えないバリアをY方向にも拡大します｡
‫それを大きくして､ この真ん中に置き､ 少し詰め物をします｡
‫そして､ Z方向にもスケールアップします｡
‫これで､ ライントレースもうまくいくはずです｡
‫では､ その理論を検証してみましょう｡
‫ビューポートでクリックし､ 壁際まで行ってみましょう｡
‫そして確かに､ ライントレースでブロックボリュームに当たっていますし､ タレットが不定な場所を見るために折れるという問題もありません｡
‫その衝撃点のベクトルがすべてゼロなので､ 世界の原点を向いているのでしょう｡
‫今度はこの壁に近づいても､ 同じ問題が発生します｡
‫だから､ このブロッキングボリュームが必要なんです｡
‫私たちのレベルの外周のすべて｡
‫さて､ それはかなり簡単なことです｡
‫このブロッキングボリュームを複製すればいいだけなんです｡
‫これで､ パースビューからトップオルソグラフィックビューに変更することができました｡
‫そこで､ topを選択し､ マウスのホイールでスクロールして､ altを押したままこの壁を複製し､
‫1つをここに置いて､ Eを押して回転モードにすることができます｡
‫そこで､ altを押しながら90度回転させます｡
‫コピーして､ ダブルユーで翻訳モードにし､ それをこちら側に移動して､
‫Altを押したままコピーをこちら側にドラッグします｡
‫これで4つの壁ができたわけです｡
‫トップビューからパースに戻り､ 再生ボタンを押すと､ どの壁に近づいても､
‫どの壁に覆われていても大丈夫になりました｡
‫これで問題のひとつが解決しましたね｡
‫しかし､ このもう1つはどうでしょう？
‫水槽の近くでマウスを動かしても､ このような散発的な挙動が見られます｡
‫だから､ そこも大事にしたいですね｡
‫さて､ これを解決する方法は､ 回転を補間することです｡
‫そこで､ この回転値を直接設定する代わりに､ 補間関数を使用することで､
‫基本的に回転を滑らかに指定した目標に向かって移動させることができます｡
‫では､ その様子をご覧ください｡
‫この補間をタレットの回転関数に組み込み､ ベースポーンに戻りタレットを回転させ､
‫タレットの回転を見るために世界の回転を設定する代わりに､ 補間関数が返す値と同じに設定できるようにしたいのですが､
‫いかがでしょうか？
‫そこで､ 回転を削除して､ 代わりにR inter twoというF math library上の関数を呼び出すことにします｡
‫さて､ 私たちの in two はローテーターの補間を扱うように設計されています｡
‫さて､ その最初の入力パラメータはcurrentと呼ばれるconst F rotator referenceである｡
‫それが､ 変えようとしているものの現在値です｡
‫タレットの回転を変更したいのですが､ タレットメッシュからそれを得ることができます｡
‫ここではタレットメッシュとし､ 使用する関数はコンポーネントの回転を取得するものとします｡
‫つまり､ コンポーネントの位置を取得するのと同じように､ 回転を取得するのです｡
‫さて､ 次の入力はTargetと呼ばれるFローテータです｡
‫それが価値です｡
‫この砲塔のメッシュの回転を解釈して､ スムーズに接近できるようにしたいのです｡
‫それが､ ローテーションの見方です｡
‫だから､ ローテーションを見ろということになるんです｡
‫次の入力はデルタ時間です｡
‫だから､ 私たちはデルタタイムの重要性を知っているのです｡
‫物を動かしたり､ 回転させたりする場合､ その動きはフレームレートに依存しないようにしたいのです｡
‫その分､ デルタタイムを確保できるわけです｡
‫単純にゲームプレイのスタティックを入れればいいし､ 記憶力のいい人なら､ includeがkismet slash gameplay
‫staticsだと覚えているはずです｡
‫ここでゲームプレイのスタティック関数にアクセスし､ ワールドデルタ秒を取得します｡ このとき､ ワールドコンテキストオブジェクトが必要になることを忘れないでください｡
‫だから､ これをそっちに回すんです｡
‫そして最後に､ 社内スピードが必要です｡
‫内部速度の値が大きいほど､ 目標に向かって速く補間することになる｡
‫この値を例えば5Fに設定すると､ かなりゆっくり補間されることになります｡
‫では､ この様子をご覧ください｡
‫これがすべて1行にまとまっていて､ 画面からはみ出るほどです｡
‫そこで､ 世界の回転を設定するための入力を､ このように独立した行に配置します｡
‫だから､ そのまんま｡
‫そして､ インタプリタが､ これら4つの入力パラメータを持ち､ 画面外を走っています｡
‫そこで､ それぞれを独立した行に設定することにします｡
‫そうすれば､ あのように画面をスクロールすることなく､ すべての入力を見ることができるのです｡
‫わかりました｡
‫このまま保存して､ ライブコーディングを開始するつもりです｡
‫再生ボタンを押してマウスを動かすと､ 回転にしばらく時間がかかることがわかります｡
‫それは､ その目標回転に向かって滑らかに補間しているからです｡
‫さて､ これは素晴らしいことです｡
‫それこそ､ 私が欲しかったものです｡
‫どうマウスを動かしても､ あのキビキビしたジャキジャキとした散発的な動きは出せないのです｡
‫今､ 5というのはものすごく遅いインターネット速度ですが､ それを変えることができるんです｡
‫もう少し速くできるはずです｡
‫これを25に設定して､ どう見えるかを見て､ 自分のゲームに合った値を決めてもらうことにします｡
‫だから､ もう1回､ ライブコーディングを蹴って､ 再生ボタンを押してください｡
‫これでかなり高速な補間ができるようになったのですが､ スナップが効きません｡
‫それでも早いんですが､ 瞬発力がないんです｡
‫だから､ こういうことをやっていない限り､ まあ､ それはないでしょう｡
‫クレイジーな行動
‫もちろん､ もっとゆっくり回転させたい場合は､ その方法はもうお分かりでしょうし､ デバッグ球の描画も終わりましたので､
‫先にそれを削除しておきますね｡
‫なるほど｡
‫要約すると､ タレットの回転を設定し､ ワールド内の点に対応するFベクトルであるルックアットターゲットを渡しています｡
‫今はトレースヒット結果だけを使っています｡
‫さて､ この関数をベースとなるポンクラスに入れ､ protectedにしたことで､ タンククラスの関数を継承することができました｡
‫そして､ ベースとなるタワークラスを作る準備ができたら -- そのタワークラスはこのrotate
‫turret関数を継承して､ 再利用できるようになります｡
‫あとは合格するだけです｡
‫ターゲットの新しい姿として､ ベースから派生したタワークラスの作成に取り組む--というのが､ これからの講義です｡
‫また､ お会いしましょう｡