[UE] Hit Effect 구현, Status Component, Hammer 공격 구현
목차
Source | ||
Characters | ||
CAnimInstance.h .cpp CEnemy.h .cpp CPlayer.h .cpp ICharacter.h .cpp |
||
Components | ||
CMontagesComponent.h .cpp CMovementComponent.h .cpp CStateComponent.h .cpp 생성 CWeaponComponent.h .cpp |
||
Notifies | ||
CAnimNotifyState_BeginAction.h .cpp CAnimNotifyState_EndAction.h .cpp CAnimNotify_EndState.h .cpp CAnimNotifyState_Collision.h .cpp CAnimNotifyState_Combo.h .cpp CAnimNotifyState_Equip.h .cpp |
||
Utilities | ||
CHelper.h CLog.h .cpp |
||
Weapons | ||
CDoAction_Combo.h .cpp CAttachment.h .cpp CDoAction.h .cpp CEquipment.h .cpp CWeaponAsset.h .cpp CWeaponStructures.h .cpp |
||
Global.h CGameMode.h .cpp U2212_06.Build.cs |
||
U2212_06.uproject | ||
Hit Effect 넣기
CWeaponStructure
CWeaponStructure.h
더보기
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "CWeaponStructures.generated.h"
USTRUCT()
struct FEquipmentData
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere)
class UAnimMontage* Montage;
UPROPERTY(EditAnywhere)
float PlayRate = 1;
UPROPERTY(EditAnywhere)
bool bCanMove = true;
UPROPERTY(EditAnywhere)
bool bUseControlRotation = true;
};
USTRUCT()
struct FDoActionData
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere)
class UAnimMontage* Montage;
UPROPERTY(EditAnywhere)
float PlayRate = 1;
UPROPERTY(EditAnywhere)
bool bCanMove = true;
UPROPERTY(EditAnywhere)
bool bFixedCamera;
UPROPERTY(EditAnywhere)
class UFXSystemAsset* Effect; //사용할 Effect 변수
UPROPERTY(EditAnywhere)
FVector EffectLocation = FVector::ZeroVector;//(Effect)지정 방향의 보정치.
UPROPERTY(EditAnywhere)
FVector EffectScale = FVector::OneVector;//Effect 크기 기본값 1 설정.
public:
void DoAction(class ACharacter* InOwner);
void PlayEffect(UWorld* InWorld, const FVector& InLocation);
void PlayEffect(UWorld* InWorld, const FVector& InLocation, const FRotator& InRotation);
};
USTRUCT()
struct FHitData
{
GENERATED_BODY()
UPROPERTY(EditAnywhere)
class UAnimMontage* Montage;
UPROPERTY(EditAnywhere)
float PlayRate = 1;
UPROPERTY(EditAnywhere)
float Power;
UPROPERTY(EditAnywhere)
float Launch = 100;
UPROPERTY(EditAnywhere)
float StopTime;
UPROPERTY(EditAnywhere)
class USoundWave* Sound;
UPROPERTY(EditAnywhere)
class UFXSystemAsset* Effect;
UPROPERTY(EditAnywhere)
FVector EffectLocation = FVector::ZeroVector;
UPROPERTY(EditAnywhere)
FVector EffectScale = FVector::OneVector;
public:
void SendDamage(class ACharacter* InAttacker, AActor* InAttackCauser, class ACharacter* InOther);
void PlayMontage(class ACharacter* InOwner);
void PlayHitStop(UWorld* InWorld);
void PlaySoundWave(class ACharacter* InOwner);
void PlayEffect(UWorld* InWorld, const FVector& InLocation);
void PlayEffect(UWorld* InWorld, const FVector& InLocation, const FRotator& InRotation);
};
USTRUCT()
struct FActionDamageEvent : public FDamageEvent
{
GENERATED_BODY()
public:
FHitData* HitData;
};
UCLASS()
class U2212_06_API UCWeaponStructures : public UObject
{
GENERATED_BODY()
};
FDoActionData 구조체에 함수 추가
- void PlayEffect(UWorld* InWorld, const FVector& InLocation);
- void PlayEffect(UWorld* InWorld, const FVector& InLocation, const FRotator& InRotation);
- 공격할 때 나오는 Effect 재생을 위한 함수
FHitData 구조체에 함수 추가
- void PlayEffect(UWorld* InWorld, const FVector& InLocation);
- void PlayEffect(UWorld* InWorld, const FVector& InLocation, const FRotator& InRotation);
- 맞았을 때 때 나오는 Effect 재생을 위한 함수
CWeaponStructure.cp
더보기
#include "Weapons/CWeaponStructures.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
#include "Components/CMovementComponent.h"
#include "Animation/AnimMontage.h"
void FDoActionData::DoAction(ACharacter* InOwner)
{
UCMovementComponent* movement = CHelpers::GetComponent<UCMovementComponent>(InOwner);
if (!!movement)
{
if (bFixedCamera)
movement->EnableFixedCamera();
if (bCanMove == false)
movement->Stop();
}
if (!!Montage)
InOwner->PlayAnimMontage(Montage, PlayRate);
}
void FDoActionData::PlayEffect(UWorld* InWorld, const FVector& InLocation)
{
CheckNull(Effect);
FTransform transform;
transform.SetLocation(EffectLocation);
transform.SetScale3D(EffectScale);
transform.AddToTranslation(InLocation);
CHelpers::PlayEffect(InWorld, Effect, transform);
}
void FDoActionData::PlayEffect(UWorld* InWorld, const FVector& InLocation, const FRotator& InRotation)
{
CheckNull(Effect);
FTransform transform;
transform.SetLocation(InLocation + InRotation.RotateVector(EffectLocation));
transform.SetScale3D(EffectScale);
CHelpers::PlayEffect(InWorld, Effect, transform);
}
void FHitData::SendDamage(ACharacter* InAttacker, AActor* InAttackCauser, ACharacter* InOther)
{
FActionDamageEvent e;
e.HitData = this;
InOther->TakeDamage(Power, e, InAttacker->GetController(), InAttackCauser);
}
void FHitData::PlayMontage(ACharacter* InOwner)
{
if (!!Montage)
InOwner->PlayAnimMontage(Montage, PlayRate);
}
void FHitData::PlayHitStop(UWorld* InWorld)
{
CheckTrue(FMath::IsNearlyZero(StopTime));
TArray<ACharacter*> characters;
for(AActor* actor : InWorld->GetCurrentLevel()->Actors)
{
ACharacter* character = Cast<ACharacter>(actor);
if(!!character)
{
character->CustomTimeDilation = 1e-3f;
characters.Add(character);
}
}
//익명 메소드 //람다 클로저
//람다는 외부에서 닫힌 상태로 실행되는 객체
FTimerDelegate timerDelegate;
timerDelegate.BindLambda([=]()
{
for (ACharacter* character : characters)
character->CustomTimeDilation = 1;
});
FTimerHandle timerHandle;
InWorld->GetTimerManager().SetTimer(timerHandle, timerDelegate, StopTime, false);
}
void FHitData::PlaySoundWave(ACharacter* InOwner)
{
CheckNull(Sound);
UWorld* world = InOwner->GetWorld();
FVector location = InOwner->GetActorLocation();
UGameplayStatics::SpawnSoundAtLocation(world, Sound, location);
}
void FHitData::PlayEffect(UWorld* InWorld, const FVector& InLocation)
{
CheckNull(Effect);
FTransform transform;
transform.SetLocation(EffectLocation);
transform.SetScale3D(EffectScale);
transform.AddToTranslation(InLocation);
CHelpers::PlayEffect(InWorld, Effect, transform);
}
void FHitData::PlayEffect(UWorld* InWorld, const FVector& InLocation, const FRotator& InRotation)
{
CheckNull(Effect);
FTransform transform;
transform.SetLocation(InLocation + InRotation.RotateVector(EffectLocation));
transform.SetScale3D(EffectScale);
CHelpers::PlayEffect(InWorld, Effect, transform);
}
HP 관리하기
CStatusComponent 생성
새 C++ 클래스 - Actor Component - CStatusComponent 생성
CStatusComponent.h
더보기
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "CStatusComponent.generated.h"
UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class U2212_06_API UCStatusComponent : public UActorComponent
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere, Category = "Health")
float MaxHealth = 100;
public:
FORCEINLINE float GetHealth() { return Health; }
FORCEINLINE bool IsDead() { return Health <= 0.0f; }
public:
UCStatusComponent();
protected:
virtual void BeginPlay() override;
public:
void Damage(float InAmount);
private:
class ACharacter* OwnerCharacter;
private:
float Health;
};
CStatusComponent.cpp
더보기
#include "Components/CStatusComponent.h"
#include "Global.h"
#include "GameFramework/Character.h"
UCStatusComponent::UCStatusComponent()
{
}
void UCStatusComponent::BeginPlay()
{
Super::BeginPlay();
OwnerCharacter = Cast<ACharacter>(GetOwner());
Health = MaxHealth;
}
void UCStatusComponent::Damage(float InAmount)
{
Health += (InAmount * -1.0f);
Health = FMath::Clamp(Health, 0.0f, MaxHealth);
}
CMontageComponent
CMontageComponent.h
더보기
#pragma once
#include "CoreMinimal.h"
#include "Components/ActorComponent.h"
#include "Components/CStateComponent.h"
#include "Engine/DataTable.h"
#include "CMontagesComponent.generated.h"
USTRUCT()
struct FMontageData
: public FTableRowBase
{
GENERATED_BODY()
public:
UPROPERTY(EditAnywhere)
EStateType Type; //상태 Type
UPROPERTY(EditAnywhere)
class UAnimMontage* Montage;
UPROPERTY(EditAnywhere)
float PlayRate = 1; //Player 속도
};
UCLASS(ClassGroup = (Custom), meta = (BlueprintSpawnableComponent))
class U2212_06_API UCMontagesComponent : public UActorComponent
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere, Category = "DataTable")
UDataTable* DataTable;
public:
UCMontagesComponent();
protected:
virtual void BeginPlay() override;
public:
void PlayBackStepMode();
void PlayDeadMode();
private:
void PlayAnimMontage(EStateType InType);
private:
class ACharacter* OwnerCharacter;
FMontageData* Datas[(int32)EStateType::Max];
};
함수 생성
- void PlayDeadMode();
CMontageComponent.cpp
더보기
#include "Components/CMontagesComponent.h"
#include "Global.h"
#include "GameFramework/Character.h"
//#define LOG_UCMontagesComponent 1
UCMontagesComponent::UCMontagesComponent()
{
}
void UCMontagesComponent::BeginPlay()
{
Super::BeginPlay();
if(DataTable == nullptr)//DataTable이 없다면
{ //DataTable이 없다고 메시지를 띄워준다.
GLog->Log(ELogVerbosity::Error, "DataTable is not selected");
return;
}
OwnerCharacter = Cast<ACharacter>(GetOwner());
TArray<FMontageData*> datas;
DataTable->GetAllRows<FMontageData>("", datas);//전체 데이터를 가져온다.
//가져온 데이터를 배열에 넣어준다.
for (int32 i = 0; i< (int32)EStateType::Max; i++)
{
for(FMontageData* data : datas)
{
if((EStateType)i == data->Type)
{
Datas[i] = data;
continue;
}
}//for(data)
}//for(i)
}
#if LOG_UCMontagesComponent
for (FMontagesData* data : datas)
{
if (data == nullptr)
continue;
FString str;
//Static이 붙는 애들은 Reflection(자료형의 타입을 변수로 다룰 수 있게 해준다).
str.Append(StaticEnum<EStateType>()->GetValueAsString(data->Type));//Enum을 문자열로 바꾸어서 자료형의 이름을 가져온다.
str.Append(" / ");
str.Append(data->Montage->GetPathName());
CLog::Log(str);
}
#endif
void UCMontagesComponent::PlayBackStepMode()
{
PlayAnimMontage(EStateType::BackStep);
}
void UCMontagesComponent::PlayDeadMode()
{
PlayAnimMontage(EStateType::Dead);
}
void UCMontagesComponent::PlayAnimMontage(EStateType InType)
{
CheckNull(OwnerCharacter);
FMontageData* data = Datas[(int32)InType];
if(data == nullptr || data->Montage == nullptr)
{
GLog->Log(ELogVerbosity::Error, "None montages data");
return;
}
OwnerCharacter->PlayAnimMontage(data->Montage, data->PlayRate);//data의 몽타주를 PlayRate속도로 OwnerCharacter에 적용하여 재생.
}
함수 정의
- void UCMontagesComponent::PlayDeadMode() { PlayAnimMontage(EStateType::Dead); }
- EStateType을 Dead로 만들어준다.
CAnimNotify_EndState
CAnimNotify_EndState.h
더보기
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimNotifies/AnimNotify.h"
#include "Components/CStateComponent.h"
#include "CAnimNotify_EndState.generated.h"
UCLASS()
class U2212_06_API UCAnimNotify_EndState : public UAnimNotify
{
GENERATED_BODY()
private:
UPROPERTY(EditAnywhere, Category = "Type")
EStateType StateType;
public:
FString GetNotifyName_Implementation() const override;
void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation) override;
};
변경사항 없음.
CAnimNotify_EndState.cpp
더보기
#include "CAnimNotify_EndState.h"
#include "Global.h"
#include "Characters/ICharacter.h"
FString UCAnimNotify_EndState::GetNotifyName_Implementation() const
{
return "EndState";
}
void UCAnimNotify_EndState::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation)
{
Super::Notify(MeshComp, Animation);
CheckNull(MeshComp);
CheckNull(MeshComp->GetOwner());
IICharacter* character = Cast<IICharacter>(MeshComp->GetOwner());
CheckNull(character);
switch(StateType)
{
case EStateType::BackStep: character->End_BackStep(); break;
case EStateType::Hitted: character->End_Hitted(); break;
case EStateType::Dead: character->End_Dead(); break;
}
}
EndState::Notify에 EStateType을 추가한다.
- switch(StateType) {
case EStateType::BackStep: character->End_BackStep(); break;
case EStateType::Hitted: character->End_Hitted(); break;
case EStateType::Dead: character->End_Dead(); break;
}
DT_Enemy 생성 후 BP_CEnemy에할당
DT_Enemy 생성
BP_CEnemy - Montages에 DT_Enemy 할당
실행화면
Hammer 공격 구현하기
Static Mesh를 Skeletal Mesh로 바꾸는 방법
- 에셋 액션 - 익스포트 - fbx로 저장
- 다른 폴더에서 fbx로 임포트
- Skeletal Mesh 체크 후에 모두 임포트
- UCX 3개는 삭제
BP_CAttachment_Hammer 생성
BP_CAttachment_Sword 복사하여 BP_CAttachment_Hammer 생성
Event Graph
DA_Hammer 생성
DA_Sword 복사하여 DA_Hammer 생성
몽타주 수정
ABP_Character
Hammer 추가
실행화면
'⭐ Unreal Engine > UE RPG Weapon System' 카테고리의 다른 글
[UE] 주먹 공격 및 카메라 흔들림(Camera Shake) 효과 구현 (0) | 2023.05.11 |
---|---|
[UE] Hit Data, Effect, Object Pooling(오브젝트 풀링) (0) | 2023.05.09 |
[UE] AnimNotify, DoAction (0) | 2023.05.08 |
[UE] 무기 장착 및 기본 공격하기 (0) | 2023.05.02 |
[UE] 무기 시스템 설계하기 (0) | 2023.05.01 |
댓글
이 글 공유하기
다른 글
-
[UE] 주먹 공격 및 카메라 흔들림(Camera Shake) 효과 구현
[UE] 주먹 공격 및 카메라 흔들림(Camera Shake) 효과 구현
2023.05.11 -
[UE] Hit Data, Effect, Object Pooling(오브젝트 풀링)
[UE] Hit Data, Effect, Object Pooling(오브젝트 풀링)
2023.05.09 -
[UE] AnimNotify, DoAction
[UE] AnimNotify, DoAction
2023.05.08 -
[UE] 무기 장착 및 기본 공격하기
[UE] 무기 장착 및 기본 공격하기
2023.05.02