초보 코린이의 성장 일지

UE4 SubAction Sword Skill Collision, Hammer Init 본문

언리얼

UE4 SubAction Sword Skill Collision, Hammer Init

코오린이 2023. 6. 26. 15:29

Sword Skill이 Target과 충돌할때, 충돌시 멈추는게 아닌 통과하게끔 충돌 옵션을 변경할 것이다.

1.  Pawn을 겹침으로 변경해주고 나머지는 블록처리를 해준다.

2. 겹침으로해야 통과가 가능하기 때문.

 

#include "Weapons/SubActions/CSubAction_Sword.h"
#include "Global.h"
#include "Weapons/CAttachment.h"
#include "Weapons/CDoAction.h"
#include "GameFramework/Character.h"
#include "Components/CapsuleComponent.h"
#include "Components/CStateComponent.h"
#include "Components/CMovementComponent.h"
#include "Components/CapsuleComponent.h"
#include "Weapons/AddOns/CGhostTrail.h"

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

	Attachment->OnAttachmentBeginOverlap.Remove(DoAction, "OnAttachmentBeginOverlap");
	Attachment->OnAttachmentBeginOverlap.AddDynamic(this, &UCSubAction_Sword::OnAttachmentBeginOverlap);

	bMoving = true;

	Start = Owner->GetActorLocation();
	End = Start + Owner->GetActorForwardVector() * Distance; // 이동할 거리

	float radius = Owner->GetCapsuleComponent()->GetScaledCapsuleRadius();
	float height = Owner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
	FRotator rotation = Owner->GetActorRotation();

	TArray<AActor*> ignores;
	ignores.Add(Owner); // 무시할 객체

	FHitResult lineHitResult;
	UKismetSystemLibrary::LineTraceSingle(Owner->GetWorld(), Start, End, ETraceTypeQuery::TraceTypeQuery1, false, ignores, DrawDebug, lineHitResult, true);

	// 하나라도 충돌되었다면,
	if (lineHitResult.bBlockingHit)
	{
		FVector direction = (End - Start).GetSafeNormal2D();
		End = lineHitResult.Location - (direction * radius * 2); // End 위치 재조정, 거리를 벌려준다.

		if (DrawDebug == EDrawDebugTrace::ForDuration) // 잘 보이도록 테스트로 확인.
			DrawDebugSphere(Owner->GetWorld(), End, radius * 2, 20, FColor::Magenta, true, 2);	
	}

	// 나가는 방향 Draw로 확인
	if (DrawDebug == EDrawDebugTrace::ForDuration)
		DrawDebugDirectionalArrow(Owner->GetWorld(), Start, End, 25, FColor::Green, true, 5, 0, 3);
}

1. 스킬을 사용하여 벽에 닿을때 급격히 가깝게 닿거나 오류가 발생하는걸 먼저 잡고 넘어갈 것이다.

2. End 지점을 기점으로 거리를 벌려 지점을 다시 설정해준다.

 

#pragma once

#include "CoreMinimal.h"
#include "Weapons/CSubAction.h"
#include "Weapons/CWeaponStructures.h"
#include "Kismet/KismetSystemLibrary.h"
#include "CSubAction_Sword.generated.h"

UCLASS(Blueprintable) // BP화 시켜주기.
class U2212_06_API UCSubAction_Sword : public UCSubAction
{
	GENERATED_BODY()

private:
    UPROPERTY(EditDefaultsOnly, Category = "Trace")
        float Distance = 1000;

    UPROPERTY(EditDefaultsOnly, Category = "Trace")
        float Speed = 200;

    UPROPERTY(EditDefaultsOnly, Category = "Trace")
        TEnumAsByte<EDrawDebugTrace::Type> DrawDebug; // 디버그 확인용

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

    UPROPERTY(EditDefaultsOnly, Category = "Action")
        FHitData HitData;

private:
    UPROPERTY(EditAnywhere, Category = "Add-On")
        TSubclassOf<class ACGhostTrail> GhostTrailClass;

public:
    void Pressed() override;
    void Begin_SubAction_Implementation() override;
    void End_SubAction_Implementation() override;
    void Tick_Implementation(float InDeltaTime) override;

private:
    // 충돌처리 함수.
    UFUNCTION()
        void OnAttachmentBeginOverlap(class ACharacter* InAttacker, AActor* InAttackCuaser, class ACharacter* InOther);

private:
    bool bMoving;

    FVector Start; // 시작지점
    FVector End; // 끝지점

    TArray<class ACharacter*> Overlapped; // 프로파일 복구 변수
    TArray<class ACharacter*> Hitted;

private:
    class ACGhostTrail* GhostTrail;

};
#include "Weapons/SubActions/CSubAction_Sword.h"
#include "Global.h"
#include "Weapons/CAttachment.h"
#include "Weapons/CDoAction.h"
#include "GameFramework/Character.h"
#include "Components/CapsuleComponent.h"
#include "Components/CStateComponent.h"
#include "Components/CMovementComponent.h"
#include "Components/CapsuleComponent.h"
#include "Weapons/AddOns/CGhostTrail.h"

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

	CheckFalse(State->IsIdleMode());
	CheckTrue(State->IsSubActionMode());

	State->SetActionMode();
	State->OnSubActionMode();

	GhostTrail = CHelpers::Play_GhostTrail(GhostTrailClass, Owner);

	ActionData.DoAction(Owner);

}

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

	Attachment->OnAttachmentBeginOverlap.Remove(DoAction, "OnAttachmentBeginOverlap");
	Attachment->OnAttachmentBeginOverlap.AddDynamic(this, &UCSubAction_Sword::OnAttachmentBeginOverlap);

	bMoving = true;

	Start = Owner->GetActorLocation();
	End = Start + Owner->GetActorForwardVector() * Distance; // 이동할 거리

	float radius = Owner->GetCapsuleComponent()->GetScaledCapsuleRadius();
	float height = Owner->GetCapsuleComponent()->GetScaledCapsuleHalfHeight();
	FRotator rotation = Owner->GetActorRotation();

	TArray<AActor*> ignores;
	ignores.Add(Owner); // 무시할 객체

	TArray<FHitResult> hitResults; // 여러개 체크하게끔 배열로 선언.
	TArray<TEnumAsByte<EObjectTypeQuery>> objects;
	objects.Add(EObjectTypeQuery::ObjectTypeQuery3); // 프로파일 Pawn에 위치가 3번이다.

	// 지점, X,Y축, 회전방향, 추적타입, 복합충돌 등등
	UKismetSystemLibrary::BoxTraceMultiForObjects(Owner->GetWorld(), Start, End, FVector(0, radius, height), rotation, objects, false, ignores, DrawDebug, hitResults, true);

	for (const FHitResult& hitResult : hitResults)
	{
		ACharacter* character = Cast<ACharacter>(hitResult.GetActor());

		if (!!character)
		{
			// Profile을 만들어 준 걸로 교체
			character->GetCapsuleComponent()->SetCollisionProfileName("Sword_SubAction");

			Overlapped.Add(character); // 복구하기 위해 저장.
		}
	}

	FHitResult lineHitResult;
	UKismetSystemLibrary::LineTraceSingle(Owner->GetWorld(), Start, End, ETraceTypeQuery::TraceTypeQuery1, false, ignores, DrawDebug, lineHitResult, true);

	// 하나라도 충돌되었다면,
	if (lineHitResult.bBlockingHit)
	{
		FVector direction = (End - Start).GetSafeNormal2D();
		End = lineHitResult.Location - (direction * radius * 2); // End 위치 재조정, 거리를 벌려준다.

		if (DrawDebug == EDrawDebugTrace::ForDuration) // 잘 보이도록 테스트로 확인.
			DrawDebugSphere(Owner->GetWorld(), End, radius * 2, 20, FColor::Magenta, true, 2);	
	}

	// 나가는 방향 Draw로 확인
	if (DrawDebug == EDrawDebugTrace::ForDuration)
		DrawDebugDirectionalArrow(Owner->GetWorld(), Start, End, 25, FColor::Green, true, 5, 0, 3);
}

void UCSubAction_Sword::End_SubAction_Implementation()
{
	// 액션 끝나면 다 돌려주기.
	Super::End_SubAction_Implementation();

	Attachment->OnAttachmentBeginOverlap.Remove(this, "OnAttachmentBeginOverlap");
	Attachment->OnAttachmentBeginOverlap.AddDynamic(DoAction, &UCDoAction::OnAttachmentBeginOverlap);

	bMoving = false;

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

	// 원래에 Profile로 복구.
	for (ACharacter* character : Overlapped)
		character->GetCapsuleComponent()->SetCollisionProfileName("Pawn");

	// 다시 충돌이 있게끔 지워준다. 
	Overlapped.Empty();
	Hitted.Empty();

	if (!!GhostTrail)
		GhostTrail->Destroy();
	
}

void UCSubAction_Sword::Tick_Implementation(float InDeltaTime)
{
	Super::Tick_Implementation(InDeltaTime);
	CheckFalse(bMoving); // 무빙이 false면 실행 x

	// 이동 후 멈춰야할 지점 정하기.
	FVector location = Owner->GetActorLocation();
	float radius = Owner->GetCapsuleComponent()->GetScaledCapsuleRadius(); // Capsule 절반만큼 멈추게 설정,

	// 뒤에 오차값 매개변수를 radius로 설정 (오차값만큼 들어오면 같은 값으로 간주하라는 의미)
	if (location.Equals(End, radius)) 
	{
		bMoving = false;
		Start = End = Owner->GetActorLocation(); // 최종위치로 다시 잡아준다. 초기화도 하는겸

		return;
	}

	// 방향, 속도만큼 이동, AddActorWorldOffset를 들어가서 보면 현재 속도에서 계속 값을 더 해가는 역할을 수행한다.
	FVector direction = (End - Start).GetSafeNormal2D();
	Owner->AddActorWorldOffset(direction * Speed, true);

}

void UCSubAction_Sword::OnAttachmentBeginOverlap(ACharacter* InAttacker, AActor* InAttackCuaser, ACharacter* InOther)
{
	CheckNull(InOther);

	// Hit 중복 충돌 제거
	for (ACharacter* character : Hitted)
		CheckTrue(character == InOther);

	Hitted.AddUnique(InOther);

	HitData.SendDamage(Owner, InAttackCuaser, InOther);
}

1. 우선 등록한 프로파일을 찾는다.

2. 충돌시 프로파일을 교체해주고, 끝이나면 다시 돌려준다.

3. Hit 중복 충돌을 제거해준다.


1. Draw로 확인할 수 있으며, 충돌처리까지 되는걸 확인할 수 있다.


이제 Hammer 스킬을 만들 것이며. 기본적인 세팅을해 놓을 것이다.

1. Ghost를 사용할 것이므로, Fist를 복사해서 Hammer로 변경한다.

1. 만들어 놓은 SubAction을 상속받아 클래스를 생성해준다.

#pragma once

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

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

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

	UPROPERTY(EditDefaultsOnly, Category = "Add-On")
		TSubclassOf<class ACGhostTrail> GhostTrailClass;

public:
	void Pressed() override;

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

private:
	class ACGhostTrail* GhostTrail;

};
#include "Weapons/SubActions/CSubAction_Hammer.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
#include "Components/CMovementComponent.h"
#include "Weapons/CAttachment.h"
#include "Weapons/CDoAction.h"
#include "Weapons/AddOns/CGhostTrail.h"

void UCSubAction_Hammer::Pressed()
{
	CheckFalse(State->IsIdleMode());
	CheckTrue(State->IsSubActionMode());

	Super::Pressed();


	State->SetActionMode();
	State->OnSubActionMode();

	GhostTrail = CHelpers::Play_GhostTrail(GhostTrailClass, Owner);

	ActionData.DoAction(Owner);

}

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

}

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

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

	Movement->Move();
	Movement->DisableFixedCamera();

	if (!!GhostTrail)
		GhostTrail->Destroy();
}

1. State 체크와 사용할 Ghost만 넣어준다.


https://www.youtube.com/watch?v=8CinFWotFKw 

 

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

UE4 SubAction Warp  (0) 2023.06.29
UE4 SubAction Hammer Skill  (0) 2023.06.27
UE4 SubAction Fist, Sword Skill  (0) 2023.06.23
UE4 SubAction Fist, Ghost Trail  (0) 2023.06.22
UE4 SubAction Fist, Camera Move  (0) 2023.06.21
Comments