C++ (Unreal C++)エラー対処まとめ
C++のエラーの対処法をどんどん追加していきます。
UE4を使ってるのでどちらかというとunreal C++での対処法かもしれません。
コード | 説明 | 対処法 |
---|---|---|
不完全クラス型へのポインターは使用できません | インクルードを忘れている。 | |
LINK2019 | 未解決の外部シンボル _hoge1 が関数 _hoge2 で参照されました。 | _hoge1のDocumentにModuleが書いてあるのでそれをBuild.csのPublicDependencyModuleNames.AddRangeに追加 |
Circular dependency detected for filename .../hoge1.h | hoge1.hでhoge2.hをinclude、hoge2.hでhoge1.hをincludeしている。(このエラーでue4のプロジェクト(ver4.17)がクラッシュした) |
Unreal C++ まとめ
UE4のC++勉強中なので分かったことをここにどんどん追加していきます。
なにか間違いがあればご指摘お願いします。
記事にまとめるとその記事に差し替えていきます。
- AActor
- BehaviorTree
- FHitResult
- Iterator
- Log
- FTimerManager
- USoundWave
- UAnimMotage
- USpringArm
- UTimeline
- UWorld
AActor
TakeDamage(ダメージ受ける側)
.h
float Health;
.cpp
float AMyActor::TakeDamage(float Damage, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, class AActor* DamageCauser) { // Call the base class - this will tell us how much damage to apply const float ActualDamage = Super::TakeDamage(Damage, DamageEvent, EventInstigator, DamageCauser); if (ActualDamage > 0.f) { Health -= ActualDamage; if (Health <= 0.f) { //体力が0以下になったときの処理 } } return ActualDamage; }
InflictDamage(ダメージを与える側)
.h
void InflictDamage();
.cpp
void AMyCharacter::InflictDamage() { APlayerController* PlayerController = Cast<APlayerController>(GetController()); if (PlayerController != nullptr) { // Perform a trace @See LineTraceSingle FHitResult TraceResult(ForceInit); TraceHitForward(PlayerController, TraceResult); // If the trace return an actor, inflict some damage to that actor AActor* ImpactActor = TraceResult.GetActor(); //fResult(LineTraceSingleByChannelのFHitResultを使用してもいい) if ((ImpactActor != nullptr) && (ImpactActor != this)) { // Create a damage event TSubclassOf<UDamageType> const ValidDamageTypeClass = TSubclassOf<UDamageType>(UDamageType::StaticClass()); FDamageEvent DamageEvent(ValidDamageTypeClass); const float DamageAmount = 25.0f; //ダメージ量 ImpactActor->TakeDamage(DamageAmount, DamageEvent, PlayerController, this); } } }
BehaviorTree
Characterクラスのhoge_AICharacterとAIControllerクラスのhoge_AIControllerを作成
.h
UCLASS() class hogeProject_API hoge_AIController : public AAIController { GENERATED_BODY() public: hoge_AIController(const class FObjectInitializer& ObjectInitializer); // UProperty 値が自動的に書き込みまたは読み出されることを許可しない UPROPERTY(Transient) class UBlackboardComponent* BlackboardComp; UPROPERTY(Transient) class UBehaviorTreeComponent* BehaviorComp; virtual void Possess(class APawn* InPawn); // BlackboardCompのKeyに対し値を設定する void SetEnemy(class APawn* InPawn); // BluePrint側でこの関数を呼び出せるように設定 UFUNCTION(BlueprintCallable, Category = Behavior) void SearchForEnemy(); protected: uint8 EnemyKeyID; // BlackBoardで定義したKeyID uint8 EnemyLocationID; // BlackBoardで定義したKeyID };
.cpp
hoge_AIController::hoge_AIController(const class FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { BlackboardComp = ObjectInitializer.CreateDefaultSubobject<UBlackboardComponent>(this, TEXT("BlackBoardComp")); BehaviorComp = ObjectInitializer.CreateDefaultSubobject<UBehaviorTreeComponent>(this, TEXT("BehaviorComp")); } void hoge_AIController::Possess(class APawn* InPawn) { Super::Possess(InPawn); AAICharacter* Bot = Cast<AAICharacter>(InPawn); if (Bot && Bot->AIBehavior) { BlackboardComp->InitializeBlackboard(*Bot->AIBehavior->BlackboardAsset); EnemyKeyID = BlackboardComp->GetKeyID("Enemy"); EnemyLocationID = BlackboardComp->GetKeyID("Destination"); BehaviorComp->StartTree(*Bot->AIBehavior); } } void hoge_AIController::SearchForEnemy() { APawn* MyBot = GetPawn(); if (MyBot == NULL) return; const FVector MyLoc = MyBot->GetActorLocation(); float BestDistSq = MAX_FLT; hogeCharacter* BestPawn = NULL; //Get All pawm in the world for (FConstPawnIterator It = GetWorld()->GetPawnIterator(); It; ++It) { hoge_Character* TestPawn = Cast<hoge_Character>(*It); if (TestPawn) { //Calculate between player and AI const float DistSq = FVector::Dist(TestPawn->GetActorLocation(), MyLoc); if (DistSq < BestDistSq) { BestDistSq = DistSq; BestPawn = TestPawn; // Default: BestPawn=NULL } } } if (BestPawn) { SetEnemy(BestPawn); } } void hoge_AIController::SetEnemy(class APawn* InPawn) { //Store player pointer BlackboardComp->SetValue<UBlackboardKeyType_Object>(EnemyKeyID, InPawn); //Store player Location BlackboardComp->SetValue<UBlackboardKeyType_Vector>(EnemyLocationID, InPawn->GetActorLocation()); }
FHitResult
.cpp
//変数一覧 FVector_NetQuantize HitLocation = fHitResult.Location; FVector_NetQuantize HitImpactPoint = fHitResult.ImpactPoint; FVector_NetQuantizeNormal HitNormal = fHitResult.Normal; FVector_NetQuantizeNormal HitImpactNormal = fHitResult.ImpactNormal; TWeakObjectPtr<AActor> HitActor = fHitResult.Actor; TWeakObjectPtr<UPrimitiveComponent> HitComponent = fHitResult.Component; FName HitBoneName = fHitResult.BoneName; bool HitbBlockkingHIt = fHitResult.bBlockingHit; int32 HitbStartPenetraing = fHitResult.bStartPenetrating; float HitDistance = fHitResult.Distance; int32 HitFaceIndex = fHitResult.FaceIndex; int32 HitItem = fHitResult.Item; float HitPenetrationDepth = fHitResult.PenetrationDepth; TWeakObjectPtr<UPhysicalMaterial> HitPhysMaterial = fHitResult.PhysMaterial;//if you need it functional, set fCollisionQueryParams.bReturnPhysicalMaterial = true; float HitTime = fHitResult.Time; FVector_NetQuantize HitTraceEnd = fHitResult.TraceEnd; FVector_NetQuantize HitTraceStart = fHitResult.TraceStart;
FTimerManager
USoundWave
SoundWave(インポートした音源)
.h
USoundWave* FireSound;
.cpp
static ConstructorHelpers::FObjectFinder<USoundWave>FireSoundWave(TEXT("SoundWave'/Game/Sounds/Weapon_AssaultRifle/Stereo/AssaultRifle_Shot01_Stereo.AssaultRifle_Shot01_Stereo'")); FireSound = FireSoundWave.Object; //FireSoundWaveの部分は適当な名前で結構です。 //パスは目的のものを右クリック→リファレンスをコピーでとれるのでそれをTEXT("ここ")の部分に貼り付けてください。
UAnimMotage
AnimInstanceを親クラスとしたものを作成
AnimInst.h
#include "Animation/AnimInstance.h" #include "AnimInst.generated.h" UCLASS(transient, Blueprintable, hideCategories = AnimInstance, BlueprintType) class hogeProject_API UAnimInst : public UAnimInstance { GENERATED_UCLASS_BODY() };
AnimInst.cpp
#include "(プロジェクト名).h" #include "AnimInst.h" UAnimInst::UAnimInst(const FObjectInitializer& ObjectInitializer) : Super(ObjectInitializer) { }
実装先
Character.h
UAnimMontage* hoge_AnimMotage;
void Fire();
Character.cpp
#include "Animation/AnimInstance.h" ACharacter::ACharacter() { Mesh=CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Mesh")); static ConstructorHelpers::FObjectFinder<UObject>hogeMontage(TEXT("AnimMontage'(パス)'")); hoge_AnimMotage = (UAnimMontage*)hogeMontage.Object; //FObjectFinder<UAnimMontage>ではエラーを吐くので、 //FObjectFinder<UObject>で取得してオブジェクトを作成するときにUAnimMontageに型を変換します。 } void ACharacter::Fire() { UAnimInst* AnimInst = Cast<UAnimInst>(Mesh->GetAnimInstance()); AnimInst->Montage_Play(hoge_AnimMotage, 1.0f); //if(AnimInst->Montage_IsPlaying(hoge_AnimMotage)){}でAnimMontageが再生しているかどうか }
USpringArm
h
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = Camera, meta = (AllowPrivateAccess = "true")) class USpringArmComponent* CameraBoom;
Character.cpp
CameraBoom = CreateDefaultSubobject<USpringArmComponent>(TEXT("CameraBoom")); CameraBoom->SetupAttachment(RootComponent); CameraBoom->TargetArmLength = 200.0f; //カメラがどのくらい後ろの位置で追従するか CameraBoom->bUsePawnControlRotation = true; // Rotate the arm based on the controller
UTimeline
.h
#include "Components/TimelineComponent.h" UPROPERTY() UTimelineComponent* ScoreTimeline; UPROPERTY() UCurveFloat* fCurve; FOnTimelineFloat InterpFunction{}; UFUNCTION() void TimelineFloatReturn(float val);
.cpp
#include "Components/TimelineComponent.h" ACharacter::ACharacter(){ static ConstructorHelpers::FObjectFinder<UCurveFloat> Curvy(TEXT("CurveFloat'(パス)'")); if (Curvy.Object) { fCurve = Curvy.Object; } ScoreTimeline = CreateDefaultSubobject<UTimelineComponent>(TEXT("TimelineScore")); //Bind the Callbackfuntion for the float return value InterpFunction.BindUFunction(this, FName{ TEXT("TimelineFloatReturn") }); } void ACharacter::TimelineFloatReturn(float val) { //タイムラインの値がここに返る } void ACharacter::PlayTimeLineFunc() { ScoreTimeline->AddInterpFloat(fCurve, InterpFunction, FName{ TEXT("Floaty") }); ScoreTimeline->Play(); } } void A4Character::ReverseTimeLineFunc() { ScoreTimeline->AddInterpFloat(fCurve, InterpFunction, FName{ TEXT("Floaty") }); ScoreTimeline->Reverse(); }
UWorld
LineTraceSingleByChannel
.h
public: UPROPERTY(EditAnywhere) float RayLineLength = 1000; UPROPERTY(EditAnywhere) FLinearColor fLineColor; FHitResult fHitResult; FVector fStartLocation; FVector fEndLocation; float Duration; float Thickness;
.cpp
//get Camera UCameraComponent* CameraComp = this->FindComponentByClass<UCameraComponent>(); //DebugLine fStartLocation = CameraComp->GetComponentLocation();//ラインの始まり fEndLocation = fStartLocation + (CameraComp->GetForwardVector() * RayLineLength);//ラインの終わり fLineColor = FLinearColor(0.0, 255.0, 0.0, 0.0); //ラインの色 Duration = 0.5; //継続時間 Thickness = 1.0f; //ラインの厚さ UKismetSystemLibrary::DrawDebugLine(GetWorld(), fStartLocation, fEndLocation, fLineColor, Duration, Thickness); //LineTrace FCollisionQueryParams fCollisionQueryParams; fCollisionQueryParams.TraceTag = FName(""); fCollisionQueryParams.OwnerTag = FName(""); fCollisionQueryParams.bTraceAsyncScene = false; fCollisionQueryParams.bTraceComplex = false; fCollisionQueryParams.bFindInitialOverlaps = false; fCollisionQueryParams.bReturnFaceIndex = false; fCollisionQueryParams.bReturnPhysicalMaterial = false; fCollisionQueryParams.bIgnoreBlocks = false; fCollisionQueryParams.IgnoreMask = 0; fCollisionQueryParams.AddIgnoredActor(this); GetWorld()->LineTraceSingleByChannel(fHitResult, fStartLocation, fEndLocation, ECollisionChannel::ECC_Visibility, fCollisionQueryParams); if (fHitResult.Actor == nullptr) { return; } //OutputLog GLog->Log("On Hit an Actor of " + fHitResult.Actor->GetName() + " " + FString::SanitizeFloat(my_Distance));
Unityまとめ
Unityの関数などをまとめ。
時間関係
ポーズ
Time.timeScale==0;//ポーズ
Time.timeScale==1;//ポーズ解除
delay
---------180フレーム後に****の処理を行う---------
using UniRx;
Observable.TimerFrame(180).Subscribe(_ =>
{
****; //delay後の処理
}).AddTo(this);
---------0.2秒後に****の処理を行う---------
Observable.Timer(TimeSpan.FromSeconds(0.2)).Subscribe(_ =>
{
****; //delay後の処理
}).AddTo(this);
オーディオ関係
再生、停止
AudioSource BGM = GameObject.Find("****").GetComponent<AudioSource>();
BGM.Play();再生開始
BGM.Stop();一時停止
シーン移動
移動したいSceneを開き、「File→Build Setting→Add open scene」
SceneManager.LoadScene(1); //Build Settingのシーン番号
出現、消滅
******.enabled= true;
******.enabled= false;
PCで絵を書く方法
ペンタブを使って絵を書き始めたので紹介。
PCで絵を描くには
①ペンタブor液タブ (マウスで描けないこともないがあったほうがいい)
②ペイントソフト
が必要です。とりあえず自分が使っているのを紹介。
①WACOM社のIntuos Draw (ペンタブ)
価格とメジャーな会社の製品なので選びました。必要システムを下記に示します。ドライバのインストール方法も下に示します。
どれを選べばいいか分からないって方はとりあえずWACOM社のIntuous シリーズを選べばいいかと思います。
ペンタブの必要システム
OS:Windows7,8,10 もしくは Mac OS X 10.8.5 以降
USBポート搭載
インターネット接続
②Medibang paint pro
無料で割と機能もそろっているので選びました。有料ではPhotoshop,Illustrator,Clip Studio,SAIなどがあります。ここらへんはいろんな情報がネットに落ちているので
価格と情報量の多さを比べて好みで選んでください。無料はこちらから
どちらかというとこっちの必要環境を気にしたほうがいいと思います。
ペンタブのドライバのインストール
そのままUSBで繋いでも使えないので使えるようにしてあげなければいけません。
付属のCDを使うかHPからダウンロードするかの2択です。付属のCDを使う場合は説明するほどではないと思うのでHPからダウンロードする方法を紹介します。
- 自分の買ったペンタブの型番をクリック→自分のOSを選択→検索をクリック
- 最新(一番上)のドライバのダウンロードページへをクリック
- 下にスクロールしていくと画像のようなダウンロードボタンがあるのでクリック
- ドライバがダウンロードされるので開く
- 指示にしたがってインストール(同意するぐらいなので特に気にしなくてもいい)
- 再起動を促されるので再起動
で完了です。
仮想キーボードの作り方(UE4.13~)
World内にキーボードとディスプレイを設置して文字を入力する方法をメモ。
VRでも利用可能みたいです。
①キャラクターの設定
自分の操作するキャラクター(ここではFirstPersonCharacter)にWidgetInteractionを追加します。そこからデバッグラインが出るので違和感ない場所に移動して「詳細→Debugging→Show Debug」をオンにします。
以下の画像ではSphereの下に追加していますが、FP_Gunの下でもいいようです。
②入力の設定
FirstPersonCharacterのイベントグラフに仮想キーボードのボタンを押下する動作を割り当てたい入力イベントを出します。そして、①で追加したWidget Interactionをドラックしグラフに持っていき、そこから Press Pointer KeyとRelease Pointer Keyを追加します。Keyは両方ともLeft Mouse Buttonにします。(ここでは右クリックが左クリックとみなされ、仮想キーボードのボタンを押下したことになります。)
③ブループリントの準備
Actorとwidgetブループリントを2つずつ作成します。(KeyPadはキーボード、Displayは入力した文字、値が表示されるディスプレイです。)
④Display_WB 1
Display用のWidgetブループリント(Display_WB)を開き、Canvas PanelをText Boxに置き換え、「右クリック→Wrap with...→Size Box」をクリックします。
⑤Display_WB 2
Size BoxをDesired on Screenにし、Width overrideとHeight overrideを好きな値に設定します。
⑥Display_WB 3
Hint Textにはここに入力してほしいことを書きます。よくログイン画面に見る「パスワード」などの薄く表示される文字です。ここはなくてもかまいませんが、ないとここに何を表示させたいのか分からなくなります。
⑦KeyPad_WB 1
KeyPad用のWidgetブループリント(KeyPad_WB)を開き、Buttonにtextを親子づけして追加して、「Detail→Content→text」には送りたい文字を書きます。他にBackSpace用とEnter用のボタンも用意します。その後、全てのボタンで 「Detail→Interaction→Is Focusable」のチェックを外します。
⑧KeyPad_WB 2
KeyPad_WBのグラフに行き、全てのボタンの「OnClicked」イベントを出します。
⑨KeyPad_WB 3
String型とWidgetInteractionComponent型の2つの変数を追加します。(String型をChar To Send、WidgetInteractionComponent型をWidgetInteractionと名づけました。)
⑩KeyPad_WB 4
BackSpaceとEnter以外の「OnClicked」イベントにChar To Sendをセットしつなげ、送りたい文字をセットします。アルファベットはもちろん、数字やひらがな、カタカナ、漢字も大丈夫みたいです。
⑪KeyPad_WB 5
Send Key Charを出し、ターゲットにはWidgetInteraction、CharctersにはChar To Sendを繋げます。
⑫KeyPad_WB 6
BackSpaceの「OnClicked」イベントにPress and Release Keyをつなげ、ターゲットにWidgetInteractionを繋げ、KeyをBackSpaceにします。
⑬KeyPad_WB 7
イベントディスパーチャー(ここではEnterPressedと名付けました)を追加し、呼び出します。グラフ上までドラックしてドロップするとアクションを選べるので「呼び出す」を選択するか、右クリックで検索して出してください。
⑭Display_Actor 1
Display_Actor(Display用のアクター)を開き、Add componentからWidgetを出します。Widget Class にDisplay_WBを選択し、Draw at Desired Sizeにチェックを入れます。
モザイクをかけてますが気にしないでください。(新しく用意するのめんどくさかった)
⑮KeyPad_Actor 1
同じようにKeyPad_Actor(KeyPad用のアクター)を開き、Widget ClassにKeyPad_WBを選択します。そして、Window Focusableのチェックを外し、Draw at Desired sizeのチェックを入れます。
⑯KayPad_Actor 2
さらにAdd componentからWidget Interactionを追加し、Enable Hit Testingをオフにします。
⑰KeyPad_Actor 3
KeyPad_ActorのBegin PlayイベントにCast To KeyPad_WBを繋げ、WidgetとGet User Widget ObjectをObjectピンに繋げます。
⑱KeyPad_Actor 4
KeyPad_WBのWidgetInteractionをセットし、KeyPad_ActorのWidget Interactionを繋げます。その後、ノード検索で、EnterPressedを割り当てるを、選択するとBind Event to EnterPressedとカスタムイベントが出て来ます。
ひとつずつ、Bind Event to EnterPressedとカスタムイベントを出してもダメ。
カスタムイベントの先にはEnterを押した時にやって欲しい処理を、書きます。
⑲KeyPad_Actor 5
KeyPad_ActorにDisplay_Actor型の変数を追加します。
⑳KeyPad_Actor 6
world内にKeypadとDisplayを設置し、KeypadのTargetDisplayのところをDisplayにします。
以上です。
参考
Leap motionを用いた物体移動
12/6にOculus Touchが発売されたということでおそらくもうLeap motionで
代用することもないと思いますが、何かあったときのためにここにメモしておきます。
ちなみにUE4のver4.13だとなぜか出来なかったのでそれ以下をおすすめします。
(私は4.12を使用しました。)
手順
①プラグインのダウンロード
以下のGithubからLeap motionのプラグインをダウンロードします。
②プラグインを使用可能に
「編集→Plugins→Input Devices」にあるLeap Motion PluginのEnabledのところにチェックを入れます。
③GameModeの作成
コンテンツブラウザの場所で右クリックメニューから「ブループリント→ブループリントクラス→Game Mode」を選択します。名前は適当に。(ここではLeapGameModeとします。)
④キャラクターを作成
「表示オプション→プラグインのコンテンツを表示」にチェックを入れます。その後、「LeapMotion コンテンツ→Blueprints→Rigging」からLeapRiggedCharacterをコピーし、自分のコンテンツブラウザに置きます。ここではLeapCharacterと呼びます。
⑤GameModeの設定
LeapGameModeを開き、Default Pawn Classを④のLeapCharacterにします。
⑥インターフェイスの作成
右クリックメニューから「詳細なアセットを作成→ブループリント→ブループリントインターフェイス」を選択します。ここではPickup Interfaceとします。下の画像のようにインプットにスタティックメッシュアクタとVector変数を追加します。
⑦キャラクターにインターフェイスを設定
LeapCharacterを開き、クラス設定を選択し、インターフェイスの部分に⑤、⑥で作成したインターフェイスを追加します。
⑧関数の作成(キャラクター) 1
関数(ここではClosest Handという名前にします)を作成し、関数内を以下のようにします。インプットにVector型、アウトプットにName型を追加し、ローカル変数にName型変数を追加します。
⑨関数の作成(キャラクター) 2
もう一つ関数(ここではPickup if Emptyという名前にします)を作成し、関数内を以下のようにします。インプットにスタティックメッシュアクタ変数とBoolean変数を作成します。Closest Handは⑧で作成したものです。
⑩関数の作成(キャラクター) 3
さらにもう一つ関数(ここではDrop if Not Emptyという名前にします)を作成します。
⑪キャラクターのイベントグラフ
LeapCharacterのイベントグラフを以下のようにします。イベントPickupは⑥で作ったものをコンパイルしておかないと出てきません。
⑫物体のブループリントを作成
動かしたいスタティックメッシュをレベル上に出し、詳細からブループリントを作成します。
⑬物体のブループリントのイベントグラフ
Does Implement Interface と Pickup のインターフェイスをキャラクターに追加したインターフェイスと同じにします。
すべてコンパイルしてプレイすると物体移動できるようになります。
物体を掴む条件として物体に手が当たっている(当たり判定がある)ことが条件で、グーのように握らないとGrabイベントが発生してくれません。また、手に強制的にひっつけている感じであり、実際に掴んでいるわけではないみたいです。
参考
UE4のLeap motion のプラグイン製作者が以下の動画で説明していました。
ブループリントプロジェクトに C++ 関数を追加する方法
よく欲しい機能のノードがなかったりしますが、自分でノードを作ることができますのでその方法をメモしておきます。
動作環境は
- UE4: 4.12.5 と 4.14.0
- Widows8.1
- Visual Studio Community 2015
です。
手順
①Visual StudioかXCodeのインストール
Visual StudioかXCodeをインストールしておきます。Visual Studio をインストールする際は Common Tools for Visual C++ 2015 も合わせてインストールする必要だそうです。
②Sourceフォルダの作成
エクスプローラーからやりたいプロジェクトのプロジェクトファイル(.uproject)がある階層に行き、新しいフォルダを作成し、名前をSourceにします。
③C++プロジェクトファイルの作成
プロジェクトファイルを右クリックすると、Generate Visual Studio project files というのがあるのでクリックします。Mac の場合はメニューの下部にサービスという項目があるのでその中にある Generate Xcode Project を選びます。
④新規C++クラスの作成 1
レベルエディタのメニューから「ファイル→新規C++クラス」を選択します。
⑤新規C++クラスの作成 2
以下の画面が出てくるのでアクターを選択し、「次へ」をクリックします。
⑥新規C++クラスの作成 3
ファイル名を任意の名前に決めて、公開設定をパブリックにします。その後、「クラスを作成」をクリックします。すると、ヘッダファイル(.h)とソースファイル(.cpp)が作成され、visual studioかXCodeが開きます。開いていない場合はコンテンツブラウザの C++ クラス(C++ Classes)フォルダ内にある 作成した名前のファイルをダブルクリックします。
※ヘッダorソースファイルを直接ダブルクリックで開かないほうがいいみたいです。
⑦ソースファイルとヘッダファイルを編集
ソースファイルとヘッダファイルを編集します。
※ソースファイルの「#include "(作成したファイル名).h"」は一番上でないとダメみたいです。
⑧コンパイル
レベルエディタのツールバーのコンパイルをクリックします。成功すると作ったものがブループリントで使えるようになります。
以上です。
参考