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);
}

 


 

 

실행화면