UnrealYoshidaのUE4講座

UnrealEngine4(UE4)に関する記事を投稿しています

よく使われる処理をUnrealC++で書いてみようの巻。

こんにちくわ。
吉田です。初めましての方が多そうなので自己紹介をさせていただきます。

 年齢は3歳。(18歳です...)
 一応高校生やらせてもらってます。UE4に触れ始めたのは去年の今頃だった記憶が...
 Twitterやってます。更新多めでもかまわないよって方、フォローミー('ω')
Profile : Kai Yoshida

twitter.com

今回は
qiita.comに参加させてもらいましたので、
自分なりに書きたいものを書きたいと思います('ω')
なお、本記事ではUE4 [4.14.0],Visual Studio Community 2015を使用しています。
Visual Studio Community 2015のダウンロードはこちらから。
www.visualstudio.com



今回のテーマはブログの題の通りです。
ごちゃごちゃ言っていても仕方がないので本題に入りましょう。


BeginOverlap,EndOverlap
こちらはBPでもおなじみCollisionの衝突判定のイベントです。
BPだとこんな感じ。

BP :
f:id:ikagamedev:20161211013731p:plain
これを使わずしてゲームは作れないって程重要なノードです。まずはこいつを実装してみましょうか。


まず、自分は今こんな状況にいる!ってシチュエーションを作りましょう。
今回は、ドアの開閉スクリプトをBPじゃなくUnrealC++で作りたくて夜も朝までしか寝れない!ってシチュエーションにしましょう。

1 : DoorClassを作る。
はい。
f:id:ikagamedev:20161211020832p:plain
f:id:ikagamedev:20161211020834p:plain
ActorClassを継承したDoorClassを作りましょう。

コードを書きます。

まずは基本となる、StaticMeshをアサインする処理から。

Door.h

UPROPERTY(EditAnywhere,BlueprintReadOnly,Category = "Door", meta = (AllowPrivateAccess = "true"))
class UStaticMeshComponent* DoorMesh;

UPROPERTY(EditAnywhere,BlueprintReadOnly,Category = "Door", meta = (AllowPrivateAccess = "true"))
class UStaticMeshComponent* DoorFrameMesh;

UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "Door", meta = (AllowPrivateAccess = "true"))
class UBoxComponent* DoorTrigger;

ひとつずつ解説していきます。

UPROPERTY([specifier, specifier, ...], [meta=(key=value, key=value, ...)])
 Type VariableName;

UPROPERTY :
UPROPERTYを簡単に説明すると、エンジン内に存在するUPROPERTYマクロを使用した
変数の宣言です。こいつを使うことによってBPClassとの連携が取れます。


specifier :
specifier(指定子)はUPROPERTYマクロを宣言する際に記述することによって、宣言子に指定子を追加しさまざまな振る舞いを持たせることができるものです。
公式ドキュメントにくわーーーしく載っています。
docs.unrealengine.com

meta :
metaを一言で説明すると、パラメータの編集を制御できるようにするためのもの。です。
Dv7Pavilionさんが詳しく説明してくれてますので、詳しくはリンクをクリック
qiita.com


2 : ソースファイルのコンストラクタにComponentを追加し、階層を設定

Door.cpp

ADoor::ADoor()
{
        DoorMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Door"));
	DoorFrameMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorFrame"));
	DoorTrigger = CreateDefaultSubobject<UBoxComponent>(TEXT("DoorTrigger"));

	//	アタッチ
	RootComponent = DoorFrameMesh;
	DoorMesh->SetupAttachment(DoorFrameMesh);
	DoorTrigger->SetupAttachment(DoorMesh);

}

Componentを追加はCreateDefaultSubobject,Attachに関してはSetupAttachmentです。
詳しく説明すると、今回の主題とはかけ離れてしまうので各自よろしくお願いします...


3 : Begin,EndOverlap関数の定義

Door.h

        // BeginOverlap
	UFUNCTION(BlueprintCallable, Category = "Door", meta = (AllowPrivateAccess = "true"))
	void OnDoorTriggerBeginOverlap(class UPrimitiveComponent* HitComp, class AActor* OtherActor,
		 class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, 
			 const FHitResult & SweepResult);

	// EndOverlap
	UFUNCTION(BlueprintCallable, Category = "Door", meta = (AllowPrivateAccess = "true"))
	void OnDoorTriggerEndOverlap(class UPrimitiveComponent* HitComp, class AActor* OtherActor,
	class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

なお、関数の引数ですがこれからのバージョンアップで増えたり減ったりすると思うので、あくまで動作を保証するバージョンは4.14.0
ということにさせてください。
UFUNCTIONマクロですが、BPClassと連携が取れる(関数Ver)とでも思っておいてください。

Door.cpp

        // OverlapEvent Override
	DoorTrigger->OnComponentBeginOverlap.AddDynamic(this, &ADoor::OnDoorTriggerBeginOverlap);
	DoorTrigger->OnComponentEndOverlap.AddDynamic(this, &ADoor::OnDoorTriggerEndOverlap);

AddDynamicヘルパーマクロというものを用いることで、自動的に関数名の文字列を生成してくれるそうです。
これによってOverlapEventのBindingは完了です。
あとは関数を呼び出して好きなタイミングで使えばOK

Door.cpp

void ADoor::OnDoorTriggerBeginOverlap(class UPrimitiveComponent* HitComp, class AActor* OtherActor,
class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
	const FHitResult & SweepResult)
{
        // 好きな処理を書いてください。
}

void ADoor::OnDoorTriggerEndOverlap(class UPrimitiveComponent* HitComp, class AActor* OtherActor,
class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
	// 好きな処理を書いてください。
}

Full Code

Door.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "GameFramework/Actor.h"
#include "Door.generated.h"

UCLASS()
class SIDESHOOTERCPP_API ADoor : public AActor
{
	GENERATED_BODY()
	
public:	
	// Sets default values for this actor's properties
	ADoor();

	// Called when the game starts or when spawned
	virtual void BeginPlay() override;
	
	// Called every frame
	virtual void Tick( float DeltaSeconds ) override;

	//	BeginOverlap
	UFUNCTION(BlueprintCallable, Category = "Door", meta = (AllowPrivateAccess = "true"))
	void OnDoorTriggerBeginOverlap(class UPrimitiveComponent* HItComp, class AActor* OtherActor,
		 class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, 
			 const FHitResult & SweepResult);

	//	EndOverlap
	UFUNCTION(BlueprintCallable, Category = "Door", meta = (AllowPrivateAccess = "true"))
	void OnDoorTriggerEndOverlap(class UPrimitiveComponent* HItComp, class AActor* OtherActor,
	class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

	//	Add primitive
	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Door")
	class UStaticMeshComponent* DoorMesh;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Door")
	class UStaticMeshComponent* DoorFrameMesh;

	UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Door")
	class UBoxComponent* DoorTrigger;

};


Door.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include "SideShooterCpp.h"
#include "Door.h"


// Sets default values
ADoor::ADoor()
{
 	// Set this actor to call Tick() every frame.  You can turn this off to improve performance if you don't need it.
	PrimaryActorTick.bCanEverTick = true;

	//	Create the Object
	DoorMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("Door"));
	DoorFrameMesh = CreateDefaultSubobject<UStaticMeshComponent>(TEXT("DoorFrame"));
	DoorTrigger = CreateDefaultSubobject<UBoxComponent>(TEXT("DoorTrigger"));

	//	Attach process
	RootComponent = DoorFrameMesh;
	DoorMesh->SetupAttachment(DoorFrameMesh);
	DoorTrigger->SetupAttachment(DoorMesh);

	//	OverlapEvent Override
	DoorTrigger->OnComponentBeginOverlap.AddDynamic(this, &ADoor::OnDoorTriggerBeginOverlap);
	DoorTrigger->OnComponentEndOverlap.AddDynamic(this, &ADoor::OnDoorTriggerEndOverlap);

}

// Called when the game starts or when spawned
void ADoor::BeginPlay()
{
	Super::BeginPlay();
	
}

// Called every frame
void ADoor::Tick( float DeltaTime )
{
         // 扉が開く処理
}

void ADoor::OnDoorTriggerBeginOverlap(class UPrimitiveComponent* HItComp, class AActor* OtherActor,
class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep,
	const FHitResult & SweepResult)
{
        // 好きな処理を書いてください。
}

void ADoor::OnDoorTriggerEndOverlap(class UPrimitiveComponent* HItComp, class AActor* OtherActor,
class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
        // 好きな処理を書いてください。
}

・おまけ
BeginOverlap,EndOverlapをイベントにしBPへ公開したい場合は

Door.h

 // BeginOverlap
 UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "Door", meta = (AllowPrivateAccess = "true"))
 void OnDoorTriggerBeginOverlap(class UPrimitiveComponent* HItComp, class AActor* OtherActor,
 class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, 
 const FHitResult & SweepResult);

 // EndOverlap
 UFUNCTION(BlueprintImplementableEvent, BlueprintCallable, Category = "Door", meta = (AllowPrivateAccess = "true"))
 void OnDoorTriggerEndOverlap(class UPrimitiveComponent* HItComp, class AActor* OtherActor,
 class UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

Door.hのBegin,EndOverlap関数のUFUNCTIONにBlueprintImplementableEventを追加し、Door.cppの関数の定義を消せばOKです。
コンパイルしてDoorClassを継承したDoorBPClassを作り、

f:id:ikagamedev:20161218000642p:plain
自分だけのイベントを作っちゃいましょう('ω')

これでOverlapEventに関しては終わり!
お次はAnimBPをC++から制御する処理についてです。

Animation
仕様 :
マウスの右クリックでADS(銃のサイトを覗き、安定させること)のAnimationをさせる

1 : AnimBPを作成する。
f:id:ikagamedev:20161211150739p:plain
ここでひとつ注意です。必ず AnimInstanceClass を継承したAnimBPClassを作成してください。
名前はなんでもOkです。


2 : AnimInstanceClassを継承したC++Classを作る
f:id:ikagamedev:20161211152654p:plain


f:id:ikagamedev:20161211152805p:plain
わかりやすい名前で作成の後、コードを書いていきましょう。
今回は TPSAnimInstance という名前で作成しました。



3 : 変数宣言

TPSAnimInsatnce.h

UCLASS(transient,Blueprintable,hideCategories=AnimInstance,BlueprintType)
class SGRAYSHOOTER_API UTPSAnimInstance : public UAnimInstance
{
GENERATED_UCLASS_BODY()

public:
UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Combat")
bool bIsAiming;
};


4 : コンストラクタで値の初期化処理

TPSAnimInstance.cpp

UTPSAnimInstance::UTPSAnimInstance(const FObjectInitializer& ObjectInitializer)
  : Super(ObjectInitializer)
{
  // ここに変数の初期値を設定します。
  bIsAiming = false;
}

Full Code :

TPSAnimInstance.h

// Fill out your copyright notice in the Description page of Project Settings.

#pragma once

#include "Animation/AnimInstance.h"
#include "TPSAnimInstance.generated.h"

/**
 * 
 */
UCLASS(transient,Blueprintable,hideCategories=AnimInstance,BlueprintType)
class SIDESHOOTERCPP_API UTPSAnimInstance : public UAnimInstance
{
  GENERATED_UCLASS_BODY()
	
public:
  UPROPERTY(VisibleAnywhere, BlueprintReadOnly, Category = "Combat")
  bool bIsAiming;
};

TPSAnimInsatnce.cpp

// Fill out your copyright notice in the Description page of Project Settings.

#include "プロジェクトの名前.h"
#include "TPSAnimInstance.h"

UTPSAnimInstance::UTPSAnimInstance(const FObjectInitializer& ObjectInitializer)
  : Super(ObjectInitializer)
{
  // ここに変数の初期値を設定します。
  bIsAiming = false;
}


5 : 使用しているCharacterClassで関数、変数を制作

ThirdPersonCharacter.h

UCLASS(config=Game)
class ThirdPersonCharacter : public ACharacter
{
   GENERATED_BODY()

   UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "Combat")
   class USkeletalMeshComponent* myMesh;

protected:
   void Aim();
   void StopAim();
};


6 : CharacterClassのコンストラクタで初期化処理

AThirdPersonCharacter::AThirdPersonCharacter()
{
   // 上にごちゃごちゃ書いてあると思いますが気にせず。
   myMesh = GetMesh();
}


7 : PlayerInputComponentを設定

f:id:ikagamedev:20161211171954p:plain
BPからバインドされたインプットイベントを呼ぶにはノード一つで対応できますがC++だと少しだけ手間が必要になります。

(1) : ThirdPersonCharacterのソースファイルにコードを書きます。
ThirdPersonCharacter.cpp

void AThirdPersonCharacter::SetupInputComponent(class UInputComponent* PlayerInputComponent)
{
   PlayerInputComponent->BindAction("ADS",IE_Pressed, this, &AThirdPersonCharacter::Aim);
   PlayerInputComponent->BindAction("ADS",IE_Released, this, &AThirdPersonCharacter::StopAim);

PlayerInputComponentのBindAction,BindAxis関数(今回使っていませんが皆さんのCharacterClassにあると思うので説明させていただきます。)ですが、
引数はこのようになっています。

void AYourCharacterClassName::SetupInputComponent(class UInputComponent* PlayerInputComponent)
{
   PlayerInputComponent->BindAction(FName ActionName, EInput KeyEvent, AYourCharacterClassName *Object, void (AYourCharacterClassName:: *Func));
   PlayerInputComponent->BindAxis(FName AxisName, AYourCharacterClassName *Object, void (AYourCharacterClassName:: *Func));
}

BindAction :
FName ActionName : Project Settings->
Inputに設定したイベントネームのことです。今回は "ADS"という名前のインプットアクションです。

f:id:ikagamedev:20161211171940p:plain

EInput KeyEvent : 列挙型でKeyEventが6つ定義されています。
IE_Pressed : キーが押された時実行
IE_Released : キーが離された時実行
IE_Repeat : キーが押されている限り実行(ですが、他のキーの割り込みが入ると中断されるそうです。)
IE_DoubleClick : キーがダブルクリックされた時実行
IE_Axis : キーのAxisValueを送る
IE_MAX : すみません、不明です...。


AYourCharacterClassName *Object :
現在、使用しているCharacterClassを参照してあげてください。今回は自分自身なので this です。

void(AYourCharacterClassName:: *Func) :
キーを押したとき,離した時に呼ぶイベントを参照してください。今回はAim,StopAim関数を呼んでいます。


8 : Aim,StopAim関数を実装

ThirdPersonCharacter.cpp

void AThirdPersonCharacter::Aim()
{
   // もしmyMeshがnullならreturn
   if(!myMesh) return;

   // UTPSAnimInstanceのAnimationを定義し、myMeshにアサインされているAnimBPにCast
   UTPSAnimInstance *Animation = 
     Cast<UTPSAnimInstance>(myMesh->GetAnimInstance());

   // もしCastに失敗したらreturn
   if(!Animation) return;
   
   // UTPSAnimInstanceのbIsAimingにtrueを代入
   Animation->bIsAiming = true;
}

void AThirdPersonCharacter::StopAim()
{
   // もしmyMeshがnullならreturn
   if(!myMesh) return;

   // UTPSAnimInstanceのAnimationを定義し、myMeshにアサインされているAnimBPにCast
   UTPSAnimInstance *Animation = 
     Cast<UTPSAnimInstance>(myMesh->GetAnimInstance());

   // もしCastに失敗したらreturn
   if(!Animation) return;
   
   // UTPSAnimInstanceのbIsAimingにfalseを代入
   Animation->bIsAiming = false;
}

Full Code :

ThirdPersonCharacter.h

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.
#pragma once
#include "GameFramework/Character.h"
#include "ThirdPersonCharacter.generated.h"

UCLASS(config=Game)
class AThirdPersonCharacter : public ACharacter
{
   GENERATED_BODY()
        
   UPROPERTY(VisibleAnywhere,BlueprintReadOnly,Category = "SkeletalMesh",meta = (AllowPrivateAccess = "true"))
   class USkeletalMeshComponent* myMesh;

protected:
   void Aim();
   void StopAim();
};


ThirdPersonCharacter.cpp

// Copyright 1998-2016 Epic Games, Inc. All Rights Reserved.

#include "YourProjectName.h"
#include "ThirdPersonCharacter.h"
#include "TPSAnimInstance.h"

AThirdPersonCharacter::AThirdPersonCharacter()
{
   myMesh = GetMesh();
}

//////////////////////////////////////////////////////////////////////////
// Input

void AThirdPersonCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
   // set up gameplay key bindings
   PlayerInputComponent->BindAction("ADS", IE_Pressed, this, &AThirdPersonCharacter::Aim);
   PlayerInputComponent->BindAction("ADS", IE_Released, this, &AThirdPersonCharacter::StopAim);

}

void AThirdPersonCharacter::Aim()
{
   if (!myMesh) return;
   UTPSAnimInstance *Animation =
	Cast<UTPSAnimInstance>(myMesh->GetAnimInstance());

   if (!Animation) return;
   Animation->bIsAiming = true;
}

void AThirdPersonCharacter::StopAim()
{
   if (!myMesh) return;
   UTPSAnimInstance *Animation =
	Cast<UTPSAnimInstance>(myMesh->GetAnimInstance());

   if (!Animation) return;
   Animation->bIsAiming = false;
}

ここまできたらAnimBPに飛びましょう。(コンパイルを忘れずに!)


9 : AnimBPでParentClassを再定義

f:id:ikagamedev:20161211201720p:plain

f:id:ikagamedev:20161211201729p:plain

変更が完了したらBPをコンパイルして下さい。

ちゃんと動作してるかテストしてみましょうか。

f:id:ikagamedev:20161217225035p:plain

画面にtrueと表示されていればOKです。


10 : 実際にプレイヤーにAnimationさせる

・まずはStateMachineを用意します。なお、StateMachineの説明は本題からそれてしまうので、
docs.unrealengine.com

こちらをご覧ください('ω')

f:id:ikagamedev:20161217225707p:plain

・StateEditorに飛んだら新しいStateを用意しましょう。
f:id:ikagamedev:20161217230032p:plain
名前はなんでもいいと思いますが、今回は " idle " という名前のStateと " Aiming " という名前のStateを作ります。


・idle内に " Idle_Rifle_Hip " を追加してあげます。
f:id:ikagamedev:20161217230338p:plain


・お次はAimingStateを追加します。
f:id:ikagamedev:20161217230439p:plain

Aiming内に " Idle_Rifle_Ironsights " を追加します。
f:id:ikagamedev:20161217230609p:plain


・遷移ルールを設定します
"idle" - "Aiming"
f:id:ikagamedev:20161217231547p:plain


"Aiming" - "idle"
f:id:ikagamedev:20161217231633p:plain


ちなみにUPROPERTYのCategoryはこんな感じで活躍できます。(便利!)
f:id:ikagamedev:20161217231915p:plain


・Test!!
f:id:ikagamedev:20161217233133p:plain

Characterがこんな感じでAnimationしていればOKです('ω')

Animation編・・・END!!




[LINETRACE]

おなじみのLineTraceです。
f:id:ikagamedev:20161217233717p:plain


銃の発射処理やikなどにも使われているこの処理をUnrealC++でやってみましょう。

1 : ObjectClassを継承したClassを作る

f:id:ikagamedev:20161220224223p:plain

今回は MyStaticLibrary という名前のClassを作りました。


2 : LineTrace関数を定義する

MyStaticLibrary.h

public:
	/** LineTrace */
	static FORCEINLINE bool Trace(
		UWorld* World,
		AActor* ActorToIgnore,
		const FVector& Start,
		const FVector& End,
		FHitResult& HitOut,
		ECollisionChannel CollisionChannel = ECC_Pawn,
		bool ReturnPhysMat = false)

FORCEINLINEマクロ
コードを強制的にインライン化するものです。(inlineの強いVerかな...?)
inlineについてはこちらを参照。
インライン関数 - Wikipedia


3 : 関数の中身を書いていく

MyStaticLibrary.h

public:
	/** LineTrace */
	static FORCEINLINE bool Trace(
		UWorld* World,
		AActor* ActorToIgnore,
		const FVector& Start,
		const FVector& End,
		FHitResult& HitOut,
		ECollisionChannel CollisionChannel = ECC_Pawn,
		bool ReturnPhysMat = false)
        {

        if (!World)
	{
	    return false;
	}

	FCollisionQueryParams TraceParams(FName(TEXT("VictoreCore Trace")), true, ActorToIgnore);
	TraceParams.bTraceComplex = true;
	//TraceParams.bTraceAsyncScene = true;
	TraceParams.bReturnPhysicalMaterial = ReturnPhysMat;

	//Ignore Actors
	TraceParams.AddIgnoredActor(ActorToIgnore);

	//Re-initialize hit info
	HitOut = FHitResult(ForceInit);

	//Trace!
	World->LineTraceSingleByChannel(
		HitOut,
		Start,
		End,
		CollisionChannel,
		TraceParams
	);
	return (HitOut.GetActor() != NULL);
	}


・FCollisionQueryParams
Collisionの衝突判定に関する情報がいろいろと入っています。
今回の処理で言えばbTraceComplex(trueなら元のmeshのCollisionから衝突判定を取り、falseならmeshに割り当てられているcollisionから衝突判定を取る),
bReturnPhysicalMaterial(PhysicalMatを返すか否か),IgnoreActor(Traceを無視するActorを指定できる)などです。便利...


・FHitResult
おなじみのヒットリザルトです。


4 : コンストラクタの定義

MyStaticLibrary.cpp

UMyStaticLibrary::UMyStaticLibrary(const FObjectInitializer& ObjectInitializer)
  : Super(ObjectInitializer)
{
    //変数の初期化とかしてね!!
}


ではCharacterClassに戻りLineTraceを呼び出す関数を定義し、PlayerInputComponentのBindActionでInputActionをBindしましょう!


5 : CharacterClassにLineTrace関数を定義

※ThirdPersonCharacterを使っていると仮定してのコードです。

ThirdPersonCharacter.h

UCLASS(config=Game)
class AThirdPersonCharacter : public ACharacter
{
   GENERATED_BODY()

protected:
   void LineTrace();

}

他にいろいろ書かれていると思いますが気にしなくて大丈夫です。


6 : InputActionを設定
一度UE4のEditorに戻りInputActionを設定しましょう。
今回は "Fire" という名前のActionをマウスの左ボタンに割り当てました。こんな感じ
f:id:ikagamedev:20161221000741p:plain



7 : cppにMyStaticLibraryをincludeし関数の呼び出し

ThirdPersonCharacter.cpp

#include "MyStaticLibrary.h"

AThirdPersonCharacter::AThirdPersonCharacter()
{

void AThirdPersonCharacter::SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent)
{
   PlayerInputComponent->BindAction("Fire",IE_Pressed, this, &AThirdPersonCharacter::LineTrace);
}

void AThirdPersonCharacter::LineTrace()
{
   ACharacter* myCharacter = UGameplayStatics::GetPlayerCharacter(AActor::GetWorld(),0);
   const FVector Start = myCharacter->GetActorLocation();
   const FVector End = Start + myCharacter->GetActorRotation().Vector() * お好きな距離(5000とか);
   
   FHitResult HidData(ForceInit);

   if(UMyStaticLibrary::Trace(AActor::GetWorld(), myCharacter, Start, End, HitData) && HitData.GetActor())
   {
      //お好きな処理をどぞ!!
   }
}

・おまけ
Traceが当たった時にBlueprintでEventを呼び出すものを "実装" してみましょう。

ThirdPersonCharacter.h

UCLASS(config=Game)
class AThirdPersonCharacter : public ACharacter
{
   GENERATED_BODY()


public:
   UFUNCTION(Category = "Trace", BlueprintImplementableEvent, BlueprintCallable)
   void OnTraceHit(FVector ImpactPoint, AActor* HitActor);


・次に先ほどの //お好きな処理をどぞ! の部分に先ほどの関数を呼び出してあげるだけで....
ThirdPersonCharacter.cpp

{
   HitPoint = HitData.ImpactPoint;
   AActor* HitActor = HitData.GetActor();
   OnTraceHit(HitPoint,HItActor);
}

f:id:ikagamedev:20161221002128p:plain

f:id:ikagamedev:20161221002134p:plain

こんなことが可能に....素晴らしい。


以上で本ブログは終了になります。張り切ってかなり長く、見にくくなってしまい申し訳ありません...。
間違っている箇所がありましたら修正依頼をお願いします早急に直します。

いよいよ明日はクリスマスイブ、ぼっちを決め込む皆さんに demuyan さんの 「 何か裏っぽいネタを書きます 」が癒してくれることを願って終わりとさせていただきます。