[UE] 해머 스킬 만들기
해머를 장착한 상태에서 앞으로 Aura를 날리는 스킬을 추가할 것이다. SubAction에 Box 충돌체와 나이아가라 이펙트를 추가하여 스킬이 발동하면 충돌체와 나이아가라 이펙트가 앞으로 나간다. 일섬 스킬과 같이 충돌을 추가하여 데미지를 전달한다.
목차
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 CDoAction_Combo.h .cpp CSubAction_Fist.h .cpp CSubAction_Hammer.h .cpp CSubAction_Sword.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 | ||
해머스킬 구현하기
Hammer_Skill_Montage 생성
SubAction 할당
CAura 생성 & BP_CAura 생성
새 C++ 클래스 생성 - Actor - CAura 생성
CAura.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Weapons/CWeaponStructures.h"
#include "NiagaraDataInterfaceExport.h"
#include "CAura.generated.h"
UCLASS()
class U2212_06_API ACAura
: public AActor, public INiagaraParticleCallbackHandler
{
GENERATED_BODY()
private:
UPROPERTY(EditDefaultsOnly, Category = "Damage")
FHitData HitData;
UPROPERTY(EditDefaultsOnly, Category = "Damage")
float DamageInterval = 0.1f;
private:
UPROPERTY(VisibleAnywhere)
class USceneComponent* Root;
UPROPERTY(VisibleAnywhere)
class UNiagaraComponent* Niagara;
UPROPERTY(VisibleAnywhere)
class UBoxComponent* Box;//나이아가라 충돌체
public:
ACAura();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnSystemFinished(class UNiagaraComponent* PSystem);//Collision을 없애주는 역할의 함수
public:
void ReceiveParticleData_Implementation(const TArray<FBasicParticleData>& Data, UNiagaraSystem* NiagaraSystem);
private:
TArray<class ACharacter*> Hitted;
FTimerHandle TimerHandle;
};
CAura.cpp
#include "Weapons/AddOns/CAura.h"
#include "Global.h"
#include "NiagaraComponent.h"
#include "GameFramework/Character.h"
#include "Components/BoxComponent.h"
ACAura::ACAura()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
CHelpers::CreateComponent<UNiagaraComponent>(this, &Niagara, "Niagara", Root);
CHelpers::CreateComponent<UBoxComponent>(this, &Box, "Box", Root);
UNiagaraSystem* niagara;
CHelpers::GetAsset<UNiagaraSystem>(&niagara, "NiagaraSystem'/Game/sA_StylizedSwordSet/Fx/NS_Ulti_lv1.NS_Ulti_lv1'");
Niagara->SetAsset(niagara);
}
void ACAura::BeginPlay()
{
Super::BeginPlay();
Niagara->SetNiagaraVariableObject("Mesh_Scale", this);//Niagara 안에서 지정한 이름 "Mesh_Scale" 사용.
Niagara->OnSystemFinished.AddDynamic(this, &ACAura::OnSystemFinished);
}
void ACAura::OnSystemFinished(UNiagaraComponent* PSystem)
{
Destroy();//Box Collision 소멸
}
void ACAura::ReceiveParticleData_Implementation(const TArray<FBasicParticleData>& Data, UNiagaraSystem* NiagaraSystem)
{
CLog::Print(Data[0].Position);
}
※ 참고) Niagara Component 사용
CAura.cpp에서 위의 코드를 사용하는 부분 캡처
Spawn된 Box 충돌체를 없애주는 역할의 코드들.
BP_CAura_Hammer
CAura 기반 블루프린트 클래스 생성 - BP_CAura_Hammer 생성
Damage
- HitData
- Montage: HIReaction_Stop_Montage 할당
- PlayRate, Power, Launch, Stop Time 등등을 기호에 맞게 설정해준다.
Aura.cpp에서 할당한 Niagara System Asset이 할당되어서 들어온다. 따라서 굳이 눌러서 넣어줄 필요가 없다.
CSubAction_Hammer
CSubAction_Hammer.h
#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 = "Aura")
TSubclassOf<class ACAura> AuraClass;
UPROPERTY(EditDefaultsOnly, Category = "Aura")
FVector AuraLoction;//Aura를 Spawn시킬 위치 변수
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;
};
변수 추가
- TSubclassOf<class ACAura> AuraClass;
- FVector AuraLoction;
- Aura를 Spawn시킬 위치 변수
CSubAction_Hammer.cpp
#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();
FActorSpawnParameters params;
params.Owner = Owner;
params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;//AlwaysSpawn는 있는없든 무조건 Spawn시키라는 의미.
FTransform transform;
transform.SetLocation(Owner->GetActorLocation());
transform.AddToTranslation(AuraLoction);//보정 위치
transform.SetRotation(FQuat(Owner->GetActorRotation()));//캐릭터의 전방방향을 캐릭터의 회전방향으로 설정.
Owner->GetWorld()->SpawnActor<ACAura>(AuraClass, transform, params);
}
void UCSubAction_Hammer::End_SubAction_Implementation()
{
Super::End_SubAction_Implementation();
State->SetIdleMode();
State->OffSubActionMode();
Movement->Move();
Movement->DisableFixedCamera();
if (!!GhostTrail)
GhostTrail->Destroy();
}
void UCSubAction_Hammer::Begin_SubAction_Implementation()
- FActorSpawnParameters params;
params.Owner = Owner;
params.SpawnCollisionHandlingOverride = ESpawnActorCollisionHandlingMethod::AlwaysSpawn;//AlwaysSpawn는 있는없든 무조건 Spawn시키라는 의미.
FTransform transform;
transform.SetLocation(Owner->GetActorLocation());
transform.AddToTranslation(AuraLoction);//보정 위치
transform.SetRotation(FQuat(Owner->GetActorRotation()));//캐릭터의 전방방향을 캐릭터의 회전방향으로 설정.
Owner->GetWorld()->SpawnActor<ACAura>(AuraClass, transform, params);
BP_CSubAction_Hammer - Aura Class 및 위치 할당, 몽타주 할당
BP_CSubAction_Hammer
Aura
- Aura Class: BP_CAura 할당
- Aura Location: 0.0, 0.0, -90.0 할당
- 바닥에 붙은 느낌을 주기 위해 보정위치인 Aura Location의 z값을 -90.0으로 설정한다.
Action
- Action Data
- Montage: Hammer_Skill_Montage 할당
DA_Hammer - SubAction Class에 BP_CSubAction_Hammer 할당
실행화면
나이아가라 충돌체 크기 조절 및 충돌 구현하기
나이아가라 에셋 수정 - NS_Ulti_lv1
NS_Ulti_lv1
NS_Ulti_lv1
시스템 세팅 - Object 추가
이름을 Mesh_Scale로 변경
- 나이아가라 파티클 매쉬의 Export Particle Data to Blueprint에 Callback Handler로 이것을 사용하기 때문에 이름을 기억해두어야 한다.
- CAura.cpp 내의 BeginPlay()에서 SetNiagaraVariableObject("Mesh_Scale")로 데이터를 할당한다. 이 때 Mesh_Scale를 문자열로 기입한다.
파티클 업데이트 - Export Particle Data to Blueprint 추가
- Condition To Export Data를 체크
- Vector to Send (As Struct Position)
- Link Inputs: 서로 간에 연결해서 입력받는 변수들
- 동적 입력: 외부에서 여기에다 넣어주는 값
- 파티클:
- 초기: 파티클 Spawn 될 때의 초기값.
- 초기가 안 붙어있으면 업데이트된 값. ex. 위치 - 위치의 업데이트된 값.
- PRESOLVE: 처리되기 이전 값.
- 여기서는 Scale 사용
- Export Particle Data Interface
- 익스포트
- Callback Handler: Mesh_Scale 할당
- 익스포트
Scale값이 Mesh_Scale를 통해 외부로 나간다.
파티클 크기 확인하기
- 나이아가라 파티클로 사용한 매쉬를 찾아 열어준다.
- 대략 크기를 확인한다. 위의 경우 421 x 185 x 291 이다.
- 이 크기값을 활용해서 Box 충돌체의 크기를 결정한다.
- BP_CAura_Hammer의 Box 충돌체의 크기를 x: 210.5, y: 92.5, z:144.5로 설정해준다.
Spawn 되는 파티클의 크기는 '파티클 매쉬의 크기 x Scale' 이다.
블루프린트 예시 - 다음 블루프린트를 코드로 구현할 것이다.
BP_CAura_Hammer - Box 충돌체 크기 변경하기
BP_CAura_Hammer
Box
- Shape
- Box Extent: 210.0, 92.5, 145.5
- Spawn 되는 Box의 크기는 '파티클 매쉬의 크기 x Scale' 이다. = Spawn 되는 파티클의 크기는 '파티클 매쉬의 크기 x Scale' 이다.
CAura 코드 추가
CAura.h
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "Weapons/CWeaponStructures.h"
#include "NiagaraDataInterfaceExport.h"
#include "CAura.generated.h"
UCLASS()
class U2212_06_API ACAura
: public AActor, public INiagaraParticleCallbackHandler
{
GENERATED_BODY()
private:
UPROPERTY(EditDefaultsOnly, Category = "Damage")
FHitData HitData;
UPROPERTY(EditDefaultsOnly, Category = "Damage")
float DamageInterval = 0.1f;
private:
UPROPERTY(VisibleAnywhere)
class USceneComponent* Root;
UPROPERTY(VisibleAnywhere)
class UNiagaraComponent* Niagara;
UPROPERTY(VisibleAnywhere)
class UBoxComponent* Box;//나이아가라 Box 충돌체
public:
ACAura();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnSystemFinished(class UNiagaraComponent* PSystem);//Collision을 없애주는 역할의 함수
private:
//충돌 이벤트 2개
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);
public:
void ReceiveParticleData_Implementation(const TArray<FBasicParticleData>& Data, UNiagaraSystem* NiagaraSystem);
private:
TArray<class ACharacter*> Hitted;//Hitted되는 목록
FTimerHandle TimerHandle;//Hitted 목록을 TimberHandle을 이용해서 데미지를 주기 위해 사용하는 변수
};
부모 클래스 추가
- public INiagaraParticleCallbackHandler
- void ReceiveParticleData_Implementation 사용을 위해 추가한다.
CAura.cpp
#include "Weapons/AddOns/CAura.h"
#include "Global.h"
#include "NiagaraComponent.h"
#include "GameFramework/Character.h"
#include "Components/BoxComponent.h"
ACAura::ACAura()
{
CHelpers::CreateComponent<USceneComponent>(this, &Root, "Root");
CHelpers::CreateComponent<UNiagaraComponent>(this, &Niagara, "Niagara", Root);
CHelpers::CreateComponent<UBoxComponent>(this, &Box, "Box", Root);
UNiagaraSystem* niagara;
CHelpers::GetAsset<UNiagaraSystem>(&niagara, "NiagaraSystem'/Game/sA_StylizedSwordSet/Fx/NS_Ulti_lv1.NS_Ulti_lv1'");//나이아가라 에셋 할당.
Niagara->SetAsset(niagara);
}
void ACAura::BeginPlay()
{
Super::BeginPlay();
Niagara->SetNiagaraVariableObject("Mesh_Scale", this);//Niagara 안에서 지정한 이름 "Mesh_Scale" 사용.
Niagara->OnSystemFinished.AddDynamic(this, &ACAura::OnSystemFinished);
Box->OnComponentBeginOverlap.AddDynamic(this, &ACAura::OnComponentBeginOverlap);
Box->OnComponentEndOverlap.AddDynamic(this, &ACAura::OnComponentEndOverlap);
//타이머 설정. 일정시간 동안 Damage를 준다.
FTimerDelegate delegate = FTimerDelegate::CreateLambda([&]()
{
for (int32 i = Hitted.Num() - 1; i >= 0; i--)
HitData.SendDamage(Cast<ACharacter>(GetOwner()), this, Hitted[i]);
});
GetWorld()->GetTimerManager().SetTimer(TimerHandle, delegate, DamageInterval, true, 0);
}
void ACAura::OnSystemFinished(UNiagaraComponent* PSystem)
{
GetWorld()->GetTimerManager().ClearTimer(TimerHandle);//끝날 때 TimerHandle 제거
Destroy();//Box 충돌체 소멸
}
void ACAura::ReceiveParticleData_Implementation(const TArray<FBasicParticleData>& Data, UNiagaraSystem* NiagaraSystem)
{
Box->SetRelativeScale3D(Data[0].Position);
FVector location = Box->GetScaledBoxExtent();
location.Y = 0;//Y=0을 만든 이유는? 캐릭터 기준에서 기준선에 맞추기 위해서이다. 캐릭터 중앙 기준은 Y=0이다.
CLog::Log(location);
Box->SetRelativeLocation(location);
}
void ACAura::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 ACAura::OnComponentEndOverlap(UPrimitiveComponent* OverlappedComponent, AActor* OtherActor, UPrimitiveComponent* OtherComp, int32 OtherBodyIndex)
{
CheckTrue(GetOwner() == OtherActor);
ACharacter* character = Cast<ACharacter>(OtherActor);
if (!!character)
Hitted.Remove(character);
}
함수 재정의
- void ReceiveParticleData_Implementation(const TArray<FBasicParticleData>& Data, UNiagaraSystem* NiagaraSystem);
- _Implementation을 붙여 NiagaraDataInterfaceExport.h 내의 void ReceiveParticleData() 함수를 재정의한다.
※참고: NiagaraDataInterfaceExport.h 내의 void ReceiveParticleData(const TArray<FBasicParticleData>& Data, UNiagaraSystem* NiagaraSystem)
location.Y = 0 이 적용 전
void ACAura::ReceiveParticleData_Implementation에서 location.Y = 0 적용 전
- 캐릭터 중앙 기준이 아닌 y: 92.5값이 적용된다.
실행화면
'⭐ Unreal Engine > UE RPG Skill' 카테고리의 다른 글
[UE] 워프 Top View 만들기 (0) | 2023.06.30 |
---|---|
[UE] 워프 구현하기 (0) | 2023.06.29 |
[UE] 일섬 스킬 충돌, 해머 스킬 만들기 (0) | 2023.06.26 |
[UE] 주먹 스킬 충돌처리, 전진 찌르기 스킬 구현하기 (0) | 2023.06.23 |
[UE] 잔상효과 구현하기 (0) | 2023.06.22 |
댓글
이 글 공유하기
다른 글
-
[UE] 워프 Top View 만들기
[UE] 워프 Top View 만들기
2023.06.30 -
[UE] 워프 구현하기
[UE] 워프 구현하기
2023.06.29 -
[UE] 일섬 스킬 충돌, 해머 스킬 만들기
[UE] 일섬 스킬 충돌, 해머 스킬 만들기
2023.06.26 -
[UE] 주먹 스킬 충돌처리, 전진 찌르기 스킬 구현하기
[UE] 주먹 스킬 충돌처리, 전진 찌르기 스킬 구현하기
2023.06.23