목차

     

     


     

     

     
    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 
    CAnimNotify_CameraShake.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
     

     

     

     

    주먹 공격 구현하기

     

     


     

    CPlayer

     

    CPlayer.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "GameFramework/Character.h"
    #include "Components/CStateComponent.h"
    #include "Characters/ICharacter.h"
    #include "CPlayer.generated.h"
    
    UCLASS()
    class U2212_06_API ACPlayer
    	: public ACharacter, public IICharacter //다중상속
    {
    	GENERATED_BODY()
    
    private:
    	UPROPERTY(VisibleAnywhere)
    		class USpringArmComponent* SpringArm;
    
    	UPROPERTY(VisibleAnywhere)
    		class UCameraComponent* Camera;
    
    private:
    	UPROPERTY(VisibleAnywhere)
    		class UCWeaponComponent* Weapon;
    
    	UPROPERTY(VisibleAnywhere)
    		class UCMontagesComponent* Montages;
    
    	UPROPERTY(VisibleAnywhere)
    		class UCMovementComponent* Movement;
    
    	UPROPERTY(VisibleAnywhere)
    		class UCStateComponent* State;
    
    public:
    	ACPlayer();
    
    protected:
    	virtual void BeginPlay() override;
    
    public:	
    	virtual void SetupPlayerInputComponent(class UInputComponent* PlayerInputComponent) override;
    
    private:
    	UFUNCTION()
    		void OnStateTypeChanged(EStateType InPrevType, EStateType InNewType);
    
    private:
    	void OnAvoid();
    
    private:
    	void BackStep();
    
    public:
    	void End_BackStep() override;//ICharacter의 함수 오버라이드
    };

    변동사항 없음.

     

     

     

    CPlayer.cpp

    더보기
    #include "Characters/CPlayer.h"
    #include "Global.h"
    #include "CAnimInstance.h"
    #include "GameFramework/SpringArmComponent.h"
    #include "GameFramework/CharacterMovementComponent.h"
    #include "Camera/CameraComponent.h"
    #include "Components/SkeletalMeshComponent.h"
    #include "Components/InputComponent.h"
    #include "Components/CMontagesComponent.h"
    #include "Components/CMovementComponent.h"
    #include "Components/CWeaponComponent.h"
    
    ACPlayer::ACPlayer()
    {
    	CHelpers::CreateComponent<USpringArmComponent>(this, &SpringArm, "SpringArm", GetMesh());
    	CHelpers::CreateComponent<UCameraComponent>(this, &Camera, "Camera", SpringArm);
    
    	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);
    
    	SpringArm->SetRelativeLocation(FVector(0, 0, 140));
    	SpringArm->SetRelativeRotation(FRotator(0, 90, 0));
    	SpringArm->TargetArmLength = 200;
    	SpringArm->bDoCollisionTest = false;
    	SpringArm->bUsePawnControlRotation = true;
    	SpringArm->bEnableCameraLag = true;
    
    	GetCharacterMovement()->RotationRate = FRotator(0, 720, 0);
    
    }
    
    void ACPlayer::BeginPlay()
    {
    	Super::BeginPlay();
    
    	Movement->OnRun(); //Movement의 기본을 Run으로 설정
    	Movement->DisableControlRotation();//Movement의 기본을 DisableControlRotation으로 설정
    
    	State->OnStateTypeChanged.AddDynamic(this, &ACPlayer::OnStateTypeChanged);
    }
    
    void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
    {
    	Super::SetupPlayerInputComponent(PlayerInputComponent);
    
    	PlayerInputComponent->BindAxis("MoveForward", Movement, &UCMovementComponent::OnMoveForward);
    	PlayerInputComponent->BindAxis("MoveRight", Movement, &UCMovementComponent::OnMoveRight);
    	PlayerInputComponent->BindAxis("VerticalLook", Movement, &UCMovementComponent::OnVerticalLook);
    	PlayerInputComponent->BindAxis("HorizontalLook", Movement, &UCMovementComponent::OnHorizontalLook);
    
    	PlayerInputComponent->BindAction("Sprint", EInputEvent::IE_Pressed, Movement, &UCMovementComponent::OnSprint);
    	PlayerInputComponent->BindAction("Sprint", EInputEvent::IE_Released, Movement, &UCMovementComponent::OnRun);
    
    	PlayerInputComponent->BindAction("Avoid", EInputEvent::IE_Pressed, this, &ACPlayer::OnAvoid);
    
    	PlayerInputComponent->BindAction("Fist", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetFistMode);
    	PlayerInputComponent->BindAction("Sword", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetSwordMode);
    	PlayerInputComponent->BindAction("Hammer", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetHammerMode);
    
    	PlayerInputComponent->BindAction("Action", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::DoAction);
    }
    
    void ACPlayer::OnStateTypeChanged(EStateType InPrevType, EStateType InNewType)
    {
    	switch (InNewType)
    	{
    		case EStateType::BackStep: BackStep(); break;
    	}
    }
    
    void ACPlayer::OnAvoid()
    {
    	CheckFalse(State->IsIdleMode());
    	CheckFalse(Movement->CanMove());
    
    	CheckTrue(InputComponent->GetAxisValue("MoveForward") >= 0.0f);//뒷방향을 입력했다면
    
    	State->SetBackStepMode();//State을 BackStepMode로 변경한다.
    }
    
    void ACPlayer::BackStep()
    {
    	Movement->EnableControlRotation();//정면을 바라본 상태로 뒤로 뛰어야하기 때문에 EnableControlRotation으로 만들어준다.
    
    	Montages->PlayBackStepMode();//PlayBackStepMode()를 통해 몽타주 재생.
    }
    
    void ACPlayer::End_BackStep()
    {
    	Movement->DisableControlRotation();//Backstep이 끝나면 원래대로 돌려준다.
    
    	State->SetIdleMode();//Idle상태로 돌려줌.
    }

    Fist 버튼 할당

    • void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent) {
      PlayerInputComponent->BindAction("Fist", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetFistMode);   }

     

     


     

    CAttachment

     

    CAttachment.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "GameFramework/Actor.h"
    #include "CAttachment.generated.h"
    
    DECLARE_DYNAMIC_MULTICAST_DELEGATE(FAttachmentBeginCollision);
    DECLARE_DYNAMIC_MULTICAST_DELEGATE(FAttachmentEndCollision);
    
    DECLARE_DYNAMIC_MULTICAST_DELEGATE_ThreeParams(FAttachmentBeginOverlap, class ACharacter*, InAttacker, AActor*, InAttackCauser, 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:
    	UPROPERTY(BlueprintReadOnly, VisibleAnywhere)
    		class USceneComponent* Root;
    	
    public:	
    	ACAttachment();
    
    protected:
    	virtual void BeginPlay() override;
    
    public:
    	UFUNCTION(BlueprintImplementableEvent)
    		void OnBeginEquip();
    
    	UFUNCTION(BlueprintImplementableEvent)
    		void OnUnequip();
    
    public:
    	void OnCollisions(); //Collision 켜기
    	void OffCollisions();//Collision 끄기
    
    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:
    	UFUNCTION(BlueprintCallable, Category = "Attach")
    		void AttachTo(FName InSocketName);
    
    	UFUNCTION(BlueprintCallable, Category = "Attach")
    		void AttachToCollision(FName InCollisionName);
    
    public:
    	FAttachmentBeginCollision OnAttachmentBeginCollision;
    	FAttachmentEndCollision OnAttachmentEndCollision;
    
    	FAttachmentBeginOverlap OnAttachmentBeginOverlap;
    	FAttachmentEndOverlap OnAttachmentEndOverlap;
    
    protected:
    	UPROPERTY(BlueprintReadOnly, Category = "Game")
    		class ACharacter* OwnerCharacter;
    
    	//UShapeComponent는 UBox,Capsule,SphereComponent의 상위클래스
    	UPROPERTY(BlueprintReadOnly, Category = "Game")
    		TArray<class UShapeComponent*> Collisions;
    };

    함수 생성

    • UFUNCTION(BlueprintCallable, Category = "Attach")
      void AttachToCollision(FName InCollisionName);
      • UFUNCTION을 붙여 직렬화해준다.

     

     

     

    CAttachment.cpp

    더보기
    #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()
    {
    	OwnerCharacter = Cast<ACharacter>(GetOwner());
    
    	TArray<USceneComponent*> children;//최종 부모는 SceneComponent다.
    	Root->GetChildrenComponents(true, children);
    	for (USceneComponent* child : children)
    	{
    		UShapeComponent* shape = Cast<UShapeComponent>(child);
    
    		if(!!shape)//shape이 있다면
    		{
    			//충돌 이벤트 연결
    			shape->OnComponentBeginOverlap.AddDynamic(this, &ACAttachment::OnComponentBeginOverlap);
    			shape->OnComponentEndOverlap.AddDynamic(this, &ACAttachment::OnComponentEndOverlap);
    
    			Collisions.Add(shape);//Collsions배열에 shape 추가
    		}
    		OffCollisions();//처음 시작할 때 collision을 꺼준다.
    	}
    
    	//ACharacter를 먼저 Cast 한 후에 Super::BeginPlay() 호출.
    	Super::BeginPlay();
    }
    
    void ACAttachment::OnCollisions()
    {
    	//Pre (충돌체가 켜지기 전에 작업)
    	if (OnAttachmentBeginCollision.IsBound())
    		OnAttachmentBeginCollision.Broadcast();//연결되어 있는것 이벤트콜
    
    	for (UShapeComponent* shape : Collisions)//Collisions배열의 for문
    		shape->SetCollisionEnabled(ECollisionEnabled::QueryAndPhysics);//Collision을 QueryAndPhysics 설정.
    }
    
    void ACAttachment::OffCollisions()
    {
    	//Pre (충돌체가 꺼지기 전에 작업)
    	if (OnAttachmentEndCollision.IsBound())
    		OnAttachmentEndCollision.Broadcast();//연결되어 있는것 이벤트콜
    
    	for (UShapeComponent* shape : Collisions)
    		shape->SetCollisionEnabled(ECollisionEnabled::NoCollision);//Collision을 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());//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());//GetClass()가 같다는 것은 아군이라는 의미
    
    	if (OnAttachmentEndOverlap.IsBound())
    		OnAttachmentEndOverlap.Broadcast(OwnerCharacter, Cast<ACharacter>(OtherActor));
    }
    
    void ACAttachment::AttachTo(FName InSocketName)
    {
    	AttachToComponent(OwnerCharacter->GetMesh(), FAttachmentTransformRules(EAttachmentRule::KeepRelative, true), InSocketName);
    }
    
    void ACAttachment::AttachToCollision(FName InCollisionName)
    {
    	for (UShapeComponent* collision : Collisions)
    	{
    		if (collision->GetName() == InCollisionName.ToString())
    		{
    			collision->AttachToComponent(OwnerCharacter->GetMesh(), FAttachmentTransformRules(EAttachmentRule::KeepRelative, true), InCollisionName);
    
    			return;
    		}
    	}
    }

    함수 정의

    • void ACAttachment::AttachToCollision(FName InCollisionName) {
      for (UShapeComponent* collision : Collisions)
      {  if (collision->GetName() == InCollisionName.ToString())
         { collision->AttachToComponent(OwnerCharacter->GetMesh(), FAttachmentTransformRules (EAttachmentRule::KeepRelative, true), InCollisionName);

         return; }
      }  }

     


     

     

     

    BP_CAttachment_Fist  생성

     

    BP_CAttachment_Sword를 복사하여 BP_CAttachment_Fist  생성

     

    • 양쪽 주먹과 발에 사용할 Sphere Collision 4개를 만들어 Root 아래에 달아준다.

     

     

     

    Event Graph

     

    ※ 주의

    • for Each Loop로 Children Components를 불러온다면
    • 상위 요소가 사라지면서 다음 요소가 제대로 불려지지 않는 문제가 발생할 수 있다.
    • 그래서 for Each Loop 대신 Reverse for Each Loop를 사용해야 한다.
    • 중간 삭제가 일어나는 것들은 for문을 거꾸로 돌려줘야 한다.
    • ex. TArray

     


     

     

    DA_Fist 생성

     

     


     

     

     

     

     

     

    Camera Shake 구현하기

     

     


     

    몽타주 수정

     

    Fist_Attack 1, 2, 3

    • Notify 할당
      • Begin_DoAction, End_DoAction
      • Camera Shake
    • NotifyState 할당
      • Combo
      • Collision

     

     

    Fist_Hitted

    • End State 할

     

     

     


     

    CS_Fist 생성

     

    새 블루프린트 클래스 - Martinee Camera - CS_Fist 생성

     


     

     

    CAnimNotify_CameraShake 생성

     

    새 C++ 클래스 - AnimNotify - CAnimNotify_CameraShake 생성

     

     

    CAnimNotify_CameraShake.h

    더보기
    #pragma once
    
    #include "CoreMinimal.h"
    #include "Animation/AnimNotifies/AnimNotify.h"
    #include "CAnimNotify_CameraShake.generated.h"
    
    UCLASS()
    class U2212_06_API UCAnimNotify_CameraShake : public UAnimNotify
    {
    	GENERATED_BODY()
    
    private:
    	UPROPERTY(EditAnywhere, Category = "CameraClass")
    		TSubclassOf<class UMatineeCameraShake> CameraShakeClass;
    
    public:
    	FString GetNotifyName_Implementation() const override;//Notify 이름을 지어주는 함수.
    
    	void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation) override;
    };

     

     

     

    CAnimNotify_CameraShake.cpp

    더보기
    #include "Notifies/CAnimNotify_CameraShake.h"
    #include "Global.h"
    #include "GameFramework/Character.h"
    #include "GameFramework/PlayerController.h"
    #include "Camera/CameraShake.h"
    
    FString UCAnimNotify_CameraShake::GetNotifyName_Implementation() const
    {
    	return "CameraShake";//Notify이름을 CameraShake으로 설정.
    }
    
    void UCAnimNotify_CameraShake::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation)
    {
    	Super::Notify(MeshComp, Animation);
    	CheckNull(MeshComp);//MeshComp 있는지 체크
    	CheckNull(MeshComp->GetOwner());//MeshComp->GetOwner() 있는지 체크
    
    	ACharacter* character = Cast<ACharacter>(MeshComp->GetOwner());
    	CheckNull(character);
    
    	APlayerController* controller = character->GetController<APlayerController>();
    	CheckNull(controller);
    
    	controller->PlayerCameraManager->StartCameraShake(CameraShakeClass);
    }

     


     

     

    실행화면