Unreal Engine C++ Developer: Learn C++ and Make Video Games | Udemy UE4.25 Simple Shooterで自分なりに理解したこと。00600 ~Actorにダメージを与える~

今回はアクターにダメージを与えるので
UE4/Engine/Source/Runtime/Engine/Classes/GameFramwork/Actor.h

が持っているTakeDamageを使う

/ **
*このアクターにダメージを与えます。
* @see https://www.unrealengine.com/blog/damage-in-ue4
* @paramDamageAmount適用するダメージの量
* @paramDamageEvent受けたダメージを完全に説明するデータパッケージ。
* @paramEventInstigator損傷の原因となったコントローラー。
* @param DamageCauserダメージを直接引き起こしたアクター(爆発した発射物、着地した岩など)
* @ return実際に適用されたダメージの量。
* /
/**
	 * Apply damage to this actor.
	 * @see https://www.unrealengine.com/blog/damage-in-ue4
	 * @param DamageAmount		How much damage to apply
	 * @param DamageEvent		Data package that fully describes the damage received.
	 * @param EventInstigator	The Controller responsible for the damage.
	 * @param DamageCauser		The Actor that directly caused the damage (e.g. the projectile that exploded, the rock that landed on you)
	 * @return					The amount of damage actually applied.
	 */
	virtual float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser);

で引数にあるDamageEventはたくさん種類あるみたい。

今回は銃なのでFPointDamageEventを使った。

FPointDamageEvent DamageEvent(Damage,Hit,ShotDirection,nullptr);

でアクターにヒットしたときTakeDamageを呼ぶというのはこうなる。

		AActor* HitActor= Hit.GetActor();
		if (HitActor!=nullptr)
		{
			FPointDamageEvent DamageEvent(Damage,Hit,ShotDirection,nullptr);
			HitActor->TakeDamage(Damage,DamageEvent,OwnerController,this);
		}

絵的にはなにもかわりません。

Unreal Engine C++ Developer: Learn C++ and Make Video Games | Udemy UE4.25 Simple Shooterで自分なりに理解したこと。00500 ~ヒットした場所にパーティクル~

UE4/Engine/Source/Runtime/Engine/Classes/Kismet/GameplayStatics.h

static UParticleSystemComponent* SpawnEmitterAtLocation(const UObject* WorldContextObject, UParticleSystem* EmitterTemplate, FVector Location, FRotator Rotation = FRotator::ZeroRotator, FVector Scale = FVector(1.f), bool bAutoDestroy = true, EPSCPoolMethod PoolingMethod = EPSCPoolMethod::None, bool bAutoActivateSystem = true);

デフォルト引数あるやつ消すとこう

static UParticleSystemComponent* SpawnEmitterAtLocation(const UObject* WorldContextObject, UParticleSystem* EmitterTemplate, FVector Location);

をつかった

Gun.hに これを追加して

	UPROPERTY(EditAnyWhere)
	UParticleSystem* ImpactEffect;

Gun.cppに実際にはShotDirection でショット方向をコントロールしてる

FVector ShotDirection = -Rotation.Vector();
UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ImpactEffect, Hit.Location,ShotDirection.Rotation() );

	if(bSuccess==true)
	{
		UE_LOG(LogTemp,Warning,TEXT("HitWall!! "));
		DrawDebugPoint(GetWorld(), Hit.Location,40.0 ,FColor::Red , bPersistentLines2);
		FVector ShotDirection = -Rotation.Vector();
		UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ImpactEffect, Hit.Location,ShotDirection.Rotation() );

	}

で作ったプロパティ、ImpactEffectに設定

今回の状態 全文
Gun.h

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Gun.generated.h"

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

	void PullTrigger();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;
private:
	UPROPERTY(VisibleAnyWhere)
	USceneComponent* Root;

	UPROPERTY(VisibleAnyWhere)
	USkeletalMeshComponent* Mesh;

	UPROPERTY(EditAnyWhere)
	UParticleSystem* MuzzleFlash;

	UPROPERTY(EditAnyWhere)
	UParticleSystem* ImpactEffect;

	UPROPERTY(EditAnyWhere)
	float MaxRange = 1000;
};

Gun.cpp

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


#include "Gun.h"

#include "Components/SkeletalMeshComponent.h"
#include "Kismet/GameplayStatics.h"
#include "DrawDebugHelpers.h"
// Sets default values
AGun::AGun()
{
 	// 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;

	Root = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
	SetRootComponent(Root);

	Mesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Mesh"));
	Mesh->SetupAttachment(Root);


}
void AGun::PullTrigger()
{
	UE_LOG(LogTemp,Warning,TEXT("You have been shot!! "));
	//MuzzleFlashSocket
	UGameplayStatics::SpawnEmitterAttached(MuzzleFlash, Mesh, TEXT("MuzzleFlashSocket"));
    
	APawn* OwnerPawn = Cast<APawn>(GetOwner());
	if(OwnerPawn==nullptr)
	{
		return;
	}
	AController* OwnerController= OwnerPawn ->GetController();
	if(OwnerController==nullptr)
	{
		return;
	}
	FVector Location= OwnerPawn->GetActorLocation();
	FRotator Rotation;
	OwnerController->GetPlayerViewPoint(  Location, Rotation );
	FVector End = Location + Rotation.Vector() * MaxRange;
	// TOTO: LineTrace

	float FOVDeg=90;
	float Scale=2.f;
	FColor const& Color=FColor::Blue;
	bool bPersistentLines=true;
	float LifeTime=-1.f;
	uint8 DepthPriority = 0;
	//DrawDebugCamera(GetWorld(), Location, Rotation, FOVDeg, Scale, Color, bPersistentLines, LifeTime, DepthPriority);

	float Size2 = 20.0;
	FColor const& Color2= FColor::Green;
	bool bPersistentLines2 = true;
	float LifeTime2 = -1.f;
	uint8 DepthPriority2 = 0;
	//DrawDebugPoint(GetWorld(), Location,Size2 ,Color2 , bPersistentLines2, LifeTime2, DepthPriority2);
	//DrawDebugPoint(GetWorld(), Location,Size2 ,Color2 , bPersistentLines2);
    //DrawDebugDirectionalArrow(GetWorld(), Location, End, 3.0, FColor::Blue, bPersistentLines);

	FHitResult Hit;
	ECollisionChannel TraceChannel = ECollisionChannel::ECC_GameTraceChannel1;
	bool bSuccess = GetWorld()->LineTraceSingleByChannel(Hit,Location,End,TraceChannel);
	if(bSuccess==true)
	{
		UE_LOG(LogTemp,Warning,TEXT("HitWall!! "));
		//DrawDebugPoint(GetWorld(), Hit.Location,40.0 ,FColor::Red , bPersistentLines2);
		FVector ShotDirection = -Rotation.Vector();
		UGameplayStatics::SpawnEmitterAtLocation(GetWorld(), ImpactEffect, Hit.Location,ShotDirection.Rotation() );

	}
	//DrawDebugPoint(GetWorld(), End,Size2 ,FColor::Red , bPersistentLines2);
}

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

// Called every frame
void AGun::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}

でできたのがこれ

Unreal Engine C++ Developer: Learn C++ and Make Video Games | Udemy UE4.25 Simple Shooterで自分なりに理解したこと。00400 ~チャネルによるライントレース~

world.h>LineTraceTestと検索

LineTraceTestByChannel

/ **
*特定のチャネルを使用して世界に対して光線をトレースし、ブロッキングヒットが見つかった場合に戻ります。
* @paramStart光線の開始位置
* @paramEnd光線の終了位置
* @paramTraceChannelこの光線が含まれる「チャネル」。ヒットするコンポーネントを決定するために使用されます。
* @paramParamsトレースに使用される追加のパラメーター
*このトレースに使用される@paramResponseParam ResponseContainer
* @ returnブロッキングヒットが見つかった場合はTRUE
* /	

// LINE TRACE

	/**
	 *  Trace a ray against the world using a specific channel and return if a blocking hit is found.
	 *  @param  Start           Start location of the ray
	 *  @param  End             End location of the ray
	 *  @param  TraceChannel    The 'channel' that this ray is in, used to determine which components to hit
	 *  @param  Params          Additional parameters used for the trace
	 * 	@param 	ResponseParam	ResponseContainer to be used for this trace
	 *  @return TRUE if a blocking hit is found
	 */
	bool LineTraceTestByChannel(const FVector& Start,const FVector& End,ECollisionChannel TraceChannel, const FCollisionQueryParams& Params = FCollisionQueryParams::DefaultQueryParam, const FCollisionResponseParams& ResponseParam = FCollisionResponseParams::DefaultResponseParam) const;
	

LineTraceSingleByChannel

/ **
*特定のチャネルを使用して世界に対して光線をトレースし、最初のブロッキングヒットを返します
* @paramOutHit最初のブロッキングヒットが見つかりました
* @paramStart光線の開始位置
* @paramEnd光線の終了位置
* @paramTraceChannelこの光線が含まれる「チャネル」。ヒットするコンポーネントを決定するために使用されます。
* @paramParamsトレースに使用される追加のパラメーター
*このトレースに使用される@paramResponseParam ResponseContainer
* @ returnブロッキングヒットが見つかった場合はTRUE
* /	

/**
	 *  Trace a ray against the world using a specific channel and return the first blocking hit
	 *  @param  OutHit          First blocking hit found
	 *  @param  Start           Start location of the ray
	 *  @param  End             End location of the ray
	 *  @param  TraceChannel    The 'channel' that this ray is in, used to determine which components to hit
	 *  @param  Params          Additional parameters used for the trace
	 * 	@param 	ResponseParam	ResponseContainer to be used for this trace	 
	 *  @return TRUE if a blocking hit is found
	 */
	bool LineTraceSingleByChannel(struct FHitResult& OutHit,const FVector& Start,const FVector& End,ECollisionChannel TraceChannel,const FCollisionQueryParams& Params = FCollisionQueryParams::DefaultQueryParam, const FCollisionResponseParams& ResponseParam = FCollisionResponseParams::DefaultResponseParam) const;

TraceChannelの設定はこう

LineTraceSingleByChannelの引数にはECollisionChannel がある

LineTraceSingleByChannel(struct FHitResult& OutHit,const FVector& Start,const FVector& End,ECollisionChannel TraceChannel,const FCollisionQueryParams& Params = FCollisionQueryParams::DefaultQueryParam, const FCollisionResponseParams& ResponseParam = FCollisionResponseParams::DefaultResponseParam) const;

ECollisionChannel の定義を開く

Config/DefaultEngine.ini ひらくとさっき設定したものがデータになってる

+EditProfiles=(Name="NoCollision",CustomResponses=((Channel="Bullet",Response=ECR_Ignore)))
+EditProfiles=(Name="OverlapAll",CustomResponses=((Channel="Bullet",Response=ECR_Ignore)))
+EditProfiles=(Name="InvisibleWall",CustomResponses=((Channel="Bullet",Response=ECR_Ignore)))
+EditProfiles=(Name="InvisibleWallDynamic",CustomResponses=((Channel="Bullet",Response=ECR_Ignore)))

Gun.hに

	UPROPERTY(EditAnyWhere)
	float MaxRange = 1000;

Gun.cppに戻る

UE4/Engine/Sounce/Runtime/Engine/Public/DrawDebugHelpers.h

DrawDebugPointを使う

	FVector End = Location + Rotation.Vector() * MaxRange;
	// TOTO: LineTrace
  / **デバッグポイントを描画します* /
  /** Draw a debug point */
	float Size=20.0;
	FColor PointColor::Red;
	bool bPersistentLines = true;
	float LifeTime = -1.f;
	uint8 DepthPriority = 0;
	DrawDebugPoint(GetWorld(), Location,Size ,Color , bPersistentLines, LifeTime, DepthPriority)
	

なんか右にでる

LineTraceSingleByChannelを使う

UE4/Engine/Source/Runtime/Engine/Classes/Engine/world.hにある

/ **
*特定のチャネルを使用して世界に対して光線をトレースし、最初のブロッキングヒットを返します
* @paramOutHit最初のブロッキングヒットが見つかりました
* @paramStart光線の開始位置
* @paramEnd光線の終了位置
* @paramTraceChannelこの光線が含まれる「チャネル」。ヒットするコンポーネントを決定するために使用されます。
* @paramParamsトレースに使用される追加のパラメーター
*このトレースに使用される@paramResponseParam ResponseContainer
* @ returnブロッキングヒットが見つかった場合はTRUE
* /	
/**
	 *  Trace a ray against the world using a specific channel and return the first blocking hit
	 *  @param  OutHit          First blocking hit found
	 *  @param  Start           Start location of the ray
	 *  @param  End             End location of the ray
	 *  @param  TraceChannel    The 'channel' that this ray is in, used to determine which components to hit
	 *  @param  Params          Additional parameters used for the trace
	 * 	@param 	ResponseParam	ResponseContainer to be used for this trace	 
	 *  @return TRUE if a blocking hit is found
	 */
	bool LineTraceSingleByChannel(struct FHitResult& OutHit,const FVector& Start,const FVector& End,ECollisionChannel TraceChannel,const FCollisionQueryParams& Params = FCollisionQueryParams::DefaultQueryParam, const FCollisionResponseParams& ResponseParam = FCollisionResponseParams::DefaultResponseParam) const;

Gun.hはこんなんで

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

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Gun.generated.h"

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

	void PullTrigger();

protected:
	// Called when the game starts or when spawned
	virtual void BeginPlay() override;

public:	
	// Called every frame
	virtual void Tick(float DeltaTime) override;
private:
	UPROPERTY(VisibleAnyWhere)
	USceneComponent* Root;

	UPROPERTY(VisibleAnyWhere)
	USkeletalMeshComponent* Mesh;

	UPROPERTY(EditAnyWhere)
	UParticleSystem* MuzzleFlash;

	UPROPERTY(EditAnyWhere)
	float MaxRange = 1000;
};

Gun.cppはこんな感じになった

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


#include "Gun.h"

#include "Components/SkeletalMeshComponent.h"
#include "Kismet/GameplayStatics.h"
#include "DrawDebugHelpers.h"
// Sets default values
AGun::AGun()
{
 	// 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;

	Root = CreateDefaultSubobject<USceneComponent>(TEXT("Root"));
	SetRootComponent(Root);

	Mesh = CreateDefaultSubobject<USkeletalMeshComponent>(TEXT("Mesh"));
	Mesh->SetupAttachment(Root);


}
void AGun::PullTrigger()
{
	UE_LOG(LogTemp,Warning,TEXT("You have been shot!! "));
	//MuzzleFlashSocket
	UGameplayStatics::SpawnEmitterAttached(MuzzleFlash, Mesh, TEXT("MuzzleFlashSocket"));
    
	APawn* OwnerPawn = Cast<APawn>(GetOwner());
	if(OwnerPawn==nullptr)
	{
		return;
	}
	AController* OwnerController= OwnerPawn ->GetController();
	if(OwnerController==nullptr)
	{
		return;
	}
	FVector Location= OwnerPawn->GetActorLocation();
	FRotator Rotation;
	OwnerController->GetPlayerViewPoint(  Location, Rotation );
	FVector End = Location + Rotation.Vector() * MaxRange;
	// TOTO: LineTrace

	float FOVDeg=90;
	float Scale=2.f;
	FColor const& Color=FColor::Blue;
	bool bPersistentLines=true;
	float LifeTime=-1.f;
	uint8 DepthPriority = 0;
	DrawDebugCamera(GetWorld(), Location, Rotation, FOVDeg, Scale, Color, bPersistentLines, LifeTime, DepthPriority);

	float Size2 = 20.0;
	FColor const& Color2= FColor::Green;
	bool bPersistentLines2 = true;
	float LifeTime2 = -1.f;
	uint8 DepthPriority2 = 0;
	//DrawDebugPoint(GetWorld(), Location,Size2 ,Color2 , bPersistentLines2, LifeTime2, DepthPriority2);
	DrawDebugPoint(GetWorld(), Location,Size2 ,Color2 , bPersistentLines2);
    DrawDebugDirectionalArrow(GetWorld(), Location, End, 3.0, FColor::Blue, bPersistentLines);

	FHitResult Hit;
	ECollisionChannel TraceChannel = ECollisionChannel::ECC_GameTraceChannel1;
	bool bSuuccess = GetWorld()->LineTraceSingleByChannel(Hit,Location,End,TraceChannel);
	if(bSuuccess==true)
	{
		UE_LOG(LogTemp,Warning,TEXT("HitWall!! "));
		DrawDebugPoint(GetWorld(), Hit.Location,40.0 ,FColor::Red , bPersistentLines2);
	}
	DrawDebugPoint(GetWorld(), End,Size2 ,FColor::Red , bPersistentLines2);
}

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

// Called every frame
void AGun::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

}