Player State で GetPlayerName() という関数を使用します。 OverheadWidget を使用して、プレーヤーの名前を頭上に表示できるかどうかを確認してください。
すべてのクライアントとサーバーで確認できますか? なぜですか、そうでないのですか?
Druid Mechanics Discord の ⚙|optional-challenges チャンネルで作品を共有してください。
Player State で GetPlayerName() という関数を使用します。 OverheadWidget を使用して、プレーヤーの名前を頭上に表示できるかどうかを確認してください。
すべてのクライアントとサーバーで確認できますか? なぜですか、そうでないのですか?
Druid Mechanics Discord の ⚙|optional-challenges チャンネルで作品を共有してください。
アンリアル エンジンへようこそ。
マルチプレイヤー ゲームでは、何らかの方法で移動する必要があります。 このレクチャーでは、シームレスな移動がどのように機能するか、シームレスでない移動よりも優先される理由、およびそれが何を意味するかについて説明します。
遷移レベルを作成して、あるレベルから別のレベルに移動するたびにシームレスな移動を設定できるようにします。 十分な数のプレイヤーが集まったら、ロビーから実際のゲームに移動できるように、ロビー ゲーム モードを作成します。
それでは、まず非シームレス TRAVEL について話しましょう。 UNREAL ENGINE には、主に [シームレス] と [非シームレス] の 2 つの移動方法があります。
クライアントがシームレスに移動しない場合は常に、現在のサーバーから切断され、同じサーバーに再接続されます。 もちろん、これには切断と再接続に時間がかかり、異なるレベルに移動するたびに再接続するときに問題が発生する可能性があります. シームレスな移動を使用することをお勧めします。
初めてマップをロードするときに、シームレスでない移動が発生します。 サーバーに初めて接続するとき、およびマルチプレイヤー マッチまたはゲームが終了して新しいものが開始されるときも同様です。 これにはシームレスではない移動が含まれ、すべてのクライアントは切断してからサーバーに再接続して再度プレイする必要があります。
現在、シームレスな移動は、Unreal Engine での移動に好まれる方法です。 クライアントがサーバーから切断する必要がないため、よりスムーズなエクスペリエンスが得られます。
また、サーバーまたはサーバーが見つからない、突然プレイヤーが多すぎてプレイヤーが再参加できないなどの再接続の問題を回避するのにも役立ちます。
プロジェクトのシームレスな移動を可能にすることができます。 これはゲームモードで行います。 ゲーム モードには bUesSeamlessTravel というブール変数があり、これを true に設定してシームレスな移動を使用できます。
遷移マップまたは遷移レベルが必要です。 これは、あるマップから別のマップに移行するために使用できる単純な小さなレベルです。
遷移マップが必要な理由は、マップが特定の時点で常に読み込まれる必要があるためです。 したがって、遷移マップなしであるマップから別のマップに移動するには、最初のマップがまだロードされている間に 2 番目のマップをロードする必要があります。
そして、これには膨大な量のリソースが必要になる可能性があります。 そのため、遷移マップを使用して、既に存在していた元のマップを分解する前にそれをロードします。 移行マップに入ると、新しいマップをロードできます。両方の大きなマップを同時に存在させる必要はありません。
さて、[TRAVEL] とマルチプレイヤーについて説明してきました。 [TRAVEL]には複数の方法があります。 それらの方法の 1 つは、serverTravel を呼び出すことです。 これは、あなたの WORLD に属する機能です。 WorldServerTravel はサーバー専用です。 サーバー マシンは serverTravel を呼び出し、サーバーが serverTravel を呼び出すと、サーバーは新しいレベルにジャンプします。
接続されているすべてのクライアントは、サーバーが移動しているマップに従います。 サーバーは、接続されているすべてのプレーヤー コントローラーを取得し、プレーヤー コントローラー クラスに存在する関数 clientTravel を呼び出すことによってこれを行います。 clientTravel は、呼び出し元によって異なることを行います。
[クライアントから呼び出される] と、クライアントは [新しいサーバー] に移動します。 クライアントは、移動先の ADDRESS を提供する必要があります。 ただし、[サーバーから呼び出された]場合、これにより、プレーヤーはサーバーによって指定された[新しいマップ]に移動します。
次に、ロビー レベル用に作成するゲーム モードで serverTravel を使用します。 このようにして、十分な数のプレイヤーが参加すると、serverTravel を呼び出して、接続されているすべてのクライアントをサーバーに従ってゲーム マップに移動させることができます。
すでに 2 つのマップがあります。 gameStartupMap があります。再生を押すと、メニュー システム プラグインにあるメニュー ウィジェットが表示されます。
これまでのところ、プレイヤーはサーバーです。 マルチプレイヤーは存在せず、シングル プレイヤー ゲームでは唯一無二のプレイヤーがサーバーです。
ホストをクリックして Steam セッションを作成すると、最終的にプレイヤーはロビー レベルに移動し、他のプレイヤーが参加するのを待ちます。
これが私たちのロビーレベルです。 menuSystemPlugin は serverTravel を呼び出してこれを行います。 これでロビー レベルができたので、実際のゲーム レベルである新しいレベルに移動したいと思います。
そのために十分な数のプレイヤーが参加したら、参加者数をカウントできるロビー ゲーム モードを作成します。
それでは、新しいゲーム モード クラスを作成しましょう。 [C++ クラス] と [Blaster] に行きます。 ここで新しい C++ クラスを作成します。 それでは、右クリックして新しい C++ クラスを作成しましょう。[すべてのクラス] を選択し、ゲーム モードを検索します。
Unreal Engine には [game mode] と [game mode base] があります。 このプロジェクトでは [ゲーム モード] を使用します。 [ゲームモードベース] にはない追加機能があるためです。 そして、マルチプレイヤー ゲームを実装するときに、その追加機能についてさらに学習します。
[ゲームモード] を選択して、[次へ] を選択します。
ここで、このコース全体で複数のゲーム モードを作成しますが、それらはすべて独自のフォルダーに保存したいと考えています。
それでは、Blaster に Game Mode という名前の新しいフォルダを作成しましょう。 このゲームモードはロビー用です。
それでは、このロビー ゲーム モードを呼び出して、[クラスの作成] をクリックします。
クラスと独自のフォルダーを作成するときに見た、おなじみのメッセージが表示されます。 いいえをクリックするだけです。
これがロビー ゲーム モードです。 ゲーム モード フォルダにあることがわかります。
そして、robyGameModes.cpp のインクルードから「gameMode」を削除することで、コンパイラ エラーを取り除くことができることがわかりました。
ここで、lobbyGameMode は 1 つのことを行う必要があります。 ロビー レベルに接続または移動したプレイヤーの数を確認する必要があります。 一定の数が入力されると、これから作成する実際のゲーム マップに移動できます。
gameMode を継承した関数 postLogin を使用して、参加するプレイヤーを追跡できます。 この関数をオーバーライドします。
[lobbyGameMode.h] に public セクションを作成します。 そして、仮想関数 postLogin をオーバーライドします。 ログイン後はバーチャルボイドになります。
この関数は、NewPlayer というポインターである APlayerController を受け取ります。これはもちろんオーバーライドです。
それでは、PostLogin の関数定義を作成しましょう。 これが postLogin 関数です。
これまで見てきたように、これらの関数をオーバーライドするときは [super] を呼び出す必要があります。 [super::postLogin] を呼び出して、NewPlayer を渡します。
postLogin は、ゲームに参加したばかりの playerController に安全にアクセスできる最初の場所です。
現在、Game State と呼ばれるクラスが存在します。 実際、ゲーム モードには Game State という変数があります。 gameState 変数は gameStateBase を保持し、この Game State にはゲームに参加したプレイヤーの配列があります。 具体的には、playerStates の配列です。
ここで、このコースでの [gameStates] と [playerStates] の役割について説明します。 しかし今のところ、知っておく必要があるのは、ゲームに参加した playerState の数だけです。 これで、ロビーにいるプレイヤーの数がわかります。
ここで Game State にカーソルを合わせると、それが TObjectPointer であることがわかります。 実際、右クリックして gameState 変数の定義を選択すると、gameState が AGameStateBase をラップする TObjectPointer であることがわかります。
TObjectPointer は Unreal Engine 5 で導入された新しいタイプのラッパーで、これらのエンジン クラスの変数の一部に使用されます。 これで、開発中のエディターとエディターにいくつかの機能が提供されます。 Unreal Engine は、「これによりアクセス トラッキングが提供されるため、オブジェクトがいつ使用されているかを実際に検出できる」と述べています。
しかし、この目的のために知っておく必要があるのは、gameState がこの型 TObjectPointer を持ち、get 関数を使用して TObjectPointer によって格納された gameStateBase ポインタにアクセスできることだけです。
したがって、gameState 変数を取得して [.Get] を呼び出すと、AGameStateBase ポインターが返されます。
ここで、gameStateBased クラスを使用します。つまり、そのヘッダー ファイルをインクルードする必要があります。 また、gameStateBase は gameFramework に存在します。 それは gameStateBase.h と呼ばれます。
gameState にアクセスしたら、そのプレーヤー配列を取得できます。 これは単に playerArray と呼ばれる TArray です。 カーソルを合わせると、playerStates を保持するこれらの TObjectPointers の TArray であることがわかります。
この配列には、ゲームに参加した各プレイヤーの playerState が含まれています。 TArray であるため、配列内の要素数を int32 として返す TArray.Num 関数があります。 これは、ゲームに参加しているプレイヤーの数を示しています。
これで、numberOfPlayers という名前の int32 を作成し、この配列の長さと等しくなるように設定できます。
これで、誰かがゲームに参加するたびに、ポスト ログインが呼び出され、この整数のプレイヤー数が参加したプレイヤーの数を示すゲーム モードが発生することがわかります。
これで、この数をチェックして、ゲームに参加しているプレイヤーの数を確認できます。 プレイヤーの数が一定数に達すると、新しいレベルに移動することを決定できます。 それが私たちがやりたいことです。
そのため、プレーヤーの数が特定の数に等しいかどうかを確認します。 今のところ、[2] はハード コーディングされた [2] を使用します。 しかし後で、これに変数を使用します。 しかし、今のところ、これがどのように機能するかを確認したいと思います。
serverTravel を呼び出して、接続しているすべてのクライアントを特定のマップに移動できることがわかっています。 MAP に移動するには、移動先の MAP が必要です。
それでは、エディターに戻って、maps フォルダーに戻りましょう。 そして、移動先の新しいマップを作成したいと考えています。 それでは、新しいレベルを作成しましょう。
アセットには learningKitGames があり、maps フォルダーにあることがわかっています。 これが LearningKit_games_showcase です。 さて、私がこのレベルに進む理由は、多くのアセットで満たされているためです。これらのアセットを使用して、実際のゲームの見栄えの良いマップを作成できます。
ですから、このレベルを複製します。 このレベルをマップ フォルダにドラッグし、[ここにコピー] を選択します。 Maps フォルダには、LearningKit_Games_Showcase があります。
これで改名します。 これが、ゲームを開始するときに移動するマップであることがわかっています。 これを [blasterMap] と呼ぶことにします。 これで、移動先のマップができました。
ここで、robyGameMode に戻ります。プレイヤーの数が 2 人に達したら、すぐにそのマップに移動したいと思います。 これは、新しいワールド クラスの serverTravel 関数を使用して実行できます。
それでは、UWorld と言うワールドを取得しましょう。 それはポインタです。 このワールドを呼び出し、get world 関数を使用します。 そして、ワールドが有効であれば、単純にワールドを取得して serverTravel を呼び出すことができます。
ここで、serverTravel は移動先の ADDRESS を取ります。 これをサーバーから呼び出す場合、後で説明するように、ゲーム モードはサーバー上にのみ存在します。 したがって、私たちは間違いなくサーバー上にいます。
ゲーム モード クラスの場合、移動したいレベルへのパスを渡すだけで、接続されているすべてのクライアントがそのレベルに移動します。 これは FString なので、FString を作成し、その文字列を BlasterMap へのパスに渡します。
さて、このエディターで、そのパスが何であるかを知ることができます。 本当に、これは [maps] フォルダへのパスです。 [コンテンツ] の代わりに [ゲーム] という単語を使用します。 したがって、ここの FString では、「/game/maps/(レベル名)」と入力します。 これは blasterMap になりますが、このレベルに移動してリッスン サーバーとして指定する必要があります。 したがって、疑問符 (?) を使用して、アドレスにオプションを追加します。 そして、必要なオプションは「LISTEN」です。 これにより、この blasterMap がクライアントの接続先のリッスン サーバーとして開かれることが指定されます。
というわけで、プレイヤー数が 2 人に達したらすぐにブラスター マップに移動します。
ここで、シームレスに移動したいと考えています。bUseSeamlessTravel というゲーム モード クラスに存在するブール変数を設定することで、シームレスに移動できます。これを true に設定できます。
それでは、ここでコードをコンパイルしてみましょう。 これで、エディターに戻ることができます。 エディターで、これを設定するためにいくつかのことを行う必要があります。
まず、ロビー レベルに戻りましょう。生の C++ クラスを使用するのではなく、ロビー レベルのゲーム モードを設定する必要があります。 このためのブループリントを作成したいと思います。
それでは、blueprints に移動して新しいフォルダーを作成し、これを [gameModes] と呼びましょう。 [gameModes] では、新しい設計図を作成します。
右クリックして新しいブループリント クラスを作成し、[すべてのクラス] を選択して、robbyGameMode を選択します。 そして、[選択] をクリックします。 これを BP_lobbyGameMode と呼びます。
そして、lobbyGameMode で、それを開いてみましょう。 [デフォルトのポーン クラス] を選択できます。 BP_BlasterCharacter を選択します。 これで、BlasterCharacter としてロビーを走り回ることができます。
それをコンパイルして保存しましょう。 ロビー ゲーム モードを閉じます。 それをロビーのゲームモードとして設定します。
それでは【ワールド設定】に行きましょう。 [game mode override] ではドロップダウンを選択し、BP_lobbyGameMode を選択します。 ここで、[デフォルトのポーン クラス] が BP_BlasterCharacter であることがわかります。
ゲームモードをオーバーライドしたので、ワールドに実際のキャラクターは必要ありません。 [プレイヤースタート]があるので。 そして、このレベルに移動するプレイヤーは、プレイヤーの開始時にここにスポーンされます。 実際、私はプレーを打つことができます。 そして、私はここの真ん中にいます。
ロビーゲームモードには「シームレストラベルを使用」があります。 ここで、ログイン後にこれを true に設定しましたが、必要に応じてここで true に設定することもできます。 これは、すでに true に設定されていることを意味します。
これで、シームレスな移動の準備がほぼ整いました。 しかし、transitionLevel について話したことを思い出してください。 そのうちの 1 つが必要になります。
マップに戻り、遷移レベルを作成します。 ファイルの新しいレベルに行きましょう。 そして、私たちの遷移レベルは実際には何も必要としません。 実際、小さくてシンプルであればあるほど良いのです。 空のレベルを選択するだけです。 ここで [選択項目を保存] をクリックすると、まったく何もない完全に空のレベルが表示されます。 これは移行レベルに最適です。 ファイルをクリックして現在のレベルを名前を付けて保存し、マップに保存します。 これを [transition map] と呼び、[保存] をクリックします。 これで遷移レベルができました。
それを transitionLevel として使用したいことを Unreal Engine が認識していることを確認する必要があるだけです。 [編集] と [プロジェクト設定] に移動して、[プロジェクト設定] でこれを確認できます。
[遷移] を検索します。 [default maps] の下に表示されます。 [トランジションマップ]。 ドロップダウンを開いて、transitionMap を選択できます。
これで、Unreal Engine はトランジション マップをトランジション レベルとして使用することを認識します。 これで、シームレスな移動を使用するための設定がすべて完了しました。2 人のプレイヤーがロビーに参加するとすぐに、サーバーはポストのロビー ゲーム モードからサーバー移動を呼び出し、ログインすると、全員が blasterMap に移動します。
これを試してみたいと思いますが、その前に、あなたに挑戦があります。 現在、いくつかのマップがありますが、どれも退屈です。 また、Learning Games アセット パックには多くのアセットがあることもわかっています。 挑戦として、私たちのレベルをもう少し面白くしてほしいです。
まず、ゲームの startStartupMap にいくつかのアセットを追加します。 これは、プレイヤーがゲームを開いたときに表示されるマップです。 いくつかのアセットを使用して、見栄えを良くしてください。
ホスト ボタンと参加ボタンのあるメニュー ウィジェットのみが表示されることはわかっています。 そのため、少し創造性を働かせて、ゲームで表示される内容のプレビューをプレーヤーに少しだけ示します。
次に、ロビー マップにいくつかのアセットを追加していただきたいと思います。 さて、ロビーは通常、人が走り回れる小さなエリアです。それほど大きくはありません。 本当にあまりありません。 走ってジャンプして、他のプレイヤーが参加するのを待つだけのエリアです。
最後に、これはおそらく最も野心的な BlasterMap を作成してもらいたいものです。 これは、プレイヤーが実際にゲームをプレイするマップになります。これは、プレイヤーが互いに撃ち合うマルチプレイヤー マッチメイキング タイプのゲームになります。 いくつかの障害物をプレイして、ピックアップや武器、その他のゲームプレイの仕組みをどこに配置するかを考えてください。 高さの変化を試してみてください。 いくつかの隠れ場所を置きます。
全力で行く。 これには、好きなだけ努力してください。 それでは、ビデオを一時停止して、これらのマップを構築して見栄えを良くしてください。 そして、ゲームをパッケージ化してテストします。
わかった。 これらのレベルの作成を楽しんでいただければ幸いです。
ここにロビー レベルがあり、learningKitGames のアセットをいくつか使用しています。 これらの浮島を拡大縮小してここに配置し、Learning Kid Games マップにある花粉などのさまざまな効果を追加しました。 そして、浮島のいくつかを引きずり出し、そこに見えるようにしました。
ゲームのスタートアップ マップでは、キャラクターをここに配置しました。 これはキャラクターの BLUEPRINT ではなく、単なる SKELETAL メッシュです。 そして、詳細パネルを見ると、ここでは別のアニメーション、epic_character_Idle を使用していることがわかります。
したがって、プレイをクリックすると、これがプレイヤーがゲームを最初にロードしたときに表示されるものです。 メニューはまだありますが、キャラクターの素敵な背景ができたので、見栄えがよく、まとめるのにそれほど難しくはありませんでした.
ブラスター マップにも力を入れています。ブラスター マップには、learningKitGames レベルのすべてのアセットが含まれています。 私は単純にすべてのメッシュを取得し、それらを拡大してさまざまな方法で配置し、素敵なシューティング マップを作成しました。
うまくいけば、これがマルチプレイヤー メカニクスを実装するための素晴らしい環境を提供してくれることを願っています。このマップでは多くのプレイヤーが走り回り、互いに撃ち合うことができます。 素晴らしい。
これでテストできます。 これで、パッケージ ビルドでテストする準備が整いました。
さて、この blasterMap にはゲーム モードがないため、BlasterMap の gameModeBlueprint を作成します。 このマップのゲーム モード C++ クラスを作成します。 しかし、私たちはそれに到達します。 今のところ、必要なのは [ゲーム モード] だけなので、[デフォルトのポーン クラス] があります。
[BLUEPRINTS] と [gameModes] に行きましょう。 [Create a new blueprint class] を右クリックして、gameMode を検索します。 そして【ゲームモード】を選んでこちらを選択。 これを BP_blasterGameMode と呼びます。
BlasterGameMode で行う必要があるのは、[デフォルトのポーン クラス] を設定することだけです。 BP_BlasterCharacter を選択します。 playerStart がある場合は、ここにドラッグできます。このレベルのゲーム モードを設定するとすぐに、ここにスポーンします。
[ワールド設定] で、[ゲーム モード オーバーライド] に BP_BlasterGameMode を選択します。 そして、今プレイすると、このレベルで走り回るキャラクターができます。
それでは、このゲームをパッケージ化してテストしてみましょう。 これが私の Unreal Engine Project フォルダです。私が作成したビルド フォルダがあります。 先に進み、ここに存在する古いビルドをすべて削除しました。ここに新しいビルドを配置します。
[プラットフォーム]、[Windows]、[パッケージ プロジェクト] に移動します。 ビルドフォルダーを選択します。 それでは、これをパッケージ化するのに少し時間を割いてみましょう。
さて、パッケージングが完了し、ここに Windows フォルダーがあり、その中に [blaster.exe] があります。 これで、これを zip フォルダーに送信できます。 圧縮が完了したら、Google ドライブにアップロードできます。 さて、これが私がパッケージ化した最後のビルドです。 右クリックしてそれを削除し、圧縮した新しいパッケージ プロジェクトを Google ドライブにドラッグするだけです。
それが終わったらすぐに、別のマシンにダウンロードして、別のマシンで別の Steam アカウントにログインして、このゲームをテストできるようにします。 わかった。 プロジェクトのアップロードが完了し、別のマシンに移動してこの zip フォルダーをダウンロードし、展開しました。
もう 1 台のマシンでゲームを起動しました。別のテスターが参加する準備ができているので、自分のマシンでゲームを起動できます。 Windows フォルダに移動して [Blaster.exe] を実行し、ホストをクリックするだけです。
ここでは、ロビー レベルにいます。ロビー ゲーム モードは、ゲーム状態でそのプレーヤー配列にアクセスできるため、入ってくるプレーヤーの数をカウントしています。
そこで、テスターに他のマシンにログインして参加するように指示します。 そして、他のプレイヤーがここからロビー レベルに移動するとすぐに、ロビー ゲーム モードのポスト ログイン関数は、ゲーム内に 2 人のプレイヤーが存在することを確認し、その時点で serverTravel を呼び出し、2 人とも blasterMap に移動します。 わかった。 プレイヤーが参加し、ここでブラスター マップにシームレスに移行しました。すべてが見栄えがします。 これで、レベル内を走り回り、ゲームをプレイすることができます。
そのため、この講義では多くのことを取り上げました。 シームレスな移動と、それを実現する方法、および移行レベルが必要な方法について説明しました。
次に、実際のゲーム用のブラスター マップと、2 人のプレイヤーがロビーに参加するとすぐにサーバー トラベルを呼び出すロビー ゲーム モードを作成しました。 これで、Blaster マップに移動する準備が整いました。
十分なプレイヤーがゲームに参加するとすぐに、ゲーム自体にいくつかのマルチプレイヤー機能を実装できるようになります。
よくやった。
また後で。
いらっしゃいませ。
このレクチャーでは、ロールの概念と、Unreal Engine のマルチプレイヤー ゲームでロールがどのように使用されるかについて説明します。 これには、ローカル ロールとリモート ロールの概念と、この 2 つの違いが含まれます。
そして、キャラクターの上に表示して現在の役割を表示できる特別なウィジェットを作成して、役割とその使用方法をよりよく把握できるようにします。
それでは、ネットワークの役割について少しお話しましょう。マルチプレイヤー ゲームでは、プレイヤーが制御する特定のキャラクターの複数のバージョンが存在します。
あなたがサーバーに接続しているクライアントの場合、現在操作しているキャラクターは [あなたのマシン] に存在します。
しかし、あなたのキャラクターのバージョンも [サーバー] に存在します。
たとえば、ゲームに 3 人以上のプレイヤーがいる場合は、他のクライアントがサーバーに接続されています。 (その後) [そのクライアントのマシン] にあなたのキャラクターのバージョンがあります。
したがって、3 人用のゲームでは、各マシンに 1 つずつ、合計 3 つのキャラクターのコピーがあります。 そのため、コード内で扱っている CHARACTER のバージョンを区別する方法を知ることが重要になります。 これを整理するために、Unreal Engine にはロールの概念があります。
ENetRole と呼ばれる列挙型が存在します。これには、特定のキャラクターまたはポーンの役割を識別するために使用できるいくつかの列挙型定数があり、その役割には役割権限 enum 定数があり、この役割はサーバー マシン上に存在するポーンに割り当てられます。
Unreal Engine は権限のあるサーバー モデルを使用するため、サーバー上に存在するすべてのポーンが権限の役割を持つと見なされます。
その役割には、ポーンに関しては [シミュレートされたプロキシ] の役割もあります。 これらは、そのポーンを制御していないマシン上に存在する任意のキャラクターまたはポーンのバージョンです。
現在マシン上で制御しているキャラクターまたはポーンには、[自律プロキシ] の役割があります。
ここで、ポーンまたはキャラクターには複数のバージョンがあり、1 つは自分のマシンにあり、もう 1 つは画面に表示される他のマシンにあることに注意してください。
したがって、[自分のマシン] でポーンを制御している場合、ポーンのそのバージョンには [自律プロキシ] の役割があります。
あなたがサーバーではないと仮定すると、あなたがサーバーである場合、ポーンはサーバー上に存在するため、役割権限を持っています。
他のプレイヤーと遊んでいるときに、自分のマシン上のキャラクターまたはポーンのバージョンが、ネットワークを介して別のマシン上の他の誰かによって制御されている場合、そのキャラクターまたはポーンのシミュレートされたプロキシを見ていることになります。 ポーンは別のクライアントによって制御されているか、サーバーによって制御されています。
ENetRole には、ロールが定義されていないアクター用のロール [none] もあります。
それでは、エディタに戻り、新しい C++ クラスを作成しましょう。 これは、キャラクターの頭の上に表示できるウィジェット用です。
[C++ クラス > Blaster] フォルダーにいます。 右クリックして新しい C++ クラスを作成し、すべてのクラスを選択します。 ユーザー ウィジェットに基づいて C++ クラスを作成したいと考えています。そうすれば、ユーザー ウィジェットの C++ 変数を操作できます。
それでは、このウィジェットを作成しましょう。 [次へ] をクリックしましょう。これを独自のフォルダに貼り付けたいと思います。
このフォルダを単に HUD と呼びます。 キャラクターの頭上に表示されるので「頭上ウィジェット」と名付けます。
それでは、クラスの作成をクリックしましょう。
わかった。
したがって、このおなじみのメッセージにノーを押して、ここにオーバーヘッド ウィジェットを用意します。 もちろん、C++ クラスでは、インクルードの HUD 部分を削除して、コンパイラ エラーを取り除くことができます。
これで UUserWidget ができました。これを、キャラクターの頭上にロールを表示するために使用するウィジェット ブループリントの親クラスとして使用します。
さて、このウィジェットは単純にテキスト ブロックを持つことになるので、このテキスト ブロックのタイプは you text block になります。
ここに公開セクションを作成しましょう。
public セクションでは、UTextBlock を前方宣言します。これは UTextBlock ポインターであり、これを [DisplayText] と呼びます。 これで、ウィジェット ブループリントを作成するこのウィジェットの表示テキストを設定できます。
先に進み、そのウィジェットのブループリントを作成しましょう。 ここのブループリント フォルダに、HUD という名前の新しいフォルダを作成します。 HUD フォルダで、右クリックして [User Interface] と [Widget Blueprint] を選択します。これを WPP_overhead_widget と呼びます。
これは単純なウィジェットの設計図になります。 キャンバスパネルは必要ありません。 私が本当に欲しいのはテキストウィジェットだけです。 テキストを選択してドラッグし、テキストのサイズを変更します。
ここで、[overheadWidget.h] です。 [DisplayText] という変数があり、それは UTextBlock です。 したがって、ここのウィジェット ブループリントの変数は、その C++ 変数と同じ名前にする必要があります。 これを [DisplayText] と呼びます。
次に、フォントを太字から標準に設定し、両端揃えを中央に変更します。 そうすれば、それは素晴らしく、中心になります。
これで、このテキスト ブロックのテキストを C++ から制御できます。 その方法は、表示テキストに特定の指定を持つ UProperty を与えることです。 では、これに UProperty を与えましょう。それは [meta = ] として指定され、括弧内にウィジェットをバインドします。 これで、この C++ 変数がウィジェット ブループリントのテキスト ブロックに関連付けられます。
それでは、C++ コードをコンパイルしましょう。 コードをコンパイルして、ウィジェット BLUEPRINT に戻り、BLUEPRINT の親を変更して、その親 C++ クラスがオーバーヘッド ウィジェット C++ クラスになるようにします。
これを行うには、グラフ タブに移動し、クラス設定を選択します。 そして、このクラス オプションの下に、親クラスが表示されます。 これで、ユーザー ウィジェットに基づいてこれを作成しました。 ただし、ドロップダウンを開いて OverheadWidget を選択することで、これを変更できます。
このウィジェット ブループリントは OverheadWidget の C++ クラスの親になり、C++ クラスには DisplayText と呼ばれる UTextBlock 変数があり、BindWidget を指定するメタがあります。 この C++ 変数を変更すると、[DisplayText] TextBlock に影響します。 これを行う場合、WidgetBlueprint 内の TextBlock が C++ 変数とまったく同じ名前であることが非常に重要です。 そうしないと、これは機能しません。
これで、ウィジェットのサイズが変更されたことがわかりました。 このテキスト ブロックに必要なサイズに戻します。
(だから今) このウィジェットを動かしている C++ クラスにいくつかの機能を追加する必要があります。 したがって、ここの C++ クラスでは、いくつかの基本的な機能を追加します。
ここで、ユーザー ウィジェットによって継承された仮想関数をオーバーライドしたいと考えています。 これは保護された機能です。 そこで、保護セクションを追加します。
そして、これは OnLevelRemovedFromWorld と呼ばれる void を返す仮想関数です。 OnLevelRemovedFromWorld は、別のレベルに移行するか、現在のレベルを離れるときに呼び出されます。 これにより、このウィジェットをビューポートから削除できます。
OnLevelRemovedFromWorld は、ULevel ポインター = InLevel と UWorld ポインター = InWorld を受け取ります。 そして、これはオーバーライドです。
では、このための関数定義を作成しましょう。 ここと OnLevelRemovedFromWorld では、このウィジェットを取得してビューポートから削除する RemoveFromParent を呼び出すだけです。
そして、これのスーパーバージョンを呼び出す必要があります。 そのため、super:: OnLevelRemovedFromWorld を呼び出し、InLevel と InWorld を渡す必要があります。 これでウィジェットがクリーンアップされ、ビューポートから削除されます。 だから、まだそこにはありません。
今度は OverheadWidget.h です。 [DisplayText] テキスト ブロックのテキストを設定する関数を作成したいと思います。 そして、これは公開機能になる可能性があります。 これを setDisplayText という void 関数にします。 これは単純に FString を取り、これを textToDisplay と呼びます。 そして、その文字列を使用して、DisplayText を値に設定できます。
関数定義をしましょう。 ここで、[DisplayText] のテキストを設定したいと思います。 そこで、まず [DisplayText] が有効かどうかを簡単に確認します。 そうであれば、[DisplayText] を取り、関数セットのテキストを使用します。 この関数は、このテキスト ブロックのテキストを設定します。
ここでは、テキスト ブロック データ型を使用しているため、そのためのヘッダー ファイルを INCLUDE する必要があります。 また、テキスト ブロック ヘッダーは「components/TextBlock」にあります。 そして、それはヘッダーファイルです。
これで、setText を呼び出すことができます。 これは FText を取ります。 したがって、FString から FText に変換する必要があります。
これで、FromString という FText 静的関数を使用して、この textToDisplay を単純に渡すことができます。 これで、表示テキストを値に設定する FString を渡すことができる便利な関数ができました。
ここで、キャラクターのネットワーク ロールを把握する別の関数を作成したいと思います。
それでは、「overheadWidget.h」に行き、別のパブリック関数を作成しましょう。 そして、これは void 関数になります。 これを単に showPlayerNetRole と呼びます。 InPawn と呼ばれるタイプ APawn の入力パラメータをこれに追加します。
そうすれば、キャラクターなどのどこからでもこの関数を呼び出して、キャラクターへのポインターを渡すことができ、ここでネットの役割を把握できます。
それでは、この関数を定義しましょう。 そして、ここ showPlayerNetRole で、プレイヤーのロールである InPawn のローカル ロールを列挙値として取得したいと考えています。 その列挙型は EMetRole です。
そこで、LocalRole というローカル変数を作成し、それを InPawn->getLocalRole と等しくなるように設定します。 したがって、ポーンから呼び出すことができる関数としてローカル ロールを取得し、そのローカル ロールが何であるかを確認します。 もちろん、このローカルの役割は、呼び出し元のマシンによって異なります。
ここで、この情報を使用して、setDisplayText 関数を呼び出してその役割を表示したいと思います。 そこで、ローカルの FString 変数を作成し、このロールを呼び出し、ローカルのロールに応じてロールの値を設定して、ここで switch ステートメントを使用できるようにします。 そこで、ローカルの役割をオンにして、ここでいくつかのケースを取り上げます。
さて、最初のケースは、localRole が ENetRole 権限の場合です。 ここでコロンを 2 つ押すとすぐに、ENetRole が使用できるさまざまな列挙型定数が表示されます。
[権限]、[自律プロキシ] があります。ロール MAX があります。これは、ほとんどのアニメでデフォルトの最大値として表示されるものです。 ロール [なし] と [シミュレートされたプロキシ] があります。
ロール [権限] を選択します。 また、ロールが [authority] の場合、ROLE (文字列) を値「authority」を持つ FString に設定します。 次のケースにカスケードしないように、ここに break ステートメントを追加します。
さて、ここではいくつかのケースがあります。 これを貼り付けて、ロール [authority] からロール [autonomous proxy] に変更します。 この場合、ロールを [autonomous proxy] という文字列に設定します。
ここで別のケースを追加しましょう。 [自律プロキシ] の代わりに、[シミュレートされたプロキシ] を使用します。 この場合、ロール文字列を [simulated proxy] に設定します。
ポーンの役割を [none] にするべきではありませんが、とにかくそのケースを処理します。 そのため、ロールがたまたま [none] の場合は、文字列を [none] に設定します。
したがって、この switch ステートメントの後、ローカル ロールの値に応じて FString ロールが設定されます。
今度は文字列をフォーマットしたいので、LocalRoleString という名前の新しい FString を作成し、FString::printf を使用します。ここでは、フォーマットされた文字列のテキストとして、単に [local role %s ] で、その文字列に役割を渡します。
もちろん、これは FString なので、アスタリスクのオーバーロードを使用して C スタイルの文字列を取得する必要があります。 これで、localRoleString という文字列ができました。この文字列値を持つように displayText を設定します。
そこで、このテキストを設定するために、FString を受け取る setDisplayText という便利な関数を作成しました。 したがって、setDisplayText を呼び出して localRoleString を渡すだけです。
したがって、このタイプのウィジェットがあり、showPlayerNetRole を呼び出す場合、役割を表示したいポーンを渡すだけです。 それは素晴らしいことです。 このウィジェットをキャラクターに追加するだけです。
それでは、ブラスターのキャラクターに戻りましょう。 したがって、この Blaster キャラクターでは、いくつかの変数を追加して、これらのoverheadWidgets の 1 つを作成できるようにします。
ですから、これらをここのプライベート セクションに貼り付けます。 これにはウィジェットコンポーネントを使用したいと思います。 そこで、OverheadWidget という UWidgetComponent を前方宣言し、これに UProperty を与え、この EditAnywhere を作成して、キャラクター ブループリント内から設定できるようにします。 これで、UWidgetComponent であるこのオーバーヘッド ウィジェットができました。
BlasterCharacter.cpp に戻り、コンストラクターでこれを作成しましょう。ここの一番下。 OverheadWidget と言って createDefaultSubobject を使用します。これは UWidgetComponent になり、[overheadWidget] という名前を付けます。 これをルート コンポーネントにアタッチするだけです。そこで、overheadWidget->setupAttachment のようにして、単純に rootComponent にアタッチします。
今は UWidgetComponent を使用しているので、そのヘッダー ファイルをインクルードする必要があります。 それでは一番上に行きましょう。これは [components/WidgetComponent] になります。 それで、そのヘッダーファイルを取得しました。 わかった。 これで、widgetComponent を BlasterCharacter に追加しました。
これで、関数がプレーヤーのネット ロールを表示します。これを、キャラクター クラスのブループリントから呼び出したいと思います。 これを Ufunction にして、blueprintCallable を追加します。
これをコンパイルしてテストする前に、Blaster キャラクターに戻ります。 また、ブループリントからウィジェットにアクセスするので、少なくとも blueprintReadOnly にする必要があります。 このプライベート変数を blueprintReadOnly にすると、「meta = ([allowPrivateAccess] = true)」が必要になります。
これが初めての場合、これはすべて、この変数をブループリントに公開していることを意味します。 このメタ指定を追加しない限り、C++ でプライベートな変数に blueprintReadOnly または blueprintReadWrite を使用することはできません。 したがって、C++ では非公開ですが、この変数で blueprintReadOnly を使用できるようになりました。
これを Blaster キャラクターでコンパイルできます。これが私のオーバーヘッド ウィジェットです。 それを選択し、ユーザー インターフェイス セクションでいくつかのプロパティを変更します。
[スペース] を [スクリーン] に変更し、[ウィジェット クラス] は [WBP_OverheadWidget] を選択し、[希望のサイズで描画] にチェックを入れたいと思います。 そうすれば、このウィジェットのサイズを手動で設定する必要がなくなります。
これで [オーバーヘッド ウィジェット] が設定されました。ここでブループリントの呼び出し可能な関数を呼び出して [beginPlay] を実行したいと思います。 そこで、overheadWidget を取得します。 そして、overheadWidget から getUserWidgetObject を呼び出します。
これは、ウィジェット コンポーネントが使用している実際のユーザー ウィジェットであり、このクラス WBP_overhead_widget です。 したがって、それにキャストできます。 キャストを使用して WBP_overhead_widget を選択し、このクラスとして、ブループリントの呼び出し可能な関数 show player net role を呼び出します。
これにはポーンが必要です。 私たちのキャラクターは実際に Pwan であるため、[自己への参照] を渡すだけです。 したがって、showPlayerNetRole は netRole を取得し、その netRole をオンにして、それに基づいてウィジェットのテキストを設定します。
それでは、コンパイルしてプレイして、何が起こるか見てみましょう。 ローカル ロール [権限] が表示されます。これは、1 人のプレーヤーだけでゲームをプレイしているためです。 その場合、私たちは [権限] であり、サーバー上にいます。 ビューポートに入り、overheadWidget をキャラクターの頭のすぐ上に移動します。
ここからが興味深いところです。 ここで実際に [3 つのドット (...)] まで来て、ネット モードがリッスン サーバーとして再生するように設定されていることを確認します。
このようにして、プレイヤーの 1 人が Listen サーバーであるゲームを実際にプレイしています。 つまり、彼らはサーバーとしてゲームをプレイしており、他のプレイヤーはクライアントであり、ここでプレイヤーの数を変更できます。
マルチプレイヤー ゲームをテストするときは、少なくとも 3 人のプレイヤーでテストすることをお勧めします。 ネットの役割に関しては、関連するすべてのケースが見られます。 プレイヤー数を 3 に設定した場合の意味を説明します。[プレイ] をクリックすると、3 つの個別のゲーム インスタンスが実行されます。
[ネット モード クライアント 1] と [ネット モード クライアント 2] の 2 つのウィンドウがトップ バーに表示されます。 したがって、ゲームのこれら 2 つのインスタンスは [クライアント] であり、このエディタの大きなウィンドウは [サーバー] です。
今、テキストはすべてごちゃごちゃしています。 ここで、サーバー上で少し先に進みます。
これをみて。 私たちのローカルでの役割は、これら 3 つすべてに対する権限であることがわかります。これは期待すべきことです。
サーバー上に存在するすべてのポーンは、ローカル ロール [権限] を持ちます。
ここで、クライアントをここに移動し、ウィンドウを少し拡大します。 ここで、私が操作しているキャラクターにはローカル ロール [自律プロキシ] があることに注意してください。 つまり、私のマシン上の私のキャラクターにはローカル ロール [自律プロキシ] があり、それは私がそれを制御しているためです。 だから私はここに走って、どちらが私か分かるようにします。 しかし、サーバー上では、ローカルの役割が [権限] であることがわかります。
ここで、他の 2 人のキャラクターを見てみましょう。どちらも [シミュレートされたプロキシ] であることがわかります。 それで、私は自分のマシンでこれらのキャラクターのバージョンを調べていますが、それらは別の場所で制御されているため、[シミュレートされたプロキシ] になります。
現在、ローカルの役割からは、サーバーによって制御されている役割を判断できません。 それを決定する方法については、コースの後半で説明します。
しかし今のところ、自分のマシンで実際に制御していないすべてのポーンがローカル ロール [シミュレートされたプロキシ] を持っていることは明らかです。 ここにいるもう 1 つのクライアント、つまりクライアント 1 に移動すると、同じことが表示されるはずです。 自分のマシンで制御しているポーンにはローカル ロール [自律プロキシ] があり、他のすべてのポーンにはローカル ロール [シミュレートされたプロキシ] があることがわかります。
これで、localRole の感触がつかめました。
それでは、remoteRole を見てみましょう。 ここで、showPlayerNetRole 関数のoverheadWidget.CPP に戻り、ローカル ロールの代わりにリモート ロールを表示したいと思います。
そこで、このローカル変数の名前をローカル ロールからリモート ロールに変更します。
また、ポーンから getLocalRole を呼び出す代わりに、getRemoteRole を呼び出したいと思います。 そして、この関数はまさにそのように機能します。 これは EnetRole を返しますが、今回は remoteRole を提供します。
したがって、localRoll で切り替える代わりに、remoteRoll で切り替えて、そのリモート ロールが何であるかに応じて文字列を設定します。
ここで、この FString の名前をリモート ロール文字列に変更します。本文では、ローカル ロールではなく、リモート ロールと表記します。 setDisplayText への関数呼び出しでは、ここでリモート ロール文字列を渡します。
それでは、これをコンパイルしましょう。 エディターに戻り、再生をクリックします。 これで、ウィジェットにリモート ロールが表示されます。
では、こちらをご覧ください。 私はクライアント 2 を使用しており、リモート ロールは [権限] です。 したがって、このキャラクターのローカル ロールが何であるかがわかります。
私はその[自律プロキシ]を制御しており、そこにある他の2つは[シミュレートされたプロキシ]です。 しかし、サーバー上にいない場合は、リモート ロールがサーバー上のロールになります。 したがって、これらすべての[権限]になります。 ここで、他のクライアントにも同じことが当てはまることに注意してください。 3つともリモートの役割は【権限】です。
次に、サーバーを見てみましょう。 ここのサーバーでは、ポートの状況が少し異なります。 私がコントロールしているリモート ロールは [自律プロキシ] であり、ここでの他の 2 人のリモート ロールは [シミュレートされたプロキシ] です。 これは、サーバー上で注意すべき微妙な違いです。
リモートの役割は、サーバーで制御されるキャラクターの [自律プロキシ] と、他の 2 つのキャラクターの [シミュレートされたプロキシ] になります。
そのため、常にこの情報を使用して、リモート ロールと C++ コードをチェックし、サーバー上かクライアント上かにかかわらず、自分がどのマシン上にいるかを知ることができます。
そのため、このレクチャーでは、ネットワーク ロールの概念と、ポーンのローカル ロールがどのように [権限] になるかについて説明しました。つまり、サーバー上に存在するポーン、または [自律プロキシ] を検討していることになります。 これは、クライアント マシンで現在制御しているポーンのローカル ロールです。
また、[シミュレートされたプロキシ] があることも確認しました。これは、制御していないクライアント マシン上のポーンのローカル ロールになります。
また、リモート ロールの概念と、クライアント マシンから見た場合のすべてのポーンのリモート ロールが [権限] になる方法、およびサーバー上で現在制御されているポーンのリモート ロールがautonomousProxy である方法についても説明しました。 サーバーがアクティブに制御していないサーバー上の他のポーンのsimulatedProxyです。
したがって、このコース全体でこのロールの概念を使用して、コード内でどのマシンを使用しているかを判断します。
よくやった。
また後で。
おかえり。
これでキャラクターの動きができましたが、キャラクターはアニメーション化されていないため、アニメーション インスタンスが必要になります。
これは、アニメーション ブループリントのベースとなる C++ クラスです。
ここで、C++ クラスが必要な理由は、C++ からこれにアクセスしてそのプロパティを設定できるようにするためです。
ここで、このコース全体を通して、アニメーション ブループリントであるアニメーション インスタンスを使用します。
しかし今のところは、プロジェクトを走り回ってテストできるように、アイドル ウォーク、ラン、ジャンプなどの未装備のアニメーションをキャラクターに設定したいと思います。
それでは飛び込みましょう。
わかった。
これが私たちのプロジェクトで、私たちのキャラクターは非常に硬いので、アニメ インスタンスをセットアップします。
それでは、C++ クラスに入りましょう。このキャラクター フォルダーには、Blaster キャラクターがあります。
ここでアニメのインスタンスを作りたいので、右クリックで新しい C++ クラスを選択し、すべてのクラスを選択してインスタンスを検索します。
そして、ここにあります。
[次へ] をクリックすると、ここにパスが設定されていることがわかります。これをキャラクター フォルダーに配置します。
では、これを「ブラスター アニメーション インスタンス」と呼びましょう。
文字クラスを作成したときと同じ警告メッセージが表示されます。 繰り返しますが、それはキャラクター フォルダーに配置したためです。
いいえをクリックします。
ここ Visual Studio には、BlasterAnimInstance.h と BlasterAnimInstance.cpp があります。
エラーの原因は次のとおりです。Unreal Engine は自動的にキャラクター フォルダをそこに配置します。 これを削除すると、コンパイルできるようになります。
これで、AnimInstance は非常に単純になり、駆動するいくつかの重要な変数を設定するだけで、非常に基本的な未実装のアニメーションになります。
そこで、パブリック セクションを追加し、いくつかの継承された関数をオーバーライドします。 したがって、これらは「仮想オーバーライド」になります。
1 つ目は NativeInitializeAnimation です。 これはBegin Playによく似ています。 これは、ゲームの最初だけでなく、Unreal Engine をロードしてコンパイルするときなど、さまざまなときに呼び出されます。
ここで、NativeUpdateAnimation という別の仮想関数もオーバーライドしたいと思います。これは Delta Time という float を取り、tick 関数と同じようにすべてのフレームで呼び出されます。
これもオーバーライドなので、先に進んでこれら 2 つの関数を実装できます。 そして、何よりも先に最初に行うことは、これらの関数の SUPER バージョンを呼び出すことです。
ですから、忘れないようにしましょう。
これで、super::NativeInitializeAnimation と super::NativeUpdateAnimation が得られました。 それにデルタ時間を渡します。 これで、アニメーション インスタンスには、アニメーション ブループリントに公開できる変数がいくつかあるはずです。
これらは非公開にすることができるので、非公開セクションを作成します。 最初に追加したい変数は、Blaster キャラクターを格納する変数です。 これは、このアニメーション インスタンスを使用するキャラクターになります。
そこで、ABlasterCharacter を前方宣言します。 このポインターは単純に BlasterCharacter と呼ばれます。
アニメーション ブループリントからこれにアクセスする必要があるため、これを UProperty で公開し、このブループリントを読み取り専用にします。
必要に応じて、これにカテゴリを指定できます。 CHARACTER というカテゴリにします。 また、このブループリントを読み取り専用にしているため、これはプライベート変数であるため、メタ指定子が必要です。
このメタ指定子を [allowPrivateAccess = true] に使用しない限り、プライベート変数で読み取り専用のブループリントを使用することはできません。
ここで、ここに保存したい他のいくつかの変数に対して同じことを行います。
1 つは速度のためなので、ここでは同じ UProperty を使用します。 MOVEMENT にできるのはカテゴリのみです。
速度に加えて、空中にいるかどうかも知りたいです。 そこで、bIsInAir という bool を作成します。 そして、これに同じ UProperty カテゴリ MOVEMENT を与えます。
そして、私は別のブールが必要です。 これを [bIsAccelerating] と呼ぶことにします。 その通り。 加速しているかどうかがわかるので、それを使用して、走っているかどうかなどのアニメーションを操作できます。
これら 4 つの変数があり、それらを設定する必要があります。
ここで、ネイティブ初期化アニメーションの早い段階でブラスター キャラクターについて説明します。 BlasterCharacter を TryGetPawnOwner の結果と等しく設定するだけです。
しかし、TryGetPawnOwner を呼び出すと、この関数は Pawn を返します。 これをブラスターキャラクターにキャストする必要があります。
というわけでキャストをやっていきます。 これを ABlasterCharacter にキャストします。 そしてもちろん、BlasterCharacter を「含める」必要があるので、ここの一番上に「含める」ことにします。 blasterCharacter.h になります。
名前の前にそのキャラクター フォルダーを配置せずに、ここでこれを「含める」ことができる理由は、アニメーション インスタンスがキャラクター フォルダー内にあるからです。
これで、ブラスターのキャラクターができました。
現在、NativeUpdateAnimation はすべてのフレームで呼び出されます。 また、NativeInitializeAnimation で設定する前に BlasterCharacter にアクセスしようとしていないことを確認する必要があります。 簡単に確認できます。 「if BlasterCharacter」。 BlasterCharacter が null ポインターであるかどうかを確認したいのですが、そうであればすぐに取得して、NativeUpdateAnimation を呼び出す最初のフレームにアクセスして設定できるようにします。 BlasterCharacter が等しいと言えます。 ここでは、ポーンの所有者を取得して BlasterCharacter にキャストしようとする同じ行を使用します。 これで、Blaster キャラクターへのアクセスが処理されます。
次に、以下の行で BlasterCharacter にアクセスしたいと思います。「If BlasterCharacter」などの IF チェックですべてをラップするのではなく、単に「If BlasterCharacter が null であるか」を確認して戻ります。 その場合、BlasterCharacter が null の場合はこの行に到達しないため、この方法で BlasterCharacter に安全にアクセスできます。
次に設定したい変数は速度です。これにより、BlasterCharacter の速度を取得できます。 ここでは FVector の速度を指定し、単純に BlasterCharacter を使用して getVelocity を呼び出します。 そして、私の速度については、横方向の速度だけが本当に必要です。 速度の z コンポーネントは気にしないので、速度の Z をゼロにします。 したがって、velocity.z = 0.f とします。
次に、このベクトルのサイズを簡単に取得して、速度に等しく設定できます。 したがって、速度は「velocity.size」に等しいと言えます。 そして、私にはスピードがあります。
ここで、bIsInAir を設定したいと思います。 そのため、bIsInAir では、キャラクターの動きのコンポーネントを取得する必要があります。 つまり、もちろん、そのための適切なインクルードを追加する必要があります。 そして、その characterMovementComponent はゲーム フレームワークにあります。 [game/framework/characterMovementComponent.h] をインクルードします。 その型が使えるようになったので、BlasterCharacter から characterMovementComponent を取得します。 つまり、BlasterCharacter->getCharacterMovement になります。 characterMovementComponent から isFalling を呼び出すだけです。 ブール値を返します。 落下している場合は true になります。この場合、空中にいることがわかり、適切なアニメーションを再生できます。
最後に、bIsAccelerating を使用します。 速度ではなく、なぜこれを使用しているのか疑問に思われるかもしれません。 また、インスタンスの観点から加速について話すとき、速度の変化率について話しているのではありません。 物理学を知っていれば、それが加速度の技術的定義であることを知っています。
私が話しているのは、キーを押して移動する入力を追加するかどうかです。 ここでそれを設定します。 bIsAccelerating で、これもキャラクターの動きのコンポーネントから取得します。 BlasterCharacter->getCharacterMovement と言って、現在の加速度を取得します。 getCurrentAcceleration を使用して、このベクトルのサイズを取得します。 ゼロより大きい場合は、それを使用して加速を定義します。
ここで三項演算子を使用して、この数量が 0 より大きい場合は「?」を使用します。 そこで「f」を使います。 次に、ブール値を「true」に設定します。 そして、これが私の「:」であり、「false」はそれ以外の場合です。
というわけで簡単にレビュー。 三項演算子に慣れていない場合は、ここで最初の式がその式、値の真偽を評価します。 したがって、現在の加速度のサイズが 0 より大きい場合、この三項演算子式によって返されるのは、この 2 番目の量です。 最初の式が false と評価された場合、三項式はこの数量をここに返します。 つまり、「この量なら「これ」を返し、そうでなければ「あれ」を返す」と言っているのと同じです。
そのため、コード行を単純化するために、必要に応じて三項演算子を使用します。 そうでなければ、ここに FALSE STATEMENT があるだけです。
これで、"speed" と "isInAir" と "isAccelerating" ブール値を変数に設定しました。 私たちのブラスターキャラクターと同様に。 これで、アニメーション ブループリント内からこれらにアクセスできるようになりました。 それでは、このクラスに基づいてアニメーション ブループリントを作成しましょう。
このコードをコンパイルし、blueprints フォルダーに移動してキャラクターに入ります。 ここにアニメーション ブループリントを追加したいと思いますが、ここで Animation という新しいフォルダーを作成し、作成したアニメーション ブループリントとその他すべてをここに保持します。 これは、アニメーション モンタージュのようなアニメーション関連です。
右クリックして、新しいアニメーション ブループリントを作成します。 親クラスには AnimInstance を選択します。 次に、クラスの親を blasterAnimInstance に変更します。 [最高の成功設定] をこのように設定しました。
次に、スケルトンを sk_epic_character_skeleton に設定し、[OK] をクリックします。 これを BlasterAnimBP と呼びたいと思います。
そして、それを開いてみましょう。 さて、これが私の blasterAnimBP です。
最初に行うことは、クラスの設定に移動することです。これは、ここの上部のバーに表示されます。 クラス設定では、親クラスを BlasterAnimInstance に設定します。
BlasterAnimInstance からアニメーション ブループリントを派生させたので、C++ で宣言した変数 (加速、速度、Blaster キャラクターなど) にアクセスできるはずです。そのため、これらのブループリントを読み取り専用にして、このブループリント内からアクセスできるようにしました。
さて、このゲームの大部分で、キャラクターは武器を装備します。 しかし、その機能を実装するまでは、未装備用のアニメーション ステート マシンを使用する予定です。
それではステートマシンを作ってみましょう。
新しいステート マシンを追加して、出力ポーズに接続します。 そして、これを未装備と呼びます。
これは、キャラクターが武器を持っていないときにポーズに使用するステート マシンです。 そこで、ステート マシンに移動して、いくつかのステートを追加します。
さて、まず、アイドル ウォーク アラウンド状態が必要になります。 したがって、このアイドル ウォーク ランを簡単に呼び出すことができます。 そして、このための簡単なブレンド スペースを作成します。
また、キャラクターもジャンプできる必要があります。 そこで、ジャンプ用の状態をいくつか作成します。 最初のアニメーションを作成するためにジャンプ スタートを実行し、空中にいるときのアニメーション状態を作成します。 これを落下と呼ぶことにします。
そして落下から、ジャンプストップアニメへ。 それでは、ジャンプ停止状態を追加しましょう。 そして、ジャンプストップから、そのままアイドルウォーク、ランに戻ることができます。 繰り返しますが、これは簡単です。
「アイドルウォークランからジャンプスタートへ」、ダブルクリックしてそのトランジションに入りましょう。
これには isInAir を使用します。 isInAir が true の場合、ジャンプ スタート アニメーションに移行し、ジャンプ スタートから落下することができます。 これを自動移行にするだけです。 [シーケンス、プレーヤー、状態に基づく自動ルール] の横にあるチェックボックスをオンにできます。 つまり、このアニメーションが終了するとすぐに、次の状態 (落下アニメーション) に自動的に遷移します。
フォールバックからジャンプストップまで、再び isInAir を使用できます。 そこで、isInAir を使用します。 そしてもちろん、このブール値を false にする必要があります。 そこで、[NOT boolean] を使用します。 isInAir が false の場合は遷移し、アイドル ウォーク ランに戻ります。
このアニメーションが特定のポイントまで再生されたら、そのために残り時間ノードを使用します。これを行うには、そこにアニメーションが必要です。 ですから、これについてはすぐに説明します。
Jump Start では、Jump を検索し、Learning Kid Games Pack に付属のアニメーションをいくつか使用します。 そしてそれらは EPIC CHARACTER で始まります。 したがって、エピック キャラクター ジャンプ アップ スタートは、キャラクターが武器を持っていない場合のジャンプ スタート アニメーションです。 それをダブルクリックすると、このように見えることがわかります。 これをジャンプスタートと落下状態に使います。
EPIC CHARACTER ジャンプ アップ ループがあり、それがこのアニメーションです。 彼はちょうど落下ポーズです。 ジャンプストップには、EPIC CHARACTERのジャンプアップエンドがあります。 そして、これがそのアニメーションの外観です。 それを再生して、キャラクターが地面に (落下) 戻っていることを確認できます。
これで [jump stop] の中にアニメーションができました。 [残り時間の比率] を使用するこの遷移規則を完成させることができます。
[残り時間比率] は、比率が必要なアニメーションを知る必要があるノードです。 だからこそ、あのアニメーションが必要だったのです。
これはジャンプアップとアニメーションのためのもので、残り時間が特定の値以下かどうかを確認したいだけで、0.1 などを使用できます。 したがって、アニメーションが 90% 再生され、そのアニメーションの残り時間の比率が 0.1 になると、IdleWalkRun に戻ります。
IdleWalkRun では、ブレンド スペースを使用して、アイドリングから実行中へのブレンドを行います。 それでは、そのブレンドスペースを作りましょう。
アニメーション フォルダに戻り、右クリックしてアニメーションを選択し、単純な [ブレンド スペース 1D] を使用します。 SK_epic_character_skeleton を選択します。 そして、これを未装備の IdleWalkRun と呼ぶことにします。
そして、これは簡単です。 EpicCharacter_Idle アニメーションを作成します。 ここにあります。 そして、彼はただそこに立って周りを見回しています。
(今) EpicCharacter_Walk があります。 これを 2 番目の場所で設定し、最後に EpicCharacter_Run を使用できます。 今度は横軸が速度になります。 [maximum] については、およそ 350 に達したら running_animation に入りたいと思います。
キャラクターのデフォルトの最大歩行速度はそれよりも高速です。 約 600 です。ゼロから最大歩行速度まで加速するので、スムーズな移行が得られるはずです。
これでブレンド スペースができたので、それを閉じます。 ここで UnequipledIdleWalkRun を取得し、それを PLUG して、速度変数 (C++ で宣言し、NativeUpdateAnimation で設定しています) を使用するだけです。
ですから、それをコンパイルして保存します。 これで、今のところのアニメーション グラフが完成しました。 キャラクター用の単純なステート マシンがあります。 武器なしで装備されていません。
それでは、キャラクター フォルダの BP_BlasterCharacter に戻り、メッシュを選択して新しいブループリントを割り当てます。
では、アニメーションモードを [use animation blueprint] にしましょう。
[アニメーション クラス] には BlasterAnimBP を使用します。アニメーション インスタンスではなく BP を選択してください。これは、BP がステート マシンを持つものであるためです。 コンパイルして再生すると、キャラクターがアイドル状態になっていることがわかります。
これで、まだコントローラーと一緒に回転しており、動きに向けられていません。これは、私たちが望むものです。 そこで、いくつかのことを行います。
まず、BlasterCharacter.CPP に戻り、C++ でいくつかの変数を設定します。
1 つ目は、コントローラーの rotationYaw を使用することです。 これを false に設定します。 少なくともまだ、コントローラーの回転に合わせてキャラクターを回転させたくないからです。 武器を装備し、エイム オフセットを使用していて、状況がさらに複雑になったら、それを使用したいと思うでしょう。 しかし今のところ、コントローラーの回転とは無関係にキャラクターを静止させ、代わりに独自の移動方向に向けます。
そのために、getCharacterMovement を使用してキャラクターの動きのコンポーネントを取得し、ブール値の bOrientRotationToMovement にアクセスします。 これを true に設定します。
ここで、キャラクターの移動コンポーネントを使用しています。 また、ヘッダーを含めたインスタンスでも使用していることを思い出してください。 これをコピーして、インクルードし、BlasterCharacter の上部に貼り付けることができます。 そして今、そこに含まれているエラーはありません。
これをコンパイルしますが、設定した C++ 変数とコンストラクターをブループリントがオーバーライドするため、ブループリントでこれらの変数を設定する必要もあります。
BlasterCharacter に戻ります。 BP_BlasterCharacter(self) を選択し、[use controller rotation Yaw] を検索します。 チェックを外します。 CharacterMovement を選択し、[回転を動きに合わせる] を検索し、チェックされていることを確認します。
コンパイルできるように見えるので、今再生すると、キャラクターは移動方向に向き、コントローラーを動かし、スプリングアームとカメラを拡張すると、キャラクターはそれに沿って回転しません.
これで、キャラクターが走り回ることができました。これは素晴らしい出発点です。 動きがあり、アニメーションがあり、ジャンプできます。 だから、これはよさそうだ。
ここで、ジャンプの最後でキャラクターの一種のグリッチが発生することに気付きました。 そこで、AnimBP の JumpStop 状態に戻り、ジャンプ エンドを選択し、ループ アニメーションのチェックを外してコンパイルします。 さて、戻ってジャンプすると、もうその不具合はありません。 そして今、私たちはジャンプしています。
すべてが良さそうです。
この講義では、アニメーション ブループリントをセットアップし、このアニメーション ブループリントの親として使用するアニメーション インスタンス C++ クラスを用意しました。
このようにして、C++ から変数を設定し、ブループリント内の変数にアクセスしてアニメーションを駆動できます。 キャラクターが走り回っており、今後のビデオでより複雑な機能を追加する予定です。 しかし、今のところ、基本的な動きがあります。
よくやった。
また後で。
おかえり。
これで、スプリング アームとカメラ コンポーネントにキャラクターができました。
プロジェクトとプログラムの入力、キャラクターの移動機能を構成する必要があります。
始めましょう。
そのため、プロジェクトにはいくつかの入力が必要になります。 そのために、編集とプロジェクト設定に進みます。
ここから、入力を選択して、アクション マッピングと AXIS マッピングを展開します。
ここで、軸マッピングにいくつかのアクションが見られます。これらは、ラーニング キット ゲームからいくつかのアセットを移行したときに作成されました。
プロジェクト設定からこれらの軸マッピングをすべて削除します。 これをすべてゼロから行いましょう。
アクション マッピングでは、ジャンプできるようにしたいと考えています。
ジャンプ アクション マッピングを作成し、これをスペースバーにマッピングします。 このアイコンをクリックしてスペースバーを押すと、スペースバーをジャンプ アクション マッピングにリンクできます。
AXIS マッピングでは、これらのいくつかが必要になります。
1 つ追加して、これを MoveForward と呼びます。 そして、これを W キーにマッピングしたいと思います。 また、これを S キーにマップし、スケールを -1 にして後方に移動します。 これで、MoveForward ができました。
MoveRight も必要です。 そこで、MoveRight を追加して、これを D キーにマップします。 また、スケール -1 の A キーにマップしたいと思います。
これで左右に移動できるようになります。
ここで、前進と右への移動に加えて、マウスを使用してカメラを回転できるようにしたいと考えています。 そこで、さらに 2 つの軸マッピングを追加し、そのうちの 1 つを [Turn] と呼びます。
このために、マウスの x 軸をマップし、look up という別の軸を作成して、これをマウスの y 軸にマップします。
ここで、マウスの y 軸のスケールを -1 に設定します。
そうすれば、マウスを前方に動かすと、下ではなく上を向くようになります。
したがって、これらのアクションと軸のマッピングがあります。
文字クラスでこれらのマッピングにバインドする関数をいくつか作成できます。
これが BlasterCharacter.h で、動きを処理する関数をいくつか作成します。
ここで、子クラスからこれらにアクセスしたい場合に備えて、これらを保護されたセクションに貼り付けます。 BlasterCharacter から派生する可能性があります。
そして、float を取る MoveForward という関数を作成します。 この値を呼び出します。これは、軸のマッピングのための軸の値です。
MoveRight という void 関数も作成し、そのために value という float を追加します。
次に、Turn と LookUp が必要です。
そこで、value という float を持つ Turn という関数と、value という float を持つ LookUp という関数を作成します。
そして、これらは私たちの基本的な動きを処理します。
これらを定義していきましょう。
ここに関数の定義があります。
ところで、これは現時点でのレビューです。 以前にこれを行ったことがなく、私たちが行っていることについて少し理解していない場合は、他の C++ Unreal Engine コースの 1 つを受講することをお勧めします。ここでは、ここで行っていることをより詳細に説明します。 少なくとも一度はこれを行ったことがあると思います。
キャラクターを立ち上げて機能させるには、このレビュー資料のいくつかを通過する必要があります.
Unreal Engine のマルチプレイヤーに関連するいくつかの新しい機能に入る前に、関数の動きができたので、setupPlayerInputComponent 関数を取得して、beginPlay の下にカット アンド ペーストします。
こうすることで、ここで関数をアクセス マッピングにバインドしているため、プレーヤー入力コンポーネントの設定を確認できます。
これで、これらの移動関数は非常に単純になり、前進します。
文字コントローラーが null ではなく、値がゼロでないことを確認します。
したがって、コントローラーが null ポインターと等しくなく、値が 0.f と等しくない場合を言います。
そのため、Character クラスには、AController 型の controller と呼ばれる継承された変数があります。
ここで、この IF チェックを行う場合、どの方向が前方であるかを調べる必要があり、コントローラーの回転を使用してこの値を見つけます。
getActorForwardVector を使用して前方方向を取得しないのはなぜですか? これは、アクティブな前方ベクトルがキャラクターの前方方向であるためです。
より具体的には、カプセルであるルート コンポーネントの前方ベクトルです。 ただし、コントローラーの回転を変更します。
コントローラーはルート コンポーネントとは異なる回転を持つ可能性があり、キャラクターの前方方向ではなく、コントローラーの前方方向に移動したいと考えています。 そこで、コントローラーを前方に向けます。
ローカル変数を宣言しましょう。 const FRotator になります。 これを YawRotation と呼びます。 これは、ヨーのピッチがゼロの FRotator になります。 そこで、ヨーイングのピッチには 0.f を使用します。 しかしヨーに関しては、私はコントローラのヨーが好きなので、controller->getControlRotation と言って、その回転からヨーを取得します。
前述のように、ロールとピッチに 0.f を使用します。 したがって、この回転 F rotator はピッチとロールに対してゼロであり、コントローラーの回転ヨーです。
次に、この FRotator を使用して前方ベクトルを取得し、方向を取得します。これが FVector になります。 そこで、const FVector を作成します。 そして、これを単に「方向」と呼ぶことにします。
FRotation 行列を使用してヨー回転から前方ベクトルを取得することで、これを初期化します。 そのため、回転を使用して FRotationMatrix を作成できます。
FRotationMatrix は、行列と呼ばれる単純な数学的構造です。 ローテーターから回転行列を作成でき、その回転行列には情報が含まれています。 FRotationMatrix で getUnitAxis という関数を使用できます。
ここで、getUnitAxis と getUnitAxes があることに注意してください。 getUnitAxis が必要で、これに値を渡します。値は EAxis::X になります。 EAxis は名前空間であり、この「列挙型」定数 X が含まれています。
私たちが行っているのは、x 軸を指定して、それを単位軸と呼んでいることだけです。 この背後にある数学を理解する必要はありません。 FRotator から FRotationMatrix を作成し、それを単位軸と呼び、FVector を返すことだけを知っておく必要があります。
このベクトルは、回転の方向を表します。 これで、ピッチとヨーの回転がゼロになります。 したがって、このベクトルは地面に平行で、コントローラーのヨーに対応する方向を指しています。
これが前進したい方向なので、キャラクターの継承関数 addMovementInput を呼び出し、方向と値を渡します。
ここで、方向の大きさは問題ではないことに注意することが重要です。 たとえば、方向を 2 倍することでこれをスケーリングできると考えていて、それが移動速度を 2 倍にする場合、それは機能しません。 AddMovementInput は単に方向と値を取り、その方向にキャラクターが移動する結果になります。
ただし、速度と加速度は characterMovementComponent から取得されます。 キャラクターをより速く動かしたい場合は、characterMovementComponent の変数を変更する必要があります。 したがって、これで先に進むことができます。
moveRight で同じコードを使用します。 回転行列から x 軸を取得するのではなく、重要な違いが 1 つあります。 y 軸を取得します。 これにより、ヨー回転に対応する前方ベクトルではなく、正しいベクトルが得られます。 他のすべては同じです。
回転と見上げがさらに簡単になりました。 turn 関数の addControllerYawInput を呼び出すだけで、マウスを左右に動かしながら値を渡します。 値は、マウスを動かしてコントローラーを追加する速度を表します。 ヨー入力は、コントローラーの回転にヨーを追加します。
LookUp は単純に addControllerPitchInput を呼び出し、ここに値を渡します。 したがって、基本的な移動関数があり、これらを軸マッピングにバインドする必要があります。
タイプ UInputComponent のオブジェクトにアクセスできるため、セットアップ プレーヤー入力コンポーネントでそれを行うことができます。 これが playerInputComponent です。 もちろん、playerInputComponent には bindAxis があります。 今 bindAxis は FName を取ります。
ここで実際の FName を渡すか、その中に文字列を含むテキスト マクロを渡すことができます。 または、単に通常の文字列を使用することもできます。リテラル バインド アクセスは、その軸名に対してこれらすべてを受け入れます。 これで moveForwards ができたので、それから始めることができます。
2 番目の入力は、このキャラクターになるユーザー オブジェクトです。
そして、ABlasterCharacter::MoveForward になるバインド先の関数のアドレスが必要です。
次に、moveRight に対して同様の方法で他の軸マッピングをバインドします。 文字列を moveRight に変更し、関数を moveRight 関数に変更できます。
「turn」と「lookUp」もあります。 それでは、それらも見つけてみましょう。 ターンにはターン軸マッピングが必要であり、ターン関数をバインドし、ルックアップまたはルックアップ軸マッピングにバインドし、ルックアップ関数を使用しています。
これで、ジャンプに関するアクション マッピングもできました。 今のところ、キャラクターの継承されたジャンプ機能を直接バインドするだけです。 これを一番上に挙げてみましょう。
playerInputComponent と言います。 bind アクションを使用します。 アクション名は「ジャンプ」。
EInputEvent があります。 これが、使用できるキー イベントです。 IE_Pressed ユーザー オブジェクトはこれで、関数は単純に ACharacter::Jump です。
後で、追加の機能が必要になる可能性があるため、ジャンプ機能をオーバーライドしますが、今のところは、キャラクターのジャンプ機能で十分です。 そのため、移動を設定し、移動関数を入力にバインドしました。
これをコンパイルしてみましょう。
エディターに戻って、キャラクター クラスをここに置いておきます。
プレーヤーの開始もまだ使用していません。
私はワールドに実際の BP_BlasterCharacter を持っています。最後のビデオでは、詳細パネルに移動し、自動所有プレイヤーをプレイヤー 0 に設定しました。
そうすれば、Play を押すと、実際にプレーヤーを所有していることになり、動き回ることができます。
もちろん、アニメーション ブループリントを使用していないため、キャラクターは固く、アニメーション ポーズすらありません。
それが私たちの次のステップになるでしょう。
キャラクターのセットアップの基本はほぼ終わりました。キャラクターを動かせたら、マルチプレイヤー プログラミングの概念を学び始めることができます。
そのため、この講義では、基本的なキャラクターの動きのアクションとアクセスのマッピングを設定し、それらの動き関数を作成してマッピングにバインドしました。
そして、実際にキャラクターとコントローラーを動かし、ひいてはスプリング アームとカメラを動かしています。
繰り返しますが、これはすべてあなたのためのレビューです。
キャラクター設定の基本はほぼ完了しており、すぐにマルチプレイヤー プログラミングに取りかかることができます。
また後で。
おかえり。
これで、キャラクター クラスとキャラクター ブループリントができました。
カメラ コンポーネントやスプリング アーム コンポーネントなどのコンポーネントの追加を開始します。
それでは飛び込みましょう。
ロビー マップに移動して、BP_Blaster_character をドラッグします。
まず、ゲームモードを設定していないため、自動的にキャラクターを所有することはありません。
しかし、キャラクターを選択し、自動所有プレイヤーの詳細パネル検索に移動し、それを player_0 に設定した場合、プレイを押すと、このキャラクターが自動的に所有されます。
しかし、カメラはほとんどキャラクターの内部にあることがわかります。
そのため、キャラクターを所有しているときにビューを制御するには、カメラとスプリング アームが必要です。
したがって、これらのコンポーネントを C++ から追加します。
これが blasterCharacter.h と BlasterCharacter.cpp です。
いくつかの新しい変数を宣言します。
public セクションにコンストラクターがあります。 ここには、Tick と SetupPlayerInputComponent を含む 2 つ目のパブリック セクションがあります。
これらの公開機能をここの一番上にあるこの公開セクションに移動したいと思います。
また、この時点で、これらの関数が何をするかをすべて知っているはずなので、これらのコメントが必要だとは本当に思いません。 なので、それらのコメントは削除します。
ここでは、Tick と SetupPlayerInputComponent を [トップ パブリック セクション] に移動します。 および保護されたセクションの下。
プライベートセクションを希望します。
そこで一つ追加します。
この公開セクションはここに置いておきます。 この領域は、さまざまなメンバー変数の単純な getter と setter 用に予約します。
ここのプライベート セクションでは、ここにスプリング アームとカメラを追加します。
そこで、use spring arm コンポーネントを前方宣言します。
これを CameraBoom と呼ぶことにします。
さて、これには新しいプロパティ マクロが必要になります。
だから私はこれをどこでも見えるようにするつもりです。
そして、CameraBoom とカメラを 1 つのカテゴリに入れたいと思います。
これを CategoryCamera と呼びます。
そしてもちろん、実際のカメラ自体も必要です。これも前方宣言されます。
そして、これは UCameraComponent になります。
これを FollowCamera と呼ぶことができます。
さて、これもVisibleAnywhere、そしてCategoryCameraにします。 これで、変数を宣言しました。
しかし、これらを構築する必要があります。 これを行い、Blaster キャラクター コンストラクターを作成します。
現時点ではこれらのコメントは必要ないと思うので、ここでこれらのコメントを削除します。 彼らは初心者をスピードアップさせるためのものです. したがって、ここでコンストラクターでそれらを削除できると思います。
CameraBoom を作成しましょう。 だから私はカメラブームと言ってデフォルトのサブオブジェクトを作成します。
これは USpringArmComponent です。
テキスト マクロでは、これを CameraBoom と呼びます。
もちろん、ここではスプリング アーム コンポーネントを使用しているため、そのタイプのヘッダーを含める必要があります。 「GameFramework/SpringArmComponent.h」をインクルードします。
これで、アンリアル エンジンのドキュメントでいつでもクラスを検索して、このインクルードを確認できます。
通常、CameraBoom をルート コンポーネントに接続しますが、カメラ ブームをメッシュ コンポーネントに接続したいと思います。
これは、後でカプセル サイズを変更するしゃがみ機能を使用するためです。
カプセルは私たちのルートであり、スプリング アームがカプセルに取り付けられた状態でカプセル サイズを変更すると、スプリング アームが動きます。
ということで、代わりにスプリングアームをメッシュに取り付けます。
セットアップ アタッチメントを呼び出して、get mesh でアクセスできるメッシュを使用します。
次に、カメラ ブームのターゲット アームの長さを設定します。 それでは、cameraBoom->TargetArmLength としましょう。 これを 600 に設定します。
しかし、それを調整したいかどうか見ていきます。
現在、カメラ ブームにも bUsePownControlRotation があります。 これを true に設定して、マウス入力を追加するときにコントローラーと共にカメラ ブームを回転できるようにします。
これで cameraBoom ができました。 カメラを作成しましょう。 そのため、フォローカメラがあります。
createDefaultSubObject を使用します。 これは UCameraComponent です。 これを followCamera と呼びます。
setupAttachment を使用して、followCamera をカメラ ブームに取り付けることができるようになりました。
そして、use springArmComponent、静的メンバー変数ソケット名を使用して、カメラを cameraBoom の socketName ソケットに接続できます。
そして、カメラ コンポーネントを使用しています。 そのため、ヘッダーを INCLUDE する必要があります。 これは camera/cameraComponent.h にあります。
現在、フォロー カメラは cameraBoom にアタッチされているため、PownControlRotation を使用する必要はありません。 したがって、followCamera->beUseControlRotation = false と言えます。
それでは、先に進んでコンパイルしましょう。
カメラがあり、もちろん、カメラ ブームがメッシュに取り付けられていることがわかります。
下部にピボットポイントがあります。 ここでは、スプリング アームが下部に取り付けられていることがわかります。
さて、ここの BLUEPRINT を見ると、約 600 単位離れているように見えます。 私たちのターゲット アームはこの 600 のようなものだからです。
しかし、ここではそれがわかりません。 カメラが床に衝突する可能性が最も高いためです。
では、カメラ ブームを上に動かしてみましょう。実際には地面から取り付けたくないからです。
カメラ ブームを取り、Z 方向の位置を 88 に設定します。そうすれば、ここの中央に取り付けられます。 カメラ ブームを少し上に移動することもできます。 それはあなた次第です。
コンパイルして再生ボタンを押すと、キャラクターから正しい距離にいることがわかります。
もちろん、まだ動き回ることはできません。
これは、その機能をプログラムしていないためです。
それが次のステップになります。
この講義では、カメラ コンポーネントとスプリング アームを追加し、それらのアタッチメントをセットアップして、カプセルであるルート コンポーネントではなく、メッシュにスプリング アームを取り付けました。
そうすれば、後でしゃがんでカプセルのサイズを変更しても、スプリング アームの高さには影響しません。
これで、移動機能をプログラムする準備が整いました。次にそれを行います。
また後で。
いらっしゃいませ。
キャラクタークラスの作成を開始する準備ができました。
そのため、このビデオでそれを行い、C++ クラスのフォルダー構造を設定して、プロジェクトを整理します。
それでは始めましょう。
これが私たちのプロジェクトです。
これまでのところ、C++ クラス フォルダーには BlasterGameModeBase クラスがあります。
新しい文字クラスを作成します。 そのため、右クリックして [新しい C++ クラス] を選択することで、C++ クラスと Blaster 内からそれを行うことができます。
次に、キャラクターに基づいてクラスを作成します。
それでは、文字を選択して次へをクリックしましょう。
このプロジェクトでは、キャラクター クラスに [ブラスター キャラクター] という名前を付けます。このプロジェクト用にかなりの数のクラスを作成します。
そのため、それらを独自のフォルダーに整理したいと思います。
Character というフォルダーに Blaster クラスを作成します。
パブリック フォルダー構造とプライベート フォルダー構造を使用するかどうかは、あなた次第です。
個人フォルダは使わなくてもいいので、そのままにして、BlasterCharacter と専用のキャラクター フォルダを追加するだけにします。 では、クラスの作成をクリックしましょう。
ここで、キャラクター クラスと独自のキャラクター フォルダーを追加することを選択したため、Blaster モジュールを再コンパイルする必要があるというメッセージが表示されます。これは、自動コンパイラ エラーが発生するためです。 私の言いたいことをお見せしましょう。 [いいえ]をクリックします。
Visual Studio は、プロジェクトをリロードするかどうかを尋ねてきます。
[すべて再読み込み] をクリックします。
これがプロジェクトです。 BlasterCharacter.h と .cp を含むソース フォルダーの Blaster の下に、このキャラクター フォルダーがあることがわかっています。
BlasterCharacter.cpp には、インクルード エラーがあります。 キャラクター フォルダー内から BlasterCharacter.h をインクルードしようとしていますが、CP ファイルは既にキャラクター フォルダーにあるためです。
したがって、include ステートメントでこの Character を削除するだけで、エラーを取り除くことができます。
これでコンパイルできるはずです。
コンパイルが成功したので、エディターに戻り、新しい Blaster キャラクター クラスに基づいてキャラクター ブループリントを作成します。
次に、コンテンツを右クリックして、新しいフォルダーを作成します。
これは、このプロジェクトのために作成するすべてのブループリントに適用されます。
このフォルダを blueprints と呼び、blueprints フォルダ内に character フォルダを作成します。
ということで、これをフォルダキャラクターと呼ぶことにします。
そして、BlasterCharacter に基づいて新しい C++ クラスを作成できるように、ここにキャラクターのブループリントを配置します。
では、そうしましょう。
そして、Blueprint のキャラクターに貼り付けます。
ここで、この BP_BlasterCharacter に名前を付けます。
そうすれば、どれがブループリント クラスで、どれが C++ クラスであるかがわかります。
それでは、Create Blueprint Class をクリックしましょう。
これが CharacterBlueprint です。
これで、すぐにメッシュを選択できます。
メッシュを選択します。
骨格メッシュには、Learning Kit ゲームからキャラクターを選択します。
今、このように見えるエピックキャラクターがいます.
Y 方向を向いていることがわかり、X 方向に向けたいと思います。
というわけで、90度回転させます。
現在、その足はカプセルの中心にあり、カプセルの半分の高さは 88 です。
したがって、メッシュを 88 単位下に移動できます。
その位置 Z を取得して、-88 に設定しましょう。
これで、キャラクターが地面に置かれます。
というわけで、コンパイルして保存します。
これで、キャラクター クラスとブループリントが完成しました。
これでキャラクター クラスが作成され、このクラスに基づく設計図ができました。このクラスをキャラクター フォルダーに貼り付けました。
したがって、C++ ソリューションは整理されています。
今後のビデオでは、カメラとスプリング アームを追加し、いくつかの入力とプログラム動作機能を追加します。
また後で。