[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