[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
댓글을 사용할 수 없습니다.