목차

     

     


     

     

     

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

     

     


     

     

    실행화면