초보 코린이의 성장 일지

UE4 SubAction Around Skill 본문

언리얼

UE4 SubAction Around Skill

코오린이 2023. 7. 4. 17:41

이번에는 나이아가라를 사용해 위에서 아래로 떨어지는 스킬을 구현해 볼 것이다.

1. CSubAction을 상속받아 클래스를 생성해준다.

#pragma once

#include "CoreMinimal.h"
#include "Weapons/CSubAction.h"
#include "Weapons/CWeaponStructures.h"
#include "CSubAction_Around.generated.h"

UCLASS(Blueprintable)
class U2212_06_API UCSubAction_Around : public UCSubAction
{
	GENERATED_BODY()

private:
	UPROPERTY(EditDefaultsOnly, Category = "Action")
		FDoActionData ActionData;

public:
	UCSubAction_Around();

public:
	virtual void Pressed() override;

	virtual void Begin_SubAction_Implementation() override;
	virtual void End_SubAction_Implementation() override;

};
#include "Weapons/SubActions/CSubAction_Around.h"
#include "Global.h"
#include "Components/CMovementComponent.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
#include "Weapons/AddOns/CThornObject.h"

UCSubAction_Around::UCSubAction_Around()
{

}

void UCSubAction_Around::Pressed()
{
	Super::Pressed();

	CheckTrue(State->IsSubActionMode());
	State->OnSubActionMode();

	ActionData.DoAction(Owner);

}

void UCSubAction_Around::Begin_SubAction_Implementation()
{
	Super::Begin_SubAction_Implementation();

}

void UCSubAction_Around::End_SubAction_Implementation()
{
	Super::End_SubAction_Implementation();

	State->OffSubActionMode();
	State->SetIdleMode();
	Movement->Move();

}

1. BP에서 사용할 수 있도록 만들어준다.

1. 블루프린트 클래스로 생성해준다.

1. 사용할 몽타주에 노티파이를 설정해준다.

1. 몽타주를 사용하기 위해 설정해준다.

1. SubAction Around를 선택해준다.

1. 실행해보면, 몽타주가 나오는걸 확인해 볼 수 있다.


1. 사용할 나이아가라 스킬과 Hit에 사용할 나이아가라 2개를 준비한다.

1. Smoke는 불필요하므로 제거해준다.

1. 연결되어있는 하나의 이펙트를 제거했기 때문에 오류가 발생할 수 있다.

2. 이 문제를 해결하려면, 오른쪽 상단에 오류 내용을 클릭해보고 만일 부모 이미터에서 해결할 수 있는지 확인해준다.

3. 위 사진처럼 부모 이미터로 갈 수 있는 마크가 나온다면 이건 자식 이펙트라고 생각하면 된다.

1. 부모로 들어오게 되면 이미 경고가 표시되어서 나온다.

1. 위에 경고표시를 한번씩 눌러보게되면 자연스럽게 오류쪽으로 하나씩 내려가게 된다.

1. 내려가다 보면 이슈고침이라는 버튼이 표시되어 있는게 보이게 된다.

1. 이슈고침을 클릭해보면 자동으로 오류가 고처지게 된다.

1. 사용할 스킬이 위에서 아래로 떨어지게끔 만들것인데, 지금 축을 보면 아래가 아닌 정면으로 향하고 있다.

2. 이걸 수정해 주기 위해 Initial Mesh Orientation을 추가해준다.

1. 아래로 방향을 틀어준다.

1. 이제 아래로 떨어지게 하기 위해서 중력에 힘이 필요로하게 되는데, Gravity를 추가해준다.

2. 추가해보면 오류가 하나 발생하게 된다.

3. 힘이나 속도에 의해서 이동하게 되는 값은 다른 이동을 관장하거나 무언가 변화를 줄 수 있는 수치를 가진 기능보다 위에 존재해야 오류를 해결할 수 있다.

1. Velocity 보다 위로 올려주면 오류가 해결된다.

1. 하나만 떨어지게 하는게 아닌 여러개가 낙하하게 만들어 주기 위해 개수를 늘려준다.

1. 왼편에 나이아가라를 보면, 25개를 만들었음에도 하나만 낙하하는걸 보게되는데, 이는 현재 한곳에서 25개가 Spawn되었기 때문이다.

2. Box Location을 추가하여 Random으로 Spawn되서 떨어지도록 만들어 주면 눈으로도 확인할 수 있으며, 이 기능을 사용할 것이다.

1. 값을 빼오기 위해 Export Particle Data to Blueprint 추가해준다.

2. 업데이트할 값이기 때문에 초기가 아닌 Scale로 선택해준다.

1. + 를 눌러서 Object를 추가해준다.

2. 빼서 사용할 Object는 Collision이 된다.

1. 사용할 Mesh Render을 찾아서 크기를 알아와야서 사용해야한다.


1. 이제 나이아가라를 사용하여 스킬을 구현하고, 필요하다면 나이아가라 안에서 특정 값을 가져와서 사용해 보게 될 것이다.

#pragma once

#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "NiagaraDataInterfaceExport.h"
#include "Weapons/CWeaponStructures.h"
#include "CThornObject.generated.h"

UCLASS()
class U2212_06_API ACThornObject
	: public AActor
	, public INiagaraParticleCallbackHandler
{
	GENERATED_BODY()

private:
	UPROPERTY(EditDefaultsOnly, Category = "Hit")
		FHitData HitData;

	UPROPERTY(EditDefaultsOnly, Category = "Niagara")
		class UStaticMesh* NiagaraMesh; // 어떤 나이아가라 사용할지,

	UPROPERTY(EditDefaultsOnly, Category = "Niagara")
		FRotator NiagaraMeshRotation; // 회전값

	UPROPERTY(EditDefaultsOnly, Category = "Collision")
		class UFXSystemAsset* CollisionEffect; // 충돌했을때 이펙트

	UPROPERTY(EditDefaultsOnly, Category = "Collision")
		FTransform CollisionEffectTransform; // 충돌했을때 이펙트 보정 위치값

private:
	UPROPERTY(VisibleDefaultsOnly)
		class USceneComponent* Root;

	UPROPERTY(VisibleDefaultsOnly)
		class UNiagaraComponent* Niagara;

public:	
	ACThornObject();

protected:
	virtual void BeginPlay() override;

public:
	// 핸들러
	void ReceiveParticleData_Implementation(const TArray<FBasicParticleData>& Data, UNiagaraSystem* NiagaraSystem);

private:
	UFUNCTION()
	// Finish 됐을때 Box 계산할 곳
		void OnSystemFinished(class UNiagaraComponent* PSystem);

private:
	FVector BoxExtent;

};
#include "Weapons/AddOns/CThornObject.h"
#include "Global.h"
#include "NiagaraComponent.h"
#include "GameFramework/Character.h"

ACThornObject::ACThornObject()
{
	// 생성
	CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
	CHelpers::CreateComponent<UNiagaraComponent>(this, &Niagara, "Niagara", Root);
}

void ACThornObject::BeginPlay()
{
	Super::BeginPlay();

	Niagara->SetNiagaraVariableObject("Collision", this); // 나이아가라에서 빼오게 될 오브젝트 이름 : Collision
	Niagara->OnSystemFinished.AddDynamic(this, &ACThornObject::OnSystemFinished);

	if (!!NiagaraMesh)
	{
		FBox box = NiagaraMesh->GetBoundingBox(); // 바운딩 box 크기, 충돌체 사이즈
		BoxExtent = (box.Min - box.Max).GetAbs() * 0.5f; // 부피로 구해서 사용하기

	}
}

void ACThornObject::ReceiveParticleData_Implementation(const TArray<FBasicParticleData>& Data, UNiagaraSystem* NiagaraSystem)
{
	CheckFalse(Data.Num() > 0);

	static TArray<AActor*> ignores; // 반복되고 자주사용되는건 static 사용하면 스택오버플로우 방지.
	ignores.AddUnique(GetOwner());

	static FHitResult hitResult;
	// Num - 1을 해주는 이유, 개수가 중간에 먼저 삭제되면 배열이 땡겨질 수 있으므로, 거꾸로 돌린다.
	for (int32 i = Data.Num() - 1; i >= 0; i--)
	{
		FVector position = Data[i].Position + GetActorLocation(); // 위치 가져오기.
		FVector scale = Data[i].Velocity * BoxExtent; // Velocity 변해가는 크기 *  원본 크기

		UKismetSystemLibrary::BoxTraceSingleByProfile(GetWorld(), position, position, scale, NiagaraMeshRotation, "Pawn", false, ignores, EDrawDebugTrace::ForOneFrame, hitResult, true);

	}
	
}

void ACThornObject::OnSystemFinished(UNiagaraComponent* PSystem)
{
	Destroy(); // 끝났으면 제거.

}

1. Box 그려서 스킬이 잘 낙하하는지 확인해 볼 수 있도록 설정.


#pragma once

#include "CoreMinimal.h"
#include "Weapons/CSubAction.h"
#include "Weapons/CWeaponStructures.h"
#include "CSubAction_Around.generated.h"

UCLASS(Blueprintable)
class U2212_06_API UCSubAction_Around : public UCSubAction
{
	GENERATED_BODY()

private:
	UPROPERTY(EditDefaultsOnly, Category = "FallObject")
		TSubclassOf<class ACThornObject> ObjectClass;

	UPROPERTY(EditDefaultsOnly, Category = "FallObject")
		FVector ObjectLocation; // Spawn시킬 위치

public:
	virtual void Begin_SubAction_Implementation() override;
	virtual void End_SubAction_Implementation() override;

};
#include "Weapons/SubActions/CSubAction_Around.h"
#include "Global.h"
#include "Components/CMovementComponent.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
#include "Weapons/AddOns/CThornObject.h"

void UCSubAction_Around::Begin_SubAction_Implementation()
{
	Super::Begin_SubAction_Implementation();

	FActorSpawnParameters params;
	params.Owner = Owner;
	params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;

	FTransform transform;

	FVector ownerLocation = Owner->GetActorLocation();
	ownerLocation += Owner->GetActorRotation().RotateVector(ObjectLocation); // 전방 방향으로부터 회전시켜서 Spawn해주기 위해.

	transform.SetLocation(ownerLocation);

	Owner->GetWorld()->SpawnActor<ACThornObject>(ObjectClass, transform, params);
}

1. Spawn 해주기 위한 회전방향 설정.


1 .블루프린트 클래스를 생성해준다.

 

 

1. 사용할 Niagara Mesh 설정 및 회전 시켜주기, Hit Effect 설정.

2. Niagara도 선택.

1. Object Class 선택해준다.

1. 실행해보면 Box Trace로 확인할 수 있게된다.


#include "Weapons/AddOns/CThornObject.h"
#include "Global.h"
#include "NiagaraComponent.h"
#include "GameFramework/Character.h"

void ACThornObject::ReceiveParticleData_Implementation(const TArray<FBasicParticleData>& Data, UNiagaraSystem* NiagaraSystem)
{
	CheckFalse(Data.Num() > 0);

	static TArray<AActor*> ignores; // 반복되고 자주사용되는건 static 사용하면 스택오버플로우 방지.
	ignores.AddUnique(GetOwner());

	static FHitResult hitResult;
	// Num - 1을 해주는 이유, 개수가 중간에 먼저 삭제되면 배열이 땡겨질 수 있으므로, 거꾸로 돌린다.
	for (int32 i = Data.Num() - 1; i >= 0; i--)
	{
		FVector position = Data[i].Position + GetActorLocation(); // 위치 가져오기.
		FVector scale = Data[i].Velocity * BoxExtent; // Velocity 변해가는 크기 *  원본 크기

		UKismetSystemLibrary::BoxTraceSingleByProfile(GetWorld(), position, position, scale, NiagaraMeshRotation, "Pawn", false, ignores, EDrawDebugTrace::ForOneFrame, hitResult, true);
		if (hitResult.bBlockingHit)
		{
			if (!!CollisionEffect)
			{
				// 이펙트 Player
				FTransform transform = CollisionEffectTransform;
				transform.AddToTranslation(hitResult.Location);

				CHelpers::PlayEffect(GetWorld(), CollisionEffect, transform);
			}

			// Hit된 객체가 Character라면 데미지 주기.
			ACharacter* character = Cast<ACharacter>(hitResult.GetActor());
			if (!!character)
				HitData.SendDamage(Cast<ACharacter>(GetOwner()), this, character);

		}
	}
	
}

1. 이펙트를 나오도록 실행시키고, Character인 유형과 충돌한다면 데미지를 전달해주게끔 설정.


https://www.youtube.com/watch?v=3BPusFLxP6E 

 

'언리얼' 카테고리의 다른 글

UE4 Bow Aim  (0) 2023.07.06
UE4 Weapon Bow  (0) 2023.07.05
UE4 SubAction Around Skill  (0) 2023.07.03
UE4 SubAction Warp, Top View  (0) 2023.06.30
UE4 SubAction Warp  (0) 2023.06.29
Comments