목차

     

     


     

     

     

     
    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 추가

     

     


     

     

    실행화면