플레이어 주위를 도는 구형 이펙터로 적에게 피해를 입히는 공격패턴을 만들것이다. 충돌체는 0.2초 간격으로 데미지를 전달할 것이다. 주위에 적이 많을 때 지속적인 데미지를 전달하기 유용한 공격패턴이 될 것이다.

 

목차

     

     


     

     

     
    Plugins
     
      Weapon
     
        Resource
     
          Icon128.png
    weapon_thumbnail_icon.png
     
        Source
     
          Weapon  
          SWeaponCheckBoxes.h .cpp
    SWeaponDetailsView.h .cpp

    SWeaponDoActionData.h .cpp
    SWeaponEquipmentData.h .cpp
    SWeaponHitData.h .cpp

    SWeaponLeftArea.h .cpp
    Weapon.Build.cs
    WeaponAssetEditor.h .cpp
    WeaponAssetFactory.h .cpp
    WeaponCommand.h .cpp 
    WeaponContextMenu.h .cpp
    WeaponModule.h .cpp
    WeaponStyle.h .cpp 
     
       

     

     
    Source
      U2212_06
        Characters
        CAnimInstance.h .cpp
    CEnemy.h .cpp 
    CPlayer.h .cpp
    ICharacter.h .cpp
        Components
        CMontagesComponent.h .cpp 
    CMovementComponent.h .cpp 
    CStateComponent.h .cpp
    CStatusComponent.h .cpp  
    CWeaponComponent.h .cpp 
        Notifies
        CAnimNotifyState_BeginAction.h .cpp 
    CAnimNotify_CameraShake.h .cpp 
    CAnimNotifyState_EndAction.h .cpp
    CAnimNotify_EndState.h .cpp
    CAnimNotifyState.h .cpp
    CAnimNotifyState_CameraAnim.h .cpp
    CAnimNotifyState_Collision.h .cpp 
    CAnimNotifyState_Combo.h .cpp
    CAnimNotifyState_Equip.h .cpp
    CAnimNotifyState_SubAction.h .cpp
        Utilities
        CHelper.h
    CLog.h .cpp
        Weapons
        CAura.h .cpp
    CCamerModifier.h .cpp
    CGhostTrail.h .cpp
    CRotate_Object.h .cpp 생성
    CDoAction_Around.h .cpp 생성

    CDoAction_Combo.h .cpp
    CDoAction_Warp.h .cpp
    CSubAction_Fist.h .cpp
    CSubAction_Hammer.h .cpp
    CSubAction_Sword.h .cpp
    CDoAction_Warp.h .cpp

    CAttachment.h .cpp
    CDoAction.h .cpp
    CEquipment.h .cpp
    CSubAction.h .cpp
    CWeaponAsset.h .cpp
    CWeaponStructures.h .cpp
        Global.h
    CGameMode.h .cpp
    U2212_06.Build.cs
        U2212_06.uproject
     

     

     

     

     

     

    Around 공격 구현하기

     

     


     

     

    CPlayer.cpp -  키 입력 추가

     

    CPlayer.h

    변동사항 없음.

     

     

    CPlayer.cpp

    더보기
    #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/CMontagesComponent.h"
    #include "Components/CMovementComponent.h"
    #include "Components/CWeaponComponent.h"
    
    ACPlayer::ACPlayer()
    {
    	CHelpers::CreateComponent<USpringArmComponent>(this, &SpringArm, "SpringArm", GetMesh());
    	CHelpers::CreateComponent<UCameraComponent>(this, &Camera, "Camera", SpringArm);
    
    	CHelpers::CreateActorComponent<UCWeaponComponent>(this, &Weapon, "Weapon");
    	CHelpers::CreateActorComponent<UCMontagesComponent>(this, &Montages, "Montages");
    	CHelpers::CreateActorComponent<UCMovementComponent>(this, &Movement, "Movement");
    	CHelpers::CreateActorComponent<UCStateComponent>(this, &State, "State");
    
    	GetMesh()->SetRelativeLocation(FVector(0, 0, -90));
    	GetMesh()->SetRelativeRotation(FRotator(0, -90, 0));
    
    	USkeletalMesh* mesh;
    	CHelpers::GetAsset<USkeletalMesh>(&mesh, "SkeletalMesh'/Game/Character/Mesh/SK_Mannequin.SK_Mannequin'");
    	GetMesh()->SetSkeletalMesh(mesh);
    
    	TSubclassOf<UCAnimInstance> animInstance;
    	CHelpers::GetClass<UCAnimInstance>(&animInstance, "AnimBlueprint'/Game/ABP_Character.ABP_Character_C'");
    	GetMesh()->SetAnimClass(animInstance);
    
    	SpringArm->SetRelativeLocation(FVector(0, 0, 140));
    	SpringArm->SetRelativeRotation(FRotator(0, 90, 0));
    	SpringArm->TargetArmLength = 200;
    	SpringArm->bDoCollisionTest = false;
    	SpringArm->bUsePawnControlRotation = true;
    	SpringArm->bEnableCameraLag = true;
    
    	GetCharacterMovement()->RotationRate = FRotator(0, 720, 0);
    
    }
    
    void ACPlayer::BeginPlay()
    {
    	Super::BeginPlay();
    
    	Movement->OnRun(); //Movement의 기본을 Run으로 설정
    	Movement->DisableControlRotation();//Movement의 기본을 DisableControlRotation으로 설정
    
    	State->OnStateTypeChanged.AddDynamic(this, &ACPlayer::OnStateTypeChanged);
    }
    
    void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
    {
    	Super::SetupPlayerInputComponent(PlayerInputComponent);
    
    	PlayerInputComponent->BindAxis("MoveForward", Movement, &UCMovementComponent::OnMoveForward);
    	PlayerInputComponent->BindAxis("MoveRight", Movement, &UCMovementComponent::OnMoveRight);
    	PlayerInputComponent->BindAxis("VerticalLook", Movement, &UCMovementComponent::OnVerticalLook);
    	PlayerInputComponent->BindAxis("HorizontalLook", Movement, &UCMovementComponent::OnHorizontalLook);
    
    	PlayerInputComponent->BindAction("Sprint", EInputEvent::IE_Pressed, Movement, &UCMovementComponent::OnSprint);
    	PlayerInputComponent->BindAction("Sprint", EInputEvent::IE_Released, Movement, &UCMovementComponent::OnRun);
    
    	PlayerInputComponent->BindAction("Avoid", EInputEvent::IE_Pressed, this, &ACPlayer::OnAvoid);
    
    	PlayerInputComponent->BindAction("Fist", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetFistMode);
    	PlayerInputComponent->BindAction("Sword", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetSwordMode);
    	PlayerInputComponent->BindAction("Hammer", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetHammerMode);
    	PlayerInputComponent->BindAction("Warp", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetWarpMode);
    	PlayerInputComponent->BindAction("Around", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetAroundMode);
    
    	PlayerInputComponent->BindAction("Action", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::DoAction);
    
    	PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SubAction_Pressed);
    	PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Released, Weapon, &UCWeaponComponent::SubAction_Released);
    }
    
    void ACPlayer::OnStateTypeChanged(EStateType InPrevType, EStateType InNewType)
    {
    	switch (InNewType)
    	{
    		case EStateType::BackStep: BackStep(); break;
    	}
    }
    
    void ACPlayer::OnAvoid()
    {
    	CheckFalse(State->IsIdleMode());
    	CheckFalse(Movement->CanMove());
    
    	CheckTrue(InputComponent->GetAxisValue("MoveForward") >= 0.0f);//뒷방향을 입력했다면
    
    	State->SetBackStepMode();//State을 BackStepMode로 변경한다.
    }
    
    void ACPlayer::BackStep()
    {
    	Movement->EnableControlRotation();//정면을 바라본 상태로 뒤로 뛰어야하기 때문에 EnableControlRotation으로 만들어준다.
    
    	Montages->PlayBackStepMode();//PlayBackStepMode()를 통해 몽타주 재생.
    }
    
    void ACPlayer::End_BackStep()
    {
    	Movement->DisableControlRotation();//Backstep이 끝나면 원래대로 돌려준다.
    
    	State->SetIdleMode();//Idle상태로 돌려줌.
    }

    키 입력 추가 - Around

    • void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
      • PlayerInputComponent->BindAction("Around", EInputEvent::IE_Pressed, Weapon,  &UCWeaponComponent::SetAroundMode);

     

     

    BP_CPlayer에 Weapon - DA_Around 할당하기

    Weapon

    • Data Assets: DA _Around 할당

     


     

     

    Around_Montage 생성

     

    Begin_DoAction과 End_DoAction 할당.


     

     

    CDoAction_Around 생성

     

    새 C++ 클래스 - CDoAction - CDoAction_Around 생성

     

     

    CDoAction_Around.h

    더보기
    #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:
    	UPROPERTY(EditAnywhere, Category = "SpawnClass")
    		TArray<TSubclassOf<class ACRotate_Object>> RotateClasses;//회전체를 여러개 만들기위해 배열로 생성한다.
    
    public:
    	void DoAction() override;
    	void Begin_DoAction() override;
    };

     

     

     

    CDoAction_Around.cpp

    더보기
    #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);
    
    
    	FActorSpawnParameters params;
    	params.Owner = OwnerCharacter;
    	params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;
    
    	OwnerCharacter->GetWorld()->SpawnActor<ACRotate_Object>(RotateClasses[index], params);
    }

     

     

     

    BP_CDoAction_Around 생성

     

    CDoAction_Around 기반 블루프린트 클래스 생성 - BP_CDoAction_Around 생성

    .Spawn Class

    • Rotate Classes:  BP_CRotate_Object, BP_CRotate_Object1 할당

     


     

     

    CRotate_Object 생성

     

    새 C++ 클래스 - Actor - CRotate_Object 생성

     

     

    CRotate_Object .h

    더보기
    #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);//타이머를 종료시키기 위해 EndPlay가 필요하다.
    
    public:	
    	virtual void Tick(float DeltaTime) override;
    
    private:
    	float Angle;//현재 돌아가는 각도
    
    	TArray<ACharacter*> Hitted;//데미지 받을 애들
    	FTimerHandle TimerHandle;//타이머
    };

     

     

     

    CRotate_Object .cpp

    더보기
    #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);
    
    	//구형태에 가깝게 HalfHeight와 Radius값을 동일하게 설정하였다.
    	Capsule->SetCapsuleHalfHeight(44);
    	Capsule->SetCapsuleRadius(44);
    
    	InitialLifeSpan = 5;
    
    	HitData.Launch = 0;//HitData 초기값 설정.
    	HitData.Power = 5;//HitData 초기값 설정.
    
    	CHelpers::GetAsset<UAnimMontage>(&HitData.Montage, "AnimMontage'/Game/Character/Montages/Common/HitReaction_Stop_Montage.HitReaction_Stop_Montage'");//HitReaction 몽타주 
    }
    
    void ACRotate_Object::BeginPlay()
    {
    	Super::BeginPlay();
    
    	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);//타이머 설정. 타이머가 돌고있는 동안 계속해서 Damage가 들어간다.
    }
    
    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;
    	if (FMath::IsNearlyEqual(Angle, bNegative ? -360 : +360))
    		Angle = 0;//짐벌락 현상을 방지하기 위해서 +-360도가 되었을때 0도로 만들어준다.
    
    	FVector distance = FVector(Distance, 0, 0);
    	FVector value = distance.RotateAngleAxis(Angle, FVector::UpVector);//UpVector(Yaw)기준으로 회전.
    	location += value;//현재위치에서 회전해서 이동한 위치값을 더해준다.
    
    	SetActorLocation(location);//위치 갱신
    	SetActorRotation(FRotator(0, Angle, 0));//각 갱신
    }
    
    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);
    }
    
    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]);
    }

     

     

     

    BP_CRotateObject, BP_CRotateObject1 생성

    BP_CRotateObject

    BP_CRotateObject1


     

     

    DA_Around 생성

     

    DA_Around 


     

     

    실행화면

     

     


     

     

     

     

    '⭐ Unreal Engine > UE RPG Skill' 카테고리의 다른 글

    [UE] 활 구현하기  (0) 2023.07.05
    [UE] Around 스킬 구현하기  (0) 2023.07.04
    [UE] 워프 Top View 만들기  (0) 2023.06.30
    [UE] 워프 구현하기  (0) 2023.06.29
    [UE] 해머 스킬 만들기  (0) 2023.06.27