[UE] Around 공격 구현하기

플레이어 주위를 도는 구형 이펙터로 적에게 피해를 입히는 공격패턴을 만들것이다. 충돌체는 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 |
댓글
이 글 공유하기
다른 글
-
[UE] 활 구현하기
[UE] 활 구현하기
2023.07.05 -
[UE] Around 스킬 구현하기
[UE] Around 스킬 구현하기
2023.07.04 -
[UE] 워프 Top View 만들기
[UE] 워프 Top View 만들기
2023.06.30 -
[UE] 워프 구현하기
[UE] 워프 구현하기
2023.06.29
댓글을 사용할 수 없습니다.