초보 코린이의 성장 일지
UE4 AnimNotify, ComboState, TakeDamage 본문
한번만 공격되는 상태이므로, 다시 예외처리를 해주고 콤보 동작을 만들어 보겠다.
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimNotifies/AnimNotify.h"
#include "CAnimNotify_BeginAction.generated.h"
UCLASS()
class U2212_06_API UCAnimNotify_BeginAction : public UAnimNotify
{
GENERATED_BODY()
public:
FString GetNotifyName_Implementation() const override;
void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation) override;
};
#include "Notifies/CAnimNotify_BeginAction.h"
#include "Global.h"
#include "Components/CWeaponComponent.h"
#include "Weapons/CDoAction.h"
FString UCAnimNotify_BeginAction::GetNotifyName_Implementation() const
{
return "Begin_DoAction";
}
void UCAnimNotify_BeginAction::Notify(USkeletalMeshComponent * MeshComp, UAnimSequenceBase * Animation)
{
Super::Notify(MeshComp, Animation);
CheckNull(MeshComp);
CheckNull(MeshComp->GetOwner());
UCWeaponComponent* weapon = CHelpers::GetComponent<UCWeaponComponent>(MeshComp->GetOwner());
CheckNull(weapon);
CheckNull(weapon->GetDoAction());
// DoAction을 가져다가 Begin_DoAction을 콜해준다.
weapon->GetDoAction()->Begin_DoAction();
}
1. 액션의 시작을 알리는 노티파이, 동작을 실행하는 것이므로, DoAction -> Begin_DoAction을 콜해주면된다.
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimNotifies/AnimNotify.h"
#include "CAnimNotify_EndAction.generated.h"
UCLASS()
class U2212_06_API UCAnimNotify_EndAction : public UAnimNotify
{
GENERATED_BODY()
public:
FString GetNotifyName_Implementation() const override;
void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation) override;
};
#include "Notifies/CAnimNotify_EndAction.h"
#include "Global.h"
#include "Components/CWeaponComponent.h"
#include "Weapons/CDoAction.h"
FString UCAnimNotify_EndAction::GetNotifyName_Implementation() const
{
return "End_DoAction";
}
void UCAnimNotify_EndAction::Notify(USkeletalMeshComponent * MeshComp, UAnimSequenceBase * Animation)
{
Super::Notify(MeshComp, Animation);
CheckNull(MeshComp);
CheckNull(MeshComp->GetOwner());
UCWeaponComponent* weapon = CHelpers::GetComponent<UCWeaponComponent>(MeshComp->GetOwner());
CheckNull(weapon);
CheckNull(weapon->GetDoAction());
// DoAction을 가져다가 End_DoAction을 콜해준다.
weapon->GetDoAction()->End_DoAction();
}
1. Begin_DoAction과 반대로, 액션 끝을 알리는 노티파이로 DoAction을 가져다가 End_DoAction을 콜해준다.
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimNotifies/AnimNotifyState.h"
#include "CAnimNotifyState_Combo.generated.h"
UCLASS()
class U2212_06_API UCAnimNotifyState_Combo : public UAnimNotifyState
{
GENERATED_BODY()
public:
FString GetNotifyName_Implementation() const override;
virtual void NotifyBegin(USkeletalMeshComponent * MeshComp, UAnimSequenceBase * Animation, float TotalDuration) override;
virtual void NotifyEnd(USkeletalMeshComponent * MeshComp, UAnimSequenceBase * Animation) override;
};
#include "Notifies/CAnimNotifyState_Combo.h"
#include "Global.h"
#include "Components/CWeaponComponent.h"
#include "Weapons/DoActions/CDoAction_Combo.h"
FString UCAnimNotifyState_Combo::GetNotifyName_Implementation() const
{
return "Combo";
}
void UCAnimNotifyState_Combo::NotifyBegin(USkeletalMeshComponent * MeshComp, UAnimSequenceBase * Animation, float TotalDuration)
{
Super::NotifyBegin(MeshComp, Animation, TotalDuration);
CheckNull(MeshComp);
CheckNull(MeshComp->GetOwner());
UCWeaponComponent* weapon = CHelpers::GetComponent<UCWeaponComponent>(MeshComp->GetOwner());
CheckNull(weapon);
CheckNull(weapon->GetDoAction());
UCDoAction_Combo* combo = Cast<UCDoAction_Combo>(weapon->GetDoAction());
CheckNull(combo);
combo->EnableCombo();
}
void UCAnimNotifyState_Combo::NotifyEnd(USkeletalMeshComponent * MeshComp, UAnimSequenceBase * Animation)
{
Super::NotifyEnd(MeshComp, Animation);
CheckNull(MeshComp);
CheckNull(MeshComp->GetOwner());
UCWeaponComponent* weapon = CHelpers::GetComponent<UCWeaponComponent>(MeshComp->GetOwner());
CheckNull(weapon);
CheckNull(weapon->GetDoAction());
UCDoAction_Combo* combo = Cast<UCDoAction_Combo>(weapon->GetDoAction());
CheckNull(combo);
combo->DisableCombo();
}
1. 이제 동작이 연달아 필요하므로, State로 노티파이를 만들어준다.
2. DoAction을 체크한다는건 액션이 시작됐다는걸 알 수 있으므로, 체크 후 콤보동작을 연결시켜준다.
1. 몽타주로가서 만들어준 노티파이 Begin, End, Combo를 알맞은 위치에 배치해준다.
1. 조절할 수치가 있다면, 변경해주고 마무리해준다.
이제 공격모션을 만들었으므로, Hit가 되는지 판별하기 위해 Enemy를 생성해 줄 것이다.
#pragma once
#include "CoreMinimal.h"
#include "UObject/Interface.h"
#include "ICharacter.generated.h"
// 인터페이스 직렬화를 위한 기본코드 이므로 수정하면 안된다.
UINTERFACE(MinimalAPI)
class UICharacter : public UInterface
{
GENERATED_BODY()
};
public:
void Create_DynamicMaterial(class ACharacter* InCharacter);
void Change_Color(class ACharacter* InCharacter, FLinearColor InColor);
};
#include "Characters/ICharacter.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/SkeletalMeshComponent.h"
#include "Materials/MaterialInstanceDynamic.h"
void IICharacter::Create_DynamicMaterial(ACharacter * InCharacter)
{
// Mesh안에 있는 Materials 갯수만큼 다 가져와서 for문으로 돌려준다.
for (int32 i = 0; i < InCharacter->GetMesh()->GetMaterials().Num(); i++)
{
UMaterialInterface* material = InCharacter->GetMesh()->GetMaterials()[i];
// Material을 만들자마자 바로 세팅
InCharacter->GetMesh()->SetMaterial(i, UMaterialInstanceDynamic::Create(material, InCharacter));
}
}
void IICharacter::Change_Color(ACharacter * InCharacter, FLinearColor InColor)
{
// Material 인터페이스를 가져다가 for문으로 돌려준다.
for (UMaterialInterface* material : InCharacter->GetMesh()->GetMaterials())
{
UMaterialInstanceDynamic* instance = Cast<UMaterialInstanceDynamic>(material);
// null 체크후 색 세팅
if (!!instance)
instance->SetVectorParameterValue("BodyColor", InColor);
}
}
1. Enemy가 Hit 되었을때 색이 변경되는것은 인터페이스에다가 넣어서 사용할 것이다.
2. Material을 생성하자마자 세팅해준다.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
#include "Characters/ICharacter.h"
#include "CEnemy.generated.h"
UCLASS()
class U2212_06_API ACEnemy
: public ACharacter
, public IICharacter
{
GENERATED_BODY()
private:
// 자신의 색상 세팅.
UPROPERTY(EditAnywhere, Category = "Color")
FLinearColor OriginColor = FLinearColor::White;
private:
// 기본 Enemy에도 필요한 것, Player가 아니므로 Camera, SpringArm은 x
UPROPERTY(VisibleAnywhere)
class UCWeaponComponent* Weapon;
UPROPERTY(VisibleAnywhere)
class UCMontagesComponent* Montages;
UPROPERTY(VisibleAnywhere)
class UCMovementComponent* Movement;
UPROPERTY(VisibleAnywhere)
class UCStateComponent* State;
public:
ACEnemy();
protected:
virtual void BeginPlay() override;
private:
UFUNCTION()
void OnStateTypeChanged(EStateType InPrevType, EStateType InNewType);
};
#include "Characters/CEnemy.h"
#include "Global.h"
#include "CAnimInstance.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/CWeaponComponent.h"
#include "Components/CMontagesComponent.h"
#include "Components/CMovementComponent.h"
ACEnemy::ACEnemy()
{
// 아래부분은 Player과 동일하게 가지고 있다.
// 생성
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);
GetCharacterMovement()->RotationRate = FRotator(0, 720, 0);
}
void ACEnemy::BeginPlay()
{
Super::BeginPlay();
Movement->OnWalk();
// 색을 세팅해주면서, 시작하면 자신이 설정한 색이 적용된다.
Create_DynamicMaterial(this);
Change_Color(this, OriginColor);
State->OnStateTypeChanged.AddDynamic(this, &ACEnemy::OnStateTypeChanged);
}
void ACEnemy::OnStateTypeChanged(EStateType InPrevType, EStateType InNewType)
{
}
1. Player와 동일하게 가지고 있어야할 기본적인 구조를 만들어준다.
2. Begin이 될때 자신이 설정한 색상을 세팅해준다.
1. 블루프린트 클래스를 만들어준 Enemy로 생성해준다.
2. 설정한 세팅들이 잘 들어와있는걸 확인할 수 있다.
3. Enemy를 맵위에 올려준다.
이제 충돌처리를 위한 작업을 할 것이다. Shape로 하위 충돌체들을 체크해 줄 것이다.
#pragma once
#include "CoreMinimal.h"
#include "UObject/NoExportTypes.h"
#include "Weapons/CWeaponStructures.h"
#include "CDoAction.generated.h"
UCLASS(Abstract) // 객체화 되면 안되므로 Abstract
class U2212_06_API UCDoAction : public UObject
{
GENERATED_BODY()
public:
UFUNCTION()
virtual void OnAttachmentBeginCollision() { } // 재정의 용도, 충돌체가 켜졌을때
UFUNCTION()
virtual void OnAttachmentEndCollision() { } // 재정의 용도, 충돌체가 꺼졌을때
// 자신의 DoAction에서 어떻게 처리할지 모르기 때문에 {} 안에를 비워둔다.
UFUNCTION()
virtual void OnAttachmentBeginOverlap(class ACharacter* InAttacker, AActor* InAttackCuaser, class ACharacter* InOther) { }
UFUNCTION()
virtual void OnAttachmentEndOverlap(class ACharacter* InAttacker, class ACharacter* InOther) { }
};
1. 충돌에 대한 On, Off를 재정의 할 수 있게 만들어 놓는다.
#include "Weapons/CWeaponAsset.h"
#include "Global.h"
#include "CAttachment.h"
#include "CEquipment.h"
#include "CDoAction.h"
#include "GameFramework/Character.h"
void UCWeaponAsset::BeginPlay(ACharacter * InOwner)
{
if (!!DoActionClass)
{
// DoAction 생성
DoAction = NewObject<UCDoAction>(this, DoActionClass);
DoAction->BeginPlay(Attachment, Equipment, InOwner, DoActionDatas);
if (!!Attachment)
{
// null이 아니라면, Attachment에 DoAction꺼를 다 연결해준다.
Attachment->OnAttachmentBeginCollision.AddDynamic(DoAction, &UCDoAction::OnAttachmentBeginCollision);
Attachment->OnAttachmentEndCollision.AddDynamic(DoAction, &UCDoAction::OnAttachmentEndCollision);
Attachment->OnAttachmentBeginOverlap.AddDynamic(DoAction, &UCDoAction::OnAttachmentBeginOverlap);
Attachment->OnAttachmentEndOverlap.AddDynamic(DoAction, &UCDoAction::OnAttachmentEndOverlap);
}
}
}
1. CWeaponAsset.cpp에 만들어 놓은 충돌관련된 이벤트를 연결시켜준다.
#pragma once
#include "CoreMinimal.h"
#include "Weapons/CDoAction.h"
#include "CDoAction_Combo.generated.h"
UCLASS()
class U2212_06_API UCDoAction_Combo : public UCDoAction
{
GENERATED_BODY()
public:
// 직렬화 표시를 안해줘도 상속된 부분을 가져왔기 때문에 직렬화가 되어있다.
void OnAttachmentBeginOverlap(class ACharacter* InAttacker, AActor* InAttackCuaser, class ACharacter* InOther) override;
};
#include "Weapons/DoActions/CDoAction_Combo.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
void UCDoAction_Combo::OnAttachmentBeginOverlap(ACharacter* InAttacker, AActor* InAttackCauser, ACharacter* InOther)
{
Super::OnAttachmentBeginOverlap(InAttacker, InAttackCauser, InOther);
CheckNull(InOther);
CLog::Log(InOther->GetName());
}
1. DoAction에 이벤트를 Override해서 다시 재정의 해준다.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Actor.h"
#include "CAttachment.generated.h"
// 충돌 On, Off
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FAttachmentBeginCollision);
DECLARE_DYNAMIC_MULTICAST_DELEGATE(FAttachmentEndCollision);
// Begin, End
DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FAttachmentBeginOverlap, class ACharacter*, InAttacker, AActor*, InAttackCuaser, class ACharacter*, InOther);
DECLARE_DYNAMIC_MULTICAST_DELEGATE_TwoParams(FAttachmentEndOverlap, class ACharacter*, InAttacker, class ACharacter*, InOther);
UCLASS()
class U2212_06_API ACAttachment : public AActor
{
GENERATED_BODY()
protected:
// 블루프린트에서 접근 가능, 컴포넌트기 때문에 VisibleAnywhere 붙인다.
UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
// 어느곳에 붙을지 모르기 때문에 USceneComponent Root 기준으로 잡는다.
class USceneComponent* Root;
public:
ACAttachment();
protected:
virtual void BeginPlay() override;
public:
// 델리게이션 연결, BP에서 수정할 수 있도록.
UFUNCTION(BlueprintImplementableEvent)
void OnBeginEquip();
UFUNCTION(BlueprintImplementableEvent)
void OnUnequip();
public:
// 충돌 On, Off
void OnCollisions();
void OffCollisions();
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);
protected:
// BP안에 붙이는 함수도 있지만, 필요한것만 사용하는게 좋으므로, BP에서 사용할 수 있도록 만들어준다.
UFUNCTION(BlueprintCallable, Category = "Attach")
void AttachTo(FName InSocketName);
public:
// 충돌에 필요한 변수들.
FAttachmentBeginCollision OnAttachmentBeginCollision;
FAttachmentEndCollision OnAttachmentEndCollision;
FAttachmentBeginOverlap OnAttachmentBeginOverlap;
FAttachmentEndOverlap OnAttachmentEndOverlap;
protected:
// BP 자식에서 Owner에 접근할수도 있기 때문에 BlueprintReadOnly
UPROPERTY(BlueprintReadOnly, Category = "Game")
class ACharacter* OwnerCharacter;
// BP에서 접근할수도 있고, 충돌체가 몇개 나올지 모르므로 배열로 받는다.
UPROPERTY(BlueprintReadOnly, Category = "Game")
TArray<class UShapeComponent*> Collisions;
};
#include "Weapons/CAttachment.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/SceneComponent.h"
#include "Components/ShapeComponent.h"
ACAttachment::ACAttachment()
{
CHelpers::CreateComponent(this, &Root, "Root");
}
void ACAttachment::BeginPlay()
{
// BP에서 BeginPlay이 먼저 호출되면 터진다.
// 먼저 세팅 후 부모를 불러줘야한다.
OwnerCharacter = Cast<ACharacter>(GetOwner());
TArray<USceneComponent*> children; // Scene로부터 붙을수 있다.
Root->GetChildrenComponents(true, children); // Root로부터 하위들을 찾는다.
for (USceneComponent* child : children)
{
UShapeComponent* shape = Cast<UShapeComponent>(child);
if (!!shape)
{
// TODO : 충돌 이벤트 연결
shape->OnComponentBeginOverlap.AddDynamic(this, &ACAttachment::OnComponentBeginOverlap);
shape->OnComponentEndOverlap.AddDynamic(this, &ACAttachment::OnComponentEndOverlap);
Collisions.Add(shape);
}
}
Super::BeginPlay();
}
void ACAttachment::OnCollisions()
{
// 가지고있는 맴버를 확인하면서 On
// 연결되어있는 이벤트를 먼저 콜해준다.
if (OnAttachmentBeginCollision.IsBound())
OnAttachmentBeginCollision.Broadcast();
for (UShapeComponent* shape : Collisions)
shape->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);
}
void ACAttachment::OffCollisions()
{
// 가지고있는 맴버를 확인하면서 Off
// 연결되어있는 이벤트를 먼저 콜해준다.
if (OnAttachmentEndCollision.IsBound())
OnAttachmentEndCollision.Broadcast();
for (UShapeComponent* shape : Collisions)
shape->SetCollisionEnabled(ECollisionEnabled::NoCollision);
}
void ACAttachment::OnComponentBeginOverlap(UPrimitiveComponent * OverlappedComponent, AActor * OtherActor, UPrimitiveComponent * OtherComp, int32 OtherBodyIndex, bool bFromSweep, const FHitResult & SweepResult)
{
CheckTrue(OwnerCharacter == OtherActor); // 자신과 공격하려는 객체가 같은지 체크
CheckTrue(OwnerCharacter->GetClass() == OtherActor->GetClass()); // 두개의 클래스 타입이 같으면 아군이므로 체크
if (OnAttachmentBeginOverlap.IsBound())
OnAttachmentBeginOverlap.Broadcast(OwnerCharacter, this, Cast<ACharacter>(OtherActor));
}
void ACAttachment::OnComponentEndOverlap(UPrimitiveComponent * OverlappedComponent, AActor * OtherActor, UPrimitiveComponent * OtherComp, int32 OtherBodyIndex)
{
CheckTrue(OwnerCharacter == OtherActor);
CheckTrue(OwnerCharacter->GetClass() == OtherActor->GetClass());
if (OnAttachmentEndOverlap.IsBound())
OnAttachmentEndOverlap.Broadcast(OwnerCharacter, Cast<ACharacter>(OtherActor));
}
void ACAttachment::AttachTo(FName InSocketName)
{
// 플레이어 Mesh, 소켓 생성된 부위 지정, Sword 장착
AttachToComponent(OwnerCharacter->GetMesh(), FAttachmentTransformRules(EAttachmentRule::KeepRelative, true), InSocketName);
}
1. 충돌이 처리되는 부분은 어디 부분이 될 것이냐면, DoAction이 어떤 행동을 하게되면 노티파이로 인해 콜리전이 켜진다.
그 상태에서 충돌을 하게되면, 실제로 DoAction안에 해당 공격에 대한 데미지 정보가 들어가있게 되는데 이 데이터를 가져다가 데미지를 주게 만들 것이다.
2. 그리하여 Attachment에 델리게이션 이벤트를 연결시키는 과정이 진행된 것이다.
#pragma once
#include "CoreMinimal.h"
#include "Animation/AnimNotifies/AnimNotifyState.h"
#include "CAnimNotifyState_Collision.generated.h"
UCLASS()
class U2212_06_API UCAnimNotifyState_Collision : public UAnimNotifyState
{
GENERATED_BODY()
public:
FString GetNotifyName_Implementation() const override;
virtual void NotifyBegin(USkeletalMeshComponent * MeshComp, UAnimSequenceBase * Animation, float TotalDuration) override;
virtual void NotifyEnd(USkeletalMeshComponent * MeshComp, UAnimSequenceBase * Animation) override;
};
#include "Notifies/CAnimNotifyState_Collision.h"
#include "Global.h"
#include "Components/CWeaponComponent.h"
#include "Weapons/CAttachment.h"
FString UCAnimNotifyState_Collision::GetNotifyName_Implementation() const
{
return "Collision";
}
void UCAnimNotifyState_Collision::NotifyBegin(USkeletalMeshComponent * MeshComp, UAnimSequenceBase * Animation, float TotalDuration)
{
Super::NotifyBegin(MeshComp, Animation, TotalDuration);
CheckNull(MeshComp);
CheckNull(MeshComp->GetOwner());
UCWeaponComponent* weapon = CHelpers::GetComponent<UCWeaponComponent>(MeshComp->GetOwner());
CheckNull(weapon);
CheckNull(weapon->GetAttachment());
weapon->GetAttachment()->OnCollisions();
}
void UCAnimNotifyState_Collision::NotifyEnd(USkeletalMeshComponent * MeshComp, UAnimSequenceBase * Animation)
{
Super::NotifyEnd(MeshComp, Animation);
CheckNull(MeshComp);
CheckNull(MeshComp->GetOwner());
UCWeaponComponent* weapon = CHelpers::GetComponent<UCWeaponComponent>(MeshComp->GetOwner());
CheckNull(weapon);
CheckNull(weapon->GetAttachment());
weapon->GetAttachment()->OffCollisions();
}
1. 이제 이벤트를 통한 충돌이 필요하므로, 노티파이를 State로 생성해서 연결해준다.
1. 만들어 준 노티파이를 알맞은 위치에 설정해준다.
1. 충돌체가 필요하므로, Capsule를 추가해준다.
1. 이제 공격을해서 Hit가 되면, 로그가 출력되는걸 확인 할 수 있다.
ActorClass안에 보면 TakeDamage라는 함수가 있다. 이 함수로 공격하는것과 맞는거 둘다 처리를 할 수 있다.
1. Engine안에 있는 정의된 함수.
2. Engine -> Actor.h 안에 재정의된 TakeDamage를 확인 할 수 있다.
#include "Weapons/DoActions/CDoAction_Combo.h"
#include "Global.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
void UCDoAction_Combo::OnAttachmentBeginOverlap(ACharacter* InAttacker, AActor* InAttackCauser, ACharacter* InOther)
{
Super::OnAttachmentBeginOverlap(InAttacker, InAttackCauser, InOther);
CheckNull(InOther);
//CLog::Log(InOther->GetName());
InOther->TakeDamage(20, FDamageEvent(), InAttacker->GetController(), InAttackCauser);
}
1. 로그를 출력했던 부분에 이제 충돌이 잘되고 있으니 주석처리를 하고, 가상함수를 재정의하여 충돌을 처리한다.
#pragma once
#include "CoreMinimal.h"
#include "GameFramework/Character.h"
#include "Components/CStateComponent.h"
#include "Characters/ICharacter.h"
#include "CEnemy.generated.h"
UCLASS()
class U2212_06_API ACEnemy
: public ACharacter
, public IICharacter
{
GENERATED_BODY()
public:
float TakeDamage(float DamageAmount, struct FDamageEvent const& DamageEvent, class AController* EventInstigator, AActor* DamageCauser) override;
};
#include "Characters/CEnemy.h"
#include "Global.h"
#include "CAnimInstance.h"
#include "GameFramework/CharacterMovementComponent.h"
#include "Components/SkeletalMeshComponent.h"
#include "Components/CWeaponComponent.h"
#include "Components/CMontagesComponent.h"
#include "Components/CMovementComponent.h"
float ACEnemy::TakeDamage(float DamageAmount, FDamageEvent const & DamageEvent, AController * EventInstigator, AActor * DamageCauser)
{
// 부모 콜을 해주고, 부모에서 처리된 데미지를 가지고와서 처리해줘야한다. (서버가 다 부모에 있기 때문)
float damage = Super::TakeDamage(DamageAmount, DamageEvent, EventInstigator, DamageCauser);
CLog::Print(damage);
return damage;
}
1. 재정의된 TakeDamage를 Hit되는 Enemy에서 정의해준다.
https://www.youtube.com/watch?v=USYb4Z_VXGI
'언리얼' 카테고리의 다른 글
UE4 Hit Effect, Status Component, Hammer (2) | 2023.05.10 |
---|---|
UE4 HitData, Effect, Sound, HitStop (0) | 2023.05.09 |
UE4 Equip, DoAction (2) | 2023.05.04 |
UE4 Weapon Attach, Sword Equip (0) | 2023.05.01 |
UE4 Notify, Attach, Weapon (0) | 2023.04.28 |