[UE] 주먹 공격 및 카메라 흔들림(Camera Shake) 효과 구현

목차
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); }
실행화면

'⭐ Unreal Engine > UE RPG Weapon System' 카테고리의 다른 글
[UE] Hit Effect 구현, Status Component, Hammer 공격 구현 (0) | 2023.05.10 |
---|---|
[UE] Hit Data, Effect, Object Pooling(오브젝트 풀링) (0) | 2023.05.09 |
[UE] AnimNotify, DoAction (0) | 2023.05.08 |
[UE] 무기 장착 및 기본 공격하기 (0) | 2023.05.02 |
[UE] 무기 시스템 설계하기 (0) | 2023.05.01 |
댓글
이 글 공유하기
다른 글
-
[UE] Hit Effect 구현, Status Component, Hammer 공격 구현
[UE] Hit Effect 구현, Status Component, Hammer 공격 구현
2023.05.10 -
[UE] Hit Data, Effect, Object Pooling(오브젝트 풀링)
[UE] Hit Data, Effect, Object Pooling(오브젝트 풀링)
2023.05.09 -
[UE] AnimNotify, DoAction
[UE] AnimNotify, DoAction
2023.05.08 -
[UE] 무기 장착 및 기본 공격하기
[UE] 무기 장착 및 기본 공격하기
2023.05.02
댓글을 사용할 수 없습니다.