해머를 장착한 상태에서 앞으로 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 BlueprintCallback 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값이 적용된다.

 

 


 

 

 

실행화면