‫こんにちは､ お帰りなさい｡
‫これで戦車を前進､ 後退させることができましたが､ 実際に操縦する方法はありません｡
‫そこで､ このビデオでは､ ローカルローテーションというものを使って､ 実際に水槽を回転させる作業をします｡
‫アクターローカルオフセットを追加するための回転アナログです｡
‫さて､ アクターのローカルオフセットには複数の入力パラメータがあり､ 他の3つはオプションであるため､ 最初の1つだけを渡しました｡
‫しかし､ そのほかの3つのうち1つは､ 掃除に関係することでした｡
‫そして､ ローテーションの実装を続ける前に､ スイープについて少し説明します｡
‫というわけで､ ADD Actor Local Offsetのドキュメントに戻りました｡
‫では､ これらの入力パラメータを今一度見てみましょう｡
‫2つ目はB Sweepと呼ばれるもので､ ブーリアンです｡
‫さて､ もう少し下にスクロールして､ Bスイープの情報を読んでみると､ 「目的地までスイープして､
‫途中でオーバーラップを起こし､ 何かに遮られた場合は目的地の手前で停止するかどうか」と書かれています｡
‫さらに､ ルート部品のみを掃引し､ ブロッキングコリジョンをチェックするとも書かれています｡
‫子部品は掃くことなく動きます｡
‫コリジョンがオフの場合､ 効果はありません｡
‫では､ これがどういうことかというと､ ゲームプログラミングでは､ スイープが有効である限り､ エンジンが行う技術です｡
‫この円で表現された球体のような移動体がある場合､ この球体が移動するたびに､ エンジンはスイープチェックを実行しているのです｡
‫これは､ このフレームでその動きが2つのオブジェクトの間に重なりをもたらすかどうかをチェックしていることを意味します｡
‫このブロックは､ この長方形で表現されています｡
‫ここで､ 世界にこの2つしかない物体を考えてみましょう｡
‫球体がオブジェクトに向かって移動している間､ エンジンはこの2つのオブジェクトが重なっているかどうかをチェックしているのです｡
‫さて､ 球体が動き続けている間に､ あるフレームで球体が移動して､ もう一方のオブジェクトに重なったとします｡
‫スイープを有効にすると､ エンジンはこの重なりを検知して､ 球体を特定のフレームに戻し､
‫実際にオブジェクトを貫通することがないようにします｡
‫これで､ 実際に球体が物体を貫通する様子は見られなくなりました｡
‫その重なりを､ 実際に動作が実装される前にエンジンがキャッチするのです｡
‫その結果､ 球体が重なる寸前で止まっていることがわかるわけです｡
‫ですから､ 例えばこの長方形が壁だったとしたら､ 球体は壁の表面で止まってしまうのです｡
‫それが､ 掃除の成果です｡
‫現在､ ドキュメントには､ コリジョンがオフの場合､ これは何の効果もないと書かれています｡
‫そのため､ スイープを行うにはコリジョンを有効にする必要があります｡
‫そして､ 必要であれば､ ここに別の入力パラメータを渡すことができます｡
‫2つ目はスイープのブール値で､ ここに真を渡すことができます｡
‫では､ これをコンパイルして､ スイープを有効にした場合の効果をみてみましょう｡
‫再生ボタンを押して､ 例えば壁を通り抜けようとすると､ 壁を突き抜けていくのがわかります｡
‫だから､ 何かがうまくいっていないのです｡
‫では､ そのBPポンドタンクのルート部品とは何なのかを見てみましょう｡
‫思い出してください､ ルートにはカプセル部品を使いました｡
‫だから､ BP池の水槽で選んだカプセル成分で｡
‫詳細パネルに移動し､ 下にスクロールすると､ ここにCollisionというセクションがあります｡
‫そして､ ここにコリジョンプリセットがあり､ ドロップダウンがあります｡
‫では､ それを広げてみましょう｡
‫さて､ コリジョン プリセットはいくつでも設定することができますが､ デフォルトでは､ すべてのダイナミックなオーバーラップを見ることができます｡
‫さて､ お使いのアンリアル・エンジンのバージョンによりますが｡
‫ここに他のものが見えるかもしれませんが､ これを変更することができます｡
‫ドロップダウンを選択して､ block all dynamicを選択すると､ 以下のグレーアウトされたオプションが変更されます｡
‫ここでは､ 3列のチェックボックスが表示されています｡
‫これは衝突に対する応答で､ 左の欄には衝突オブジェクトの種類のリストが表示されます｡
‫つまり､ 任意のコンポーネントは､ 独自のコリジョンオブジェクトタイプを持つことになります｡
‫カプセルのオブジェクトタイプがワールドダイナミックに設定されていることに注目してください｡
‫また､ コリジョンプリセットをすべてのダイナミックをブロックするように変更すると､ 他のすべてのコリジョンオブジェクトタイプに反応して､
‫コリジョン応答がすべてブロックするようにチェックされていることがわかります｡
‫では､ 再生ボタンを押して､ モノを通過させてみるとどうなるか見てみましょう｡
‫と重なるギリギリのところで止まっているのがわかると思います｡
‫他の池のこと｡
‫では､ 水槽を動かして壁と重なるようにし､ 他の池を回り込むようにするとどうでしょう｡
‫今は､ 再生ボタンを押すと､ 壁もブロックしてしまいます｡
‫つまり､ このコリジョンプリセットブロック､ オールダイナミックは､ 他のすべてのオブジェクトタイプをブロックするコリジョンレスポンスを設定します｡
‫また､ コンポーネントパネルでコンポーネントを選択し､ 詳細パネルのコリジョンセクションまでスクロールしてコリジョンプリセットのドロップダウンを開くと､
‫特定のコンポーネントのコリジョンオブジェクトタイプを常に確認することができます｡
‫ベースメッシュを選択し､ そのオブジェクトタイプをワールドダイナミックにし､ すべてをブロックするように設定しています｡
‫カプセルコンプのコリジョンプリセットですべてのダイナミックをブロックするように設定したので､ スイープが機能していることがわかります｡
‫そして､ ルートコンポーネントのみを掃引し､ ブロックの衝突をチェックすることをドキュメントで確認しました｡
‫ですから､ 他の部品がどう設定されているかはあまり関係ありません｡
‫ルートコンポーネントが何かをブロックしていないかどうかを確認しているだけです｡
‫さて､ 一部の生徒がつまずく問題として､ カプセルをセットしてすべてのダイナミックをブロックすると､ すぐに移動できなくなることがあります｡
‫さて､ その原因のひとつに､ カプセルが床と重なっていることが考えられます｡
‫カプセルが床と重なっている場合､ エンジンがブロックするように設定されているものとカプセルの部品が重なっている場合､
‫戦車を移動させることができないため､ 移動することができません｡
‫ですから､ これを簡単に解決するには､ カプセルが床と重ならないようにすることです｡
‫さて､ BP -- タンクに入り､ カプセルがちょうどこのホイールの上にあることを確認します｡
‫オルソグラフィックビューにする｡
‫そして､ ベースメッシュを選択し､ それを下に持ってくるだけです｡
‫つまり､ カプセル部品のすぐ下にホイールがあるわけです｡
‫では､ メッシュがちょうど床の上にあり､ カプセルがメッシュのすぐ上にある場合です｡
‫動けるようになるはずです｡
‫だから､ 再生を押して､ そこに行くんだ｡
‫さて､ 掃き出しが終わったところで､ いよいよローテーションの実装に入ります｡
‫プロジェクトの設定に戻りましょう｡
‫edit project settings "で "input "までスクロールし､ "input "セクションで軸のマッピングを設定します｡
‫これでもう大丈夫です｡
‫前に進む｡
‫次はTurnという曲で､ TurnにはDとAが割り当てられていて､ Dはスケールが1､ Aはスケールがマイナス1になっています｡
‫DとAXを使ってタンクを回転させたいと考えています｡
‫そこで､ 回転軸マッピングに関数をバインドするために､ バインドする関数が必要です｡
‫Vのコードに戻り､ タンクファイルに移動して､ 回転軸マッピングにバインドする関数を作成することにします｡
‫さて､ このvoid関数をturnと呼び､ moveと同じようにします｡
‫これはfloatの入力パラメータを必要とし､ この値を呼び出すことにします｡
‫この関数を宣言したので､ 定義してタンクCPとし､ move関数のすぐ下に置くことにします｡
‫そこで､ 関数本体を与えたのですが､ 関数名の直前にダブルコロンと一緒にクラス名が必要です｡
‫これで､ ちゃんとした機能ができました｡
‫さて､ やるべきことはこれだけではありません｡
‫この関数がturnという軸マッピングに束縛されていることを確認する必要があります｡
‫プレイヤー入力コンポーネントのセットアップで､ 前進軸のマッピングと同じように行います｡
‫プレーヤー入力コンポーネントと言い､ 矢印演算子と軸の結合を行います｡
‫さて､ 最初のパラメータは､ テキストマクロでラップされた軸のマッピング名となります｡
‫そこで､ 軸のマッピング名としてturnとすることにしました｡
‫次に､ 関数をバインドするオブジェクトです｡
‫これを渡して､ 最後にまたバインドしたい関数を渡します｡
‫オペレーターのアドレスが必要で､ 戦車で回ることになる｡
‫だから､ それくらい簡単なことなんです｡
‫ターン機能をターン軸マッピングにバインドしました｡
‫あとは､ ターン機能で実際に何かを行うだけです｡
‫さて､ ADD Actor Local offset を見てきましたが､ この関数には回転方向のアナログがあり､ ADD Actor
‫Local rotation と呼ばれています｡
‫この関数には､ F ローテーターを受け取るバージョンと､ F クワッドと呼ばれるものを受け取るバージョンの
‫2 種類があることがわかります｡
‫今回はFローテータを取るバージョンを使用します｡
‫デルタ回転と呼ばれるものです｡
‫また､ ADD Actor Local offsetと同様に､ Sweepパラメータと他の2つの入力パラメータを取ることができます｡
‫そして､ これら最後の3つの入力パラメータは､ アクターローカルオフセットを追加するのと同様､ オプションです｡
‫そこで､ Fベクトルの代わりに､ Fローテータを渡すことにします｡
‫F rotatorを右クリックして定義に進むと､ rotatorに移動し､
‫float型の3つのパブリックメンバ変数が表示されます｡
‫さて､ FベクトルFローテータと同じように､ X､ Y､ Zの代わりに､ ピッチ､ ヨー､ ロールの3つの成分を持っています｡
‫さて､ ここで気になるのがヨーの成分です｡
‫Z軸を中心とした上軸周りの回転を括弧書きで書いてあります｡
‫そして､ この回転は､ Z軸を中心に回転することにこだわる唯一のタイプです｡
‫そうやって戦車の舵取りをするのです｡
‫さて､ Fローテータにも複数のコンストラクタがあり､ Fベクタと同じようにデフォルトでは初期化なしとなっていることを指摘します｡
‫そこで､ floatを1つだけ受け取るものを使えば､ すべてのコンポーネントはそのfloatの値で初期化されます｡
‫フロート値が3つあるものがありますが､ 他のものも見てみてください｡
‫さて､ ゼロローテーターがあることも指摘しておきますが､ ちなみにこれはスタティック・ゼロローテーターです｡
‫そのため､ タンクCPに戻って､ equals F rotator zero rotator zero rotatorは静的メンバ変数であり､
‫スコープ解決演算子でクラス名を指定して､ その静的変数や関数を名前で参照すれば､ このように静的メンバ関数や変数にアクセスできるようになるのです｡
‫それが､ 私たちがここで皆さんと一緒にやっていることです｡
‫ゲームプレイのスタティックはワールドデルタ秒を取得するスタティックです｡
‫つまり､ ゲームプレイ静的クラスの実際のインスタンスがなくても､ その静的関数にアクセスすることができます｡
‫もう存在しているだけなんです｡
‫ゼロローテーター､ ゼロベクトルも同様です｡
‫ローテータhをクローズアウトして､ このデルタ回転があり､ ローテータがゼロに初期化されているわけです｡
‫これで､ FベクトルのX､ Y､ Zがゼロになったのと同様に､ ピッチとロールがゼロになりました｡
‫そのため､ このコンポーネントを変更する必要があります｡
‫そこで､ MOV関数のデルタ位置でやったように､ デルタ回転の疑似コードを作ってみましょう｡
‫もちろん､ フレームレートに依存しない旋回をしたいので､ デルタ時間でスケーリングされた値に設定する必要があります｡
‫これを設定したら､ ローカル回転を追加して､ 各フレームでFローテータに従ってアクタを回転させ､
‫Yaを値でスケーリングします｡
‫つまり､ 何もキーを押していなければ0になり､ DXとaxを押していれば値を持つことになります｡
‫そこで､ 今度は挑戦です｡
‫これは､ アクターのローカルオフセットを追加するのと同じように機能することになります｡
‫ただ一つ違うのは､ 今は役者を交代させていることです｡
‫アクターを回転させるためにある種のターンレートが必要なので､ ターンレート変数を作成し､
‫これをフロートにして､ スピード変数のすぐ隣のプライベートセクションに置きます｡
‫この変数をあなたのプロパティで公開し､ 適切な新しいプロパティ指定子を選択してください｡
‫次に､ turn 関数で､ 特に Delta rotation を設定するつもりです｡
‫私たちは､ あなたのコンポーネントを気にして､ 値を turn rate 変数の値に等しくして､
‫delta time を掛けてから､ この f rotator を渡して､ add
‫actor local rotation を呼び出す準備ができました｡
‫なるほど｡
‫だから､ これはかなりシンプルなものになるんだ｡
‫ターンレート変数があればいいんです｡
‫今度は､ スピードのすぐ下のタンクに入り､ フロート回転数を作成します｡
‫さて､ あなたはおそらくこれを何らかの値で初期化するでしょうし､ それでいいのです｡
‫選んでいるものと違うなら､ 45Fで様子を見ようと思っています｡
‫しかし､ これをブループリントに公開することで､ 開発中に変更できるようにするのです｡
‫あとはどこでも編集できるようにしたいので､ スピードと同じカテゴリの動きにくっつけようと思っています｡
‫そこで､ このあなたのプロパティを盗んで､ 右回転の上のここに貼り付けて､ どこにでも設定できるようにします｡
‫今すぐカテゴリ移動､ 戦車CP｡
‫デルタ回転のイヤーができた｡
‫そこで､ デルタ回転とします｡
‫そうですね｡
‫そして､ 値の時間､ 回転率の時間､ デルタ時間に等しくなるように設定するつもりです｡
‫もちろん､ Uゲームプレイのスタティックでデルタタイムを取得することもできます｡
‫そこで､ それをそのまま貼り付けます｡
‫今､ 私の擬似コードは正確に一致していないことがわかりました｡
‫順番が違うんです｡
‫デルタタイムは､ ここでは真ん中です｡
‫3つの値を掛け合わせる場合､ どのような順番で掛け合わせても同じ結果が得られるので問題ない｡
‫だから一応､ この3つの値を違う順番でかけても､ 計算結果は同じになる｡
‫だから､ あまり気にしないでください｡
‫今度はデルタ回転です｡
‫あとは､ add actor local rotationを呼び出すだけです｡ Delta rotationを渡し､ 2番目の入力には､
‫回転時にスイープを有効にするためにtrueを渡すつもりです｡
‫では､ これをコンパイルしてみましょう｡
‫よし､ これでまとまった｡
‫次のビデオでは､ ゼロベクトルとゼロローテータがこれらのラインから失われていることにお気づきでしょう｡
‫というのも､ 最初はこれらを初期化していたのですが､ 後から､ これらは少なくともゼロ値で初期化されるべきなのだろうと気づいたからです｡
‫ゼロベクターとゼロローテーターはそのままで､
‫近いうちにビデオでお見せします｡
‫だから､ 心配しないでください｡
‫もし､ これらの初期化のものが表示されない場合は､ そこにあるはずです｡
‫そして､ 再び編集部に戻ってきました｡
‫再生ボタンを押してみましょう｡ Dキーで回転させ､ Aキーで反対方向に回転させ､
‫前進と後退も可能です｡
‫だから､ 回転して前進することができるようになった今､ 私たちは世界中を移動することができるようになったのです｡
‫これは大きな節目です｡
‫今はかなりゆっくり動いていますが､ 戦車を選択し､ 移動のカテゴリーを検索してターンレートを90など高いものに変えられるので大丈夫です｡
‫では､ さっそく再生を押してみましょう｡
‫しかも､ かなり高速化されています｡
‫さて､ これでも少し遅いと思われた方｡
‫もちろん､ これらを調整することも可能です｡
‫そこで､ もう一度 -- タンクを選択します｡
‫そして､ 400ではなく､ 800にしよう｡
‫なぜダメなのか？
‫90ではなく､ 例えば120にしよう｡
‫今､ 再生ボタンを押したら､ かなり速くなりました｡
‫だから､ これは本当に､ 本当にいい感じです｡
‫そこで､ セクションプランを振り返ってみると､ 世界中を移動できる戦車が出来上がりました｡
‫最初の箇条書きは確実にチェックされていますし､ WASDの動きにも対応しています｡
‫まだ､ マウス入力は扱っていませんが､ そのうち扱えるようになるでしょう｡
‫しかし､ このゲームの完成に一歩近づいたと言えるでしょう｡
‫まとめると､ スイープとは何か､ そしてオブジェクト同士がすれ違わないようにするためにはどうすればよいかを学びました｡
‫アクターのローカルローテーションを追加し､ 細部で調整可能なターンレートを実装して行いました｡
‫開発を少しでも楽にするために､ エディタにパネルを設置｡
‫素晴らしい仕事です｡
‫今､ 私たちは世界中でタンクを動かしています｡
‫次の動画でお会いしましょう｡