Unreal EngineのC ++ゲームプレイの基礎

画像






Unreal Engine 4のゲームプレイの基礎は、ゲームを作成するための強力なクラスセットを開発者に提供します。 プロジェクトはシューティングゲーム、ファームシミュレーター、ディープRPGになります。重要ではありません。基盤は非常に普遍的であり、ハードワークの一部を担い、いくつかの基準を設定します。 それはエンジンにほとんど統合されているので、Unity3Dのようなエンジンでよくあるように、これらのクラスに固執し、独自のゲームベースを発明しようとしないことをお勧めします。 この基盤を理解することは、プロジェクトを成功させるために非常に重要です。



この記事の対象者



UE4、特にC ++でゲームを作成することに興味があり、Unrealゲームプレイの基礎について詳しく知りたい人向け。 この投稿では、ゲームプレイの基礎として使用する基本クラスについて説明し、そのアプリケーション、エンジンを使用してインスタンスを作成するプロセス、およびゲームコードの他の部分からこれらのクラスにアクセスする方法について説明します。 情報のほとんどは、鈍器にも有効です。



Unreal Engine 4の基本を学びたい場合は、以前のチュートリアルをご覧ください 。 また、初心者向けのバーチャルリアリティに関する個別のガイドも用意しています。 アンリアルエンジン4でVRの仕様を学習する人に役立ちます。



Unreal Engine 4でゲームを作成するとき、多くの既成の定型ブランクに遭遇します。 C ++またはブループリントでゲームを作成するときによく使用するいくつかのクラスがあります。 これらの各クラスとそれらの素晴らしい機能を見て、コードの他の部分からそれらを参照する方法を学びます。 このガイドの情報のほとんどは設計図に適用されますが、私はC ++コードのスニペットを使用しているため、一部の機能は鈍感では利用できず、C ++ユーザーのみに役立ちます。



俳優



おそらくゲームで最もよく使用されるクラスです。 アクターは、AIの敵、ドア、壁、ゲームプレイオブジェクトによって制御されるプレイヤーを含む、レベルのオブジェクトの基盤です。 Actorは、StaticMeshComponent、CharacterMovementComponent、ParticleComponentなど、ActorComponents(次のセクションを参照)を使用して作成されます。 GameMode(以下を参照)などのクラスでさえアクターです(ただし、GameModeには世界で「実際の」位置はありません)。 俳優について知っておく必要のあるいくつかの側面について説明しましょう。



アクターは、ネットワーク上で複製可能なクラスです(マルチユーザーモードの場合)。 これは、SetReplicates(true)コンストラクターの呼び出しを使用して簡単に実行できます。 アクターの効果的なネットワークプログラミングを作成するには、この記事では検討できない多くの側面を考慮する必要があります。



アクターは、ダメージを受けるという概念をサポートしています。 MyActor-> TakeDamage(...)またはUGameplayStatics :: ApplyDamage(...)を使用して、アクターに直接ダメージを与えることができます。 バリエーションがあることを考慮する価値があります:PointDamage(たとえば、武器の場合、レイトレーシング(ヒットスキャン)によって計算されるヒット)とRadialDamage(たとえば、爆発の場合)。 Unreal Engineの公式Webサイトには、 UE4入門記事大きなダメージがあります。



GetWorld()-> SpawnActor <T>(...);を使用して、コード内に新しいアクターインスタンスを簡単に作成できます。 ここで、Tは戻りクラスです。たとえば、AGadgetActor、AGameplayPropなど、独自のクラスの1つのAActorです。



アプリケーションの実行中にアクターが作成されるコードの例を次に示します。



FTransform SpawnTM; FActorSpawnParameters SpawnParams; SpawnParams.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn; SpawnParams.Owner = GetOwner(); /* Attempt to assign an instigator (used for damage application) */ SpawnParams.Instigator = Cast<APawn>(GetOwner()); ASEquippableActor* NewItem = GetWorld()->SpawnActor<ASEquippableActor>(NewItemClass, SpawnTM, SpawnParams);
      
      





アクターにアクセスするには多くの方法があります。 通常、必要な特定のアクターへのポインター/リンクがあります。 上記の例では、変数に着用されているオブジェクトのアクターへのポインターを保存し、それを通してアクターのインスタンスの操作を開始します。



エンジンのプロトタイピングまたはマスタリング時に使用できる非常に便利な関数は、 UGameplayStatics :: GetAllActorsOfClass(...)です。 転送されたクラスのすべてのアクターの配列を取得できます(生成されたクラスを含む。アクタークラスとして渡す場合、すべてのレベルオブジェクトを取得します)。 この機能は、環境と相互作用するあまり効果的でない方法としてしばしば恐れられ回避されますが、利用できる唯一のツールである場合もあります。



アクターには、独自の転送、回転、スケールはありません。 これはすべて、RootComponentを使用して設定および取得されます。 SceneComponents階層の最上位コンポーネント(以下のSceneComponentsの詳細)。 MyActor-> GetActorLocation()のような最も一般的に使用される関数は、実際にはRootComponentに行き、世界での位置を返します。



アクターのコンテキストで使用されるいくつかの便利な機能を次に示します。





アクターには、膨大な機能と多くの変数が含まれています。これは、Unreal Engineのゲームプレイの中核の基盤であるため、驚くことではありません。 このクラスをさらに学習するには、Visual StudioでActor.hヘッダーファイルを開き、どの機能を備えているかを確認するとよいでしょう。 この記事では、まだ考慮すべきことがたくさんあるので、リストの次のクラスに移りましょう。



俳優俳優



コンポーネントはアクター内にあり、標準コンポーネントはStaticMeshComponent、CharacterMovementComponent、CameraComponent、およびSphereComponentです。 これらの各コンポーネントは、動き、物理的な相互作用(たとえば、相互作用する俳優を明確に確認するための衝突量)などの独自の特定のタスクを処理したり、プレイヤーのメッシュなど、世界の何かを視覚的に表示します。



このコンポーネントのサブクラスはSceneComponentです -これは、アタッチメントをサポートする変換(位置、回転、スケール)に関連するすべての基本クラスです。 たとえば、CameraComponentをSpringArmComponentに接続して、サードパーティのカメラを構成できます。 相対位置を正しく配置するには、変換とアタッチメントの両方が必要です。



ほとんどの場合、コンポーネントはアクターのコンストラクターで作成されますが、実行時に作成および破棄することもできます。 最初に、アクターのコンストラクターの1つを見てみましょう。



 ASEquippableActor::ASEquippableActor() { PrimaryActorTick.bCanEverTick = true; MeshComp = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("MeshComp")); MeshComp->SetCollisionObjectType(ECC_WorldDynamic); // Just setting a property on our component RootComponent = MeshComp; // Set our root component for other SceneComponents to attach to ItemComp = CreateDefaultSubobject<USItemComponent>(TEXT("ItemComp")); // not attached to anything (not a SceneComponent with a transform) }
      
      





USkeletalMeshComponentはCreateDefaultSubobject <T> (actor function)を使用して作成され、名前が必要です(この名前はブループリントコンポーネントのリストで確認できます)。 ゲームコードをC ++で記述する場合、この関数を頻繁に使用しますが、コンストラクタコンテキスト内でのみ使用します。



また、MeshCompを新しいRootComponentとして定義していることにお気づきかもしれません。 これで、すべてのシーンコンポーネントをこのメッシュにアタッチする必要があります。これは、次の行を使用して簡単に実行できます。



 WidgetComp = CreateDefaultSubobject<UWidgetComponent>(TEXT("InteractWidgetComp")); WidgetComp->SetupAttachment(MeshComp);
      
      





SetupAttachmentは、元の添付ファイルの処理を処理します。 RootComponent自体を除く、シーンのすべてのコンポーネントのコンストラクターで呼び出されることが予想されます。 私のItemComponentがこのSetupAttachment関数を呼び出さないのはなぜかと思うかもしれません。 このコンポーネントはActorComponentであり、SceneComponentではなく、Transform(位置、回転、スケール)を持たないため、階層に追加しないでください。 ただし、コンポーネントは引き続きアクターに登録されます。 階層から分離されているということは、MyActor-> GetComponentByClassのような関数がすべてのActorComponentsとSceneComponentsを返すことを意味します。



アクターとともに、これらのコンポーネントは、C ++とブループリントの両方でゲームを作成するために重要です。 それらはゲームの構成要素です。 ヘルスポイントを保存し、親のアクターが受けたダメージに反応するHealthComponentなど、ゲームの特定の側面を処理するように、独自のコンポーネントを簡単に作成できます。



以下のコードを使用して、実行時に独自のコンポーネントを作成できます。 これは、コンストラクターにのみ使用されるCreateDefaultSubobjectの動作とは異なります。



 UActorComponent* SpawnedComponent = NewObject<UActorComponent>(this, UStaticMeshComponent::StaticClass(), TEXT("DynamicSpawnedMeshCompoent")); if (SpawnedComponent) { SpawnedComponent->RegisterComponent(); }
      
      





ActorComponentsの便利な機能の一部を次に示します。





ActorComponentの複製を確実にするには、SetIsReplicated(true)関数を呼び出す必要があります。この関数の名前は、アクター関数とわずかに異なります。 これは、たとえば、関数呼び出し中の変数など、コンポーネントロジックの特定の部分を複製する必要がある場合にのみ必要です。つまり、複製されたアクターのすべてのコンポーネントを複製する必要はありません。



プレイヤーコントローラー



これは、ユーザーから入力を受け取るプレーヤーの基本クラスです。 PlayerController自体は、環境に視覚的に表示されず、代わりに、このプレーヤーの世界での視覚的および物理的表現を定義するPawnインスタンスを制御します。 ゲームプレイ中、プレイヤーは複数の異なるPawn(たとえば、車両またはリスポーン時のPawnの新しいコピー)を持つことができ、PlayerControllerのインスタンスはレベル全体で同じままです。 PlayerControllerがPawnをまったく持たない場合があるため、これは重要です。 これは、メニューを開くなどのことをPawnクラスではなくPlayerControllerに追加する必要があることを意味します。



マルチプレイヤーゲームでは、PlayerControllerはそれを所有するクライアントとサーバー上にのみ存在します。 これは、4人用のゲームでは、サーバーには4人のプレイヤーコントローラがあり、各クライアントには1人しかいないことを意味します。 変数を使用する必要がある場合を理解することは非常に重要です。 すべてのプレーヤーがプレーヤー変数の複製を必要とする場合、PlayerControllerに存在するのではなく、PawnまたはPlayerStateに存在する必要があります(以下で説明します)。



PlayerControllersにアクセスする




このクラスにはPlayerCameraManagerが含まれています 。これは、カメラのビューターゲットと、揺れを含む変換を処理します。 PlayerControllerが管理するもう1つの重要なクラスはHUDです(以下で説明します)。 Canvasでのレンダリングに使用され(現在はUMGがあるためあまり使用されていません)、UMGインターフェイスに転送する必要があるデータの管理に使用できます。



新しいプレーヤーがGameModeに接続すると、Login()を使用してGameModeBaseクラスでこのプレーヤーのPlayerControllerが作成されます。



ポーン



これは、プレイヤー(またはAI)が制御するものの物理的および視覚的な表現です。 車、戦士、塔など、ゲームのキャラクターを表すものであれば何でもかまいません。 標準のPawnサブクラスはCharacterで、SkeletalMeshを実装します。さらに重要なことは、通常のシューティングゲームの動きを使用して、環境内のプレーヤーの動きを微調整するための多くのオプションを備えたCharacterMovementComponentです。



マルチプレイヤーゲームでは、Pawnの各インスタンスは他のクライアントに複製されます。 つまり、4人用のゲームでは、サーバーと各クライアントに4つのポーンインスタンスがあります。 プレイヤーが死ぬとPawnインスタンスが「殺され」、多くの場合、リスポーンが作成されると新しいインスタンスが作成されます。 プレーヤーのライフが終了した後に保存する必要があるデータを保存する場合は、このことに留意してください(または、このパターンを完全に破棄し、ポーンインスタンスを常に有効なままにします)

Pawnへのアクセス




作成


GameModeBaseは、SpawnDefaultPawnAtTransformを使用してPawnを作成します。 GameModeBaseクラスは、作成するPawnクラスも決定します。



GameModeBase



使用されるクラス(PlayerController、Pawn、HUD、GameState、PlayerState)を定義する基本クラス。 多くの場合、「Capture the Flag」などのモードでゲームルールを設定するために使用されます。 フラグや敵の波を処理できます。 プレーヤーの作成など、その他の重要な機能を処理します。



GameModeはGameModeBaseのサブクラスです。 MatchStateやその他のシューティング機能など、Unreal Tournamentで元々使用されていた機能がいくつか含まれています。



マルチプレイヤーモードでは、GameModeクラスはサーバー上にのみ存在します! これは、クライアントがそのインスタンスを持たないことを意味します。 シングルプレイヤーゲームでは、彼は影響力を持ちません。 関数を複製し、GameModeに必要なデータを保存するには、すべてのクライアントに存在し、この目的のために特別に作成されたGameStateを使用できます。



GameModeにアクセスする




ハド



これはユーザーインターフェイスクラスです。 これには、多くのCanvasコードが含まれています。これは、 UMGの登場前に書かれたユーザーインターフェイスをレンダリングするためのコードです。 現在、ユーザーインターフェイスのレンダリングに関する主な作業はUMGによって行われています。



クラスはクライアントにのみ存在します。 複製はできません。 PlayerControllerが所有しています。



HUDへのアクセス


PlayerController-> GetHUD()//ローカルPlayerControllerで利用可能。



作成


HUDを所有するPlayerController内でSpawnDefaultHUDを使用して作成(通常のAHUDを作成)し、GameModeBaseで指定されたHUDクラスでInitializeHUDForPlayerを使用してGameModeBaseによって再定義されます。



私の個人的なメモ


私はこのクラスを次第に使用し始め、UMGを使用します。UMGはPlayerControllerを介して制御できます。 忘れないでください-マルチプレーヤーゲームでウィジェットを作成する前に、プレーヤーのコントローラーがIsLocalController()であることを確認する必要があります。



世界



UWorldは、アクターとコンポーネントが存在してレンダリングするマップを表すトップレベルのオブジェクトです。 これには、一定レベルと、ゲームステート、ゲームモード、マップ上のポーンとコントローラーのリストなど、他の多くのオブジェクトが含まれています。



ライントレースとそのすべてのバリエーションは、 World- > LineTraceSingleByChannelなどの関数と他の多くの同様のバリエーションを使用して、Worldを通じて実行されます。



世界にアクセスする


アクセスするには、アクター内でGetWorld()を呼び出すだけです。



静的関数でWorldのインスタンスを取得する必要がある場合、WorldContextObjectを渡す必要があります。これは、基本的に、呼び出し-> GetWorld()に使用できるすべてのアクターの単語です。 ヘッダーファイルの1つからの例を次に示します。



 static APlayerController* GetFirstLocalPlayerController(UObject* WorldContextObject);
      
      





Gameinstance



GameInstanceには、ゲームの期間中ずっと存在し続ける1つのインスタンスがあります。 マップとメニュー間をナビゲートすると、このクラスの同じインスタンスが保存されます。 このクラスを使用して、イベントハンドラーを作成したり、ネットワークエラーを処理したり、ゲームの1つのレベルだけに関連しないゲームパラメーターや関数などのユーザーデータをロードしたりできます。



GameInstanceにアクセスする




私の個人的なメモ


通常、プロジェクトの初期段階では使用されません。 開発を掘り下げない限り、重要なことは何もしません(ゲームセッション、デモのプレイ、レベル間でのデータ転送などの側面を管理できます)



Playerstate



個々のプレーヤーのクライアント/サーバー間で複製される変数のコンテナー。 マルチプレイヤーゲームでは、ロジックを実行することを目的としておらず、単なるデータコンテナーです。これは、PlayerControllerがすべてのクライアントで利用可能ではなく、ゲームが終了するとPawnが破棄されることが多いため、死後に保存する必要があるデータには適用できないためです。



PlayerStateへのアクセス


Pawnには、変数Pawn-> PlayerStateとして含まれています。Controller-> PlayerStateでも使用できます。 PawnのPlayerStateは、PawnがControllerを所有している場合にのみ割り当てられます。そうでない場合はnullptrが割り当てられます。



PlayerStateの使用可能なすべてのインスタンスのリスト(たとえば、試合中のすべてのプレーヤー)は、GameState-> PlayerArrayを介して取得できます。



作成


作成クラスはGameMode(PlayerStateClass)で割り当てられ、AController :: InitPlayerState()で作成されます



私の個人的なメモ


マルチプレイヤーゲームで作業する場合にのみ有用です。



Gamestatebase



PlayerStateに似ていますが、GameMode情報を顧客に提供します。 GameModeインスタンスはクライアントに存在せず、サーバーにのみ存在するため、このクラスは、たとえば試合時間の終わり、チームポイントなどの情報を複製するための便利なコンテナです。



GameStateとGameStateBaseの2つのバリエーションがあります。 GameStateは、GameModeに必要な追加変数を処理します(GameModeBaseとは異なります)



GameStateBaseにアクセスする




私の個人的なメモ


ゲームモードがGameModeBaseの代わりにGameModeから継承されない場合にのみ、GameStateの代わりにGameStateBaseを使用します。



Uobject



エンジンのほぼすべてのベースオブジェクト。 アクター、およびGameInstanceなどの他の基本クラスは、UObjectから継承されます。 レンダリングには決して使用すべきではありませんが、構造体が要件に適さない場合にデータや関数を保存するのに非常に役立ちます。



UObjectの作成


UObjectはアクターのように生成されるのではなく、NewObject <T>()を使用して作成されます。 例:



 TSubclassOf<UObject> ClassToCreate; UObject* NewDesc = NewObject<UObject>(this, ClassToCreate);
      
      





個人メモ


エンジンを十分にマスターし、独自のシステムの作成を掘り下げたくない限り、UObjectから直接クラスを作成することはほとんどありません。 たとえば、データベースからの情報のリストを保存するために使用します。



ネットワークに使用できますが、オブジェクトクラスの追加構成が必要であり、オブジェクトはアクターに保存する必要があります。



Gameplaystatics



静的クラスは、サウンドの再生やパーティクルエフェクトの作成、アクターの作成、アクターへのダメージの適用、ポーンプレーヤー、PlayerControllerなどの取得など、さまざまな標準ゲーム機能を処理するために使用されます。 このクラスは、ゲームプレイ機能へのあらゆる種類のアクセスに非常に役立ちます。 すべての関数は静的です。つまり、次の例に示すように、このクラスのインスタンスへのポインターは必要なく、どこからでも関数を直接呼び出すことができます。



GameplayStaticsにアクセスする


GameplayStaticsはUBlueprintFunctionLibraryであるため、コード(または設計図)のどこからでもアクセスできます。



 UGameplayStatics::WhateverFunction(); // static functions are easily accessed anywhere, just include #include "Kismet/GameplayStatics.h"
      
      





私の個人的なメモ


このクラスには多くの便利な機能があり、ゲームを作成するときに必ず知っておく必要があります。 その機能を調べるためにそれを研究することをお勧めます。



参照資料



Unreal Engine 4の教材でゲームプレイとプログラミングの基本を学ぶのに推奨されます。






All Articles