초보 코린이의 성장 일지

UE4 SubAction Around Skill 본문

언리얼

UE4 SubAction Around Skill

코오린이 2023. 7. 3. 11:42

플레이어 주변을 회전하는 스킬을 만들어 볼 것이다.

1. 먼저 DataAsset를 생성해준다.

2. Attach은 사용하지 않을 것이다.


1. Action을 할 수 있도록 DoAction을 상속받아 생성해준다.

#pragma once

#include "CoreMinimal.h"
#include "Weapons/CDoAction.h"
#include "CDoAction_Around.generated.h"

UCLASS(Blueprintable)
class U2212_06_API UCDoAction_Around : public UCDoAction
{
	GENERATED_BODY()

public:
	void DoAction() override;
	void Begin_DoAction() override;


};
#include "Weapons/DoActions/CDoAction_Around.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"

void UCDoAction_Around::DoAction()
{
	// 체크
	CheckFalse(DoActionDatas.Num() > 0);
	CheckFalse(State->IsIdleMode());

	Super::DoAction();

	// 데이터 받기.
	DoActionDatas[0].DoAction(OwnerCharacter);

}

void UCDoAction_Around::Begin_DoAction()
{
	Super::Begin_DoAction();

}

1. 데이터만 받아놓는다.

1. BP로 생성해준다.

 

1. DoAction 넣어주고, 시점 고정 없이 돌아다닐 수 있도록 Use Control은 꺼준다.

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

1. 다시 돌아와서 몽타주를 넣어주고, 각 설정에 알맞은 수치를 넣어준다.


#include "Characters/CPlayer.h"
#include "Global.h"
#include "CAnimInstance.h"
#include "GameFramework/SpringArmComponent.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Camera/CameraComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/InputComponent.h"
#include "Components/CWeaponComponent.h"
#include "Components/CMontagesComponent.h"
#include "Components/CMovementComponent.h"

void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
{
	Super::SetupPlayerInputComponent(PlayerInputComponent);

	PlayerInputComponent->BindAction("Around", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetAroundMode);

}

1. Player로가서 Around 버튼을 등록해준다.

1. Player로가서 Weapon에 Around를 넣어준다.

1. 몽타주가 실행되는걸 확인할 수 있다.


1. Around 스킬로 생성하게될 객체를 Actor로 만들어준다.

#pragma once

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

UCLASS()
class U2212_06_API ACRotate_Object : public AActor
{
	GENERATED_BODY()

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

private:
    UPROPERTY(EditDefaultsOnly, Category = "Spawn")
        float Speed = 300; // 돌아가는 속도

    UPROPERTY(EditDefaultsOnly, Category = "Spawn")
        float Distance = 150; // 중심으로부터 거리

    UPROPERTY(EditDefaultsOnly, Category = "Spawn")
        bool bNegative; // 시계방향인지, 반시계방향인지

    UPROPERTY(EditDefaultsOnly, Category = "Spawn")
        float DamageInteval = 0.1f; // 데미지 들어갈 간격

private:
    UPROPERTY(VisibleDefaultsOnly)
        class UCapsuleComponent* Capsule;

    UPROPERTY(VisibleDefaultsOnly)
        class UParticleSystemComponent* Particle;

private:
    UFUNCTION()
        void OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult);

    UFUNCTION()
        void OnComponentEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex);

    UFUNCTION()
    // 데미지 보내주는 이벤트
        void SendDamage();

public:	
	ACRotate_Object();

protected:
	virtual void BeginPlay() override;
    virtual void EndPlay(const EEndPlayReason::Type EndPlayReason); // 타이머 제거용

public:	
	virtual void Tick(float DeltaTime) override;

private:
    float Angle; // 현재 돌아갈 각도

    TArray<ACharacter*> Hitted; // 데미지 받은 객체
    FTimerHandle TimerHandle; // 타이머

};
#include "Weapons/AddOns/CRotate_Object.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/CapsuleComponent.h"
#include "Particles/ParticleSystemComponent.h"

ACRotate_Object::ACRotate_Object()
{
	PrimaryActorTick.bCanEverTick = true;

	// 생성
	CHelpers::CreateComponent<UCapsuleComponent>(this, &Capsule, "Capsule");
	CHelpers::CreateComponent<UParticleSystemComponent>(this, &Particle, "Particle", Capsule);

	// 모양 : 구형태
	Capsule->SetCapsuleHalfHeight(44);
	Capsule->SetCapsuleRadius(44);

	// 초기값들
	InitialLifeSpan = 5;

	HitData.Launch = 0;
	HitData.Power = 5;

	// HitData에 대한 몽타주 초기값 설정, 
	CHelpers::GetAsset<UAnimMontage>(&HitData.Montage, "AnimMontage'/Game/Character/Montages/HitReaction_Montage.HitReaction_Montage'");
}

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

	// 맨 앞에서 나타나지 않도록, Angle 랜덤으로 설정
	Angle = UKismetMathLibrary::RandomFloatInRange(0, 360);

	// 이벤트 연결
	Capsule->OnComponentBeginOverlap.AddDynamic(this, &ACRotate_Object::OnComponentBeginOverlap);
	Capsule->OnComponentEndOverlap.AddDynamic(this, &ACRotate_Object::OnComponentEndOverlap);

	// 타이머 이벤트 연결
	GetWorld()->GetTimerManager().SetTimer(TimerHandle, this, &ACRotate_Object::SendDamage, DamageInteval, true);

}

void ACRotate_Object::EndPlay(const EEndPlayReason::Type EndPlayReason)
{
	Super::EndPlay(EndPlayReason);

	// 타이머 제거
	GetWorld()->GetTimerManager().ClearTimer(TimerHandle);

}

void ACRotate_Object::Tick(float DeltaTime)
{
	Super::Tick(DeltaTime);

	// 스킬 나갈 시작지점
	FVector location = GetOwner()->GetActorLocation();

	Angle += (bNegative ? -Speed : +Speed) * DeltaTime; // 더해질 수치
	// 양방향 360 수치에 도달하고 수치들이 중첩되면, 짐벌락이 생길 가능성이 높아지므로, 0으로 초기화 시켜주기
	if (FMath::IsNearlyEqual(Angle, bNegative ? -360 : +360))
		Angle = 0;

	// 거리 만들어주기
	FVector distance = FVector(Distance, 0, 0);
	// 회전값 만들어주기, UpVector인 이유는 위에 Vector 기준으로 Angle을 돌게 하기 위해.
	FVector value = distance.RotateAngleAxis(Angle, FVector::UpVector);
	location += value; // 현재위치에 + 해주면 수치만큼 이동한다.

	// 세팅값 넣어주기
	SetActorLocation(location);
	SetActorRotation(FRotator(0, Angle, 0)); // 캐릭터 주변으로 돌것이므로, Yaw만 사용.

}

void ACRotate_Object::OnComponentBeginOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult& SweepResult)
{
	CheckTrue(GetOwner() == OtherActor);

	ACharacter* character = Cast<ACharacter>(OtherActor);
	if (!!character)
		Hitted.AddUnique(character); // Hitted되면 리스트에 넣기.

}

void ACRotate_Object::OnComponentEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
	CheckTrue(GetOwner() == OtherActor);

	ACharacter* character = Cast<ACharacter>(OtherActor);
	if (!!character)
		Hitted.Remove(character);

}

void ACRotate_Object::SendDamage()
{
	// 타이머에 의해서 계속 데미지 누적시키기.
	for (int32 i = Hitted.Num() - 1; i >= 0; i--)
		HitData.SendDamage(Cast<ACharacter>(GetOwner()), this, Hitted[i]);

}

1. 기본 초기값을 설정해주고, Hit 몽타주 또한 초기값 세팅을 해준다.

2. 플레이어 주변을 돌게 설정할 것이므로,  시작지점을 중심으로 일정 거리만큼 Spawn되서 돌아갈 수 있도록 설정.


#pragma once

#include "CoreMinimal.h"
#include "Weapons/CDoAction.h"
#include "CDoAction_Around.generated.h"

UCLASS(Blueprintable)
class U2212_06_API UCDoAction_Around : public UCDoAction
{
	GENERATED_BODY()

private:
	// 나갈 Around 스킬이 여러개이므로, 배열
	UPROPERTY(EditAnywhere, Category = "SpawnClass")
		TArray<TSubclassOf<class ACRotate_Object>> RotateClasses;

public:
	void DoAction() override;
	void Begin_DoAction() override;


};
#include "Weapons/DoActions/CDoAction_Around.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"

void UCDoAction_Around::DoAction()
{
	// 체크
	CheckFalse(DoActionDatas.Num() > 0);
	CheckFalse(State->IsIdleMode());

	Super::DoAction();

	// 데이터 받기.
	DoActionDatas[0].DoAction(OwnerCharacter);

}

void UCDoAction_Around::Begin_DoAction()
{
	Super::Begin_DoAction();

	// 랜덤 인덱스
	int32 index = UKismetMathLibrary::RandomIntegerInRange(0, RotateClasses.Num() - 1);

	// 랜덤 인덱스로 객체 Spawn,
	FActorSpawnParameters params;
	params.Owner = OwnerCharacter;
	params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;

	OwnerCharacter->GetWorld()->SpawnActor<ACRotate_Object>(RotateClasses[index], params);

}

1. Spawn 스킬이 여러개가 될 것이므로, 배열로 생성해준다.

2. Index 랜덤으로 돌려주면서 Spawn될 수 있도록 설정.


1. Spawn되서 캐릭터 주변을 돌게될 스킬 생성.

2. Particles 설정해주기.

1. 위에서 만들어 준 Rotate 복사해주고, Particles을 Ice 스킬로 바꿔준다.

2. Fire와 다르게 수치를 변경해주고, Inteval을 0.2 간격으로 데미지 들어가도록 설정.

1. 만들어준 스킬 등록해준다.


https://www.youtube.com/watch?v=mBZHX_SLrIw 

 

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

UE4 Weapon Bow  (0) 2023.07.05
UE4 SubAction Around Skill  (0) 2023.07.04
UE4 SubAction Warp, Top View  (0) 2023.06.30
UE4 SubAction Warp  (0) 2023.06.29
UE4 SubAction Hammer Skill  (0) 2023.06.27
Comments