초보 코린이의 성장 일지

UE4 AnimNotify, ComboState, TakeDamage 본문

언리얼

UE4 AnimNotify, ComboState, TakeDamage

코오린이 2023. 5. 8. 18:06

한번만 공격되는 상태이므로, 다시 예외처리를 해주고 콤보 동작을 만들어 보겠다.

더보기
#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을 체크한다는건 액션이 시작됐다는걸 알 수 있으므로, 체크 후 콤보동작을 연결시켜준다.


Attack_1
Attack_2
Attack_3

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로 생성해서 연결해준다.


Attack_1
Attack_2
Attack_3

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
Comments