[UE] 파쿠르: 벽 오르기

파쿠르는 다음과 같은 과정을 통해 구현하였다. 먼저, 캐릭터 허리 높이 중앙에 있는 Arrow Component로 앞에 장애물 유무를 판단한다. 그 다음, Arrow Component 내 여러 개의 Line Trace로 장애물을 판단한다. Line Trace의 결과값을 바탕으로 어떤 파쿠르가 가능한지 판단한다. 마지막으로 Data Table에 기록된 몽타주를 찾아서 가져워 상황에 맞는 파쿠르 몽타주를 재생한다.
목차
Plugins |
||||
Weapon |
||||
Resource |
||||
Icon128.png weapon_thumbnail_icon.png |
||||
Source |
||||
Weapon | ||||
SWeaponCheckBoxes.h .cpp SWeaponDetailsView.h .cpp SWeaponDoActionData.h .cpp SWeaponEquipmentData.h .cpp SWeaponHitData.h .cpp SWeaponLeftArea.h .cpp Weapon.Build.cs WeaponAssetEditor.h .cpp WeaponAssetFactory.h .cpp WeaponCommand.h .cpp WeaponContextMenu.h .cpp WeaponModule.h .cpp WeaponStyle.h .cpp |
||||
Source | ||
U2212_06 | ||
Characters | ||
CAnimInstance.h .cpp CEnemy.h .cpp CPlayer.h .cpp ICharacter.h .cpp |
||
Components | ||
CMontagesComponent.h .cpp CMovementComponent.h .cpp CStateComponent.h .cpp CStatusComponent.h .cpp CWeaponComponent.h .cpp |
||
Notifies | ||
CAnimNotifyState_BeginAction.h .cpp CAnimNotifyState_BowString.h .cpp CAnimNotify_CameraShake.h .cpp CAnimNotify_End_Parkour 생성 CAnimNotifyState_EndAction.h .cpp CAnimNotify_EndState.h .cpp CAnimNotifyState.h .cpp CAnimNotifyState_CameraAnim.h .cpp CAnimNotifyState_Collision.h .cpp CAnimNotifyState_Combo.h .cpp CAnimNotifyState_Equip.h .cpp CAnimNotifyState_SubAction.h .cpp |
||
Parkour | ||
CParkourComponent.h .cpp | ||
Utilities | ||
CHelper.h CLog.h .cpp |
||
Weapons | ||
CArrow.h .cpp CAura.h .cpp CCamerModifier.h .cpp CGhostTrail.h .cpp CRotate_Object.h .cpp CThornObject.h .cpp CAnimInstance_Bow.h .cpp CAttachment_Bow.h .cpp CDoAction_Around.h .cpp CDoAction_Bow.h .cpp CDoAction_Combo.h .cpp CDoAction_Warp.h .cpp CSubAction_Around.h .cpp CSubAction_Bow.h .cpp CSubAction_Fist.h .cpp CSubAction_Hammer.h .cpp CSubAction_Sword.h .cpp CDoAction_Warp.h .cpp CAttachment.h .cpp CDoAction.h .cpp CEquipment.h .cpp CSubAction.h .cpp CWeaponAsset.h .cpp CWeaponStructures.h .cpp |
||
Global.h CGameMode.h .cpp U2212_06.Build.cs |
||
U2212_06.uproject | ||
파쿠르: 벽 오르기
CParkourComponent
CParkourComponent.h
#pragma once #include "CoreMinimal.h" #include "Components/ActorComponent.h" #include "Kismet/KismetSystemLibrary.h"//DrawDebug를 포함하는 헤더 #include "Engine/DataTable.h"//DataTable를 다루는 헤더 #include "CParkourComponent.generated.h" //파쿠르를 위해 추적할 화살표 타입 UENUM(BlueprintType) enum class EParkourArrowType : uint8 { Center = 0, Ceil, Floor, Left, Right, Land, Max, }; //파쿠르 동작 타입 UENUM(BlueprintType) enum class EParkourType : uint8 { Climb = 0, Fall, Slide, Short, Normal, Wall, Max, }; USTRUCT(BlueprintType) struct FParkourData : public FTableRowBase { GENERATED_BODY() public: UPROPERTY(EditAnywhere) EParkourType Type; UPROPERTY(EditAnywhere) UAnimMontage* Montage;//파쿠르 타입에 따라 Play할 몽타주 UPROPERTY(EditAnywhere) float PlayRatio = 1;//Play 속도 UPROPERTY(EditAnywhere) FName SectionName;//몽타주에 Section을 주면 해당 Section부터 재생. 이를 위한 변수 UPROPERTY(EditAnywhere) float MinDistance;//파쿠르가 수행될 최소거리 UPROPERTY(EditAnywhere) float MaxDistance;//파쿠르가 수행될 최대거리 UPROPERTY(EditAnywhere) float Extent;//부피, 상황에 따라 다르게 사용 UPROPERTY(EditAnywhere) bool bFixedCamera;//카메라 고정 여부 public: void PlayMontage(class ACharacter* InCharacter); }; UCLASS() class U2212_06_API UCParkourComponent : public UActorComponent { GENERATED_BODY() private: UPROPERTY(EditAnywhere, Category = "Data") UDataTable* DataTable;//파쿠르 DataTable private: UPROPERTY(EditAnywhere, Category = "Trace") float TraceDistance = 600;//파쿠르 Line Trace가 적용되는 거리 UPROPERTY(EditAnywhere, Category = "Trace") TEnumAsByte<EDrawDebugTrace::Type> DebugType; UPROPERTY(EditAnywhere, Category = "Trace") float AvailableFrontAngle = 15;//파쿠르 수행 제한각도 public: UCParkourComponent(); protected: virtual void BeginPlay() override; public: virtual void TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) override; private: void LineTrace(EParkourArrowType InType); private: //Arrow로 쏜 LineTrace를 체크하는 함수들 void CheckTrace_Center(); void CheckTrace_Ceil(); void CheckTrace_Floor(); void CheckTrace_LeftRight(); private: bool Check_Obstacle(); public: //파쿠르 수행 함수 void DoParkour(bool bLanded = false); void End_DoParkour(); private: bool Check_ClimbMode(); void DoParkour_Climb(); void End_DoParkour_Climb(); private: TMap<EParkourType, TArray<FParkourData>> DataMap;//TMap에 Key와 Key를 넣으면 배열이 리턴된다. private: class ACharacter* OwnerCharacter; class UArrowComponent* Arrows[(int32)EParkourArrowType::Max]; FHitResult HitResults[(int32)EParkourArrowType::Max];//Arrows 마다 충돌 결과를 저장할 배열 변수 private: AActor* HitObstacle; FVector HitObstacleExtent; float HitDistance; float ToFrontYaw; private: EParkourType Type = EParkourType::Max;//현재 수행중인 파쿠프 타입. 기본값을 Max로 설정하여 아무것도 하지 않는 타입을 기본값으로 만들어준다. };
CheckTrace 함수 추가(=Arrow로 쏜 LineTrace를 체크하는 함수들)
- void CheckTrace_Ceil();
- void CheckTrace_Floor();
- void CheckTrace_LeftRight();
장애물 여부를 판단하는 함수 추가
- bool Check_Obstacle();
파쿠르를 수행하는 함수 추가
- void DoParkour(bool bLanded = false);
- void End_DoParkour();
변수 추가
- EParkourType Type = EParkourType::Max;
- 파쿠르 타입의 기본값을 Max로 설정한다. Max는 파쿠르를 수행하지 않는 타입이다.
올라가기 파쿠르 함수 추가
- bool Check_ClimbMode();
- void DoParkour_Climb();
- void End_DoParkour_Climb();
CParkourComponent.cpp
#include "Parkour/CParkourComponent.h" #include "Global.h" #include "GameFramework/Character.h" #include "GameFramework/CharacterMovementComponent.h" #include "Components/ArrowComponent.h" #define LOG_UCParkourComponent void FParkourData::PlayMontage(class ACharacter* InCharacter) { InCharacter->PlayAnimMontage(Montage, PlayRatio, SectionName); } /////////////////////////////////////////////////////////////////////////////// UCParkourComponent::UCParkourComponent() { PrimaryComponentTick.bCanEverTick = true; CHelpers::GetAsset<UDataTable>(&DataTable, "DataTable'/Game/Parkour/DT_Parkour.DT_Parkour'");//DataTable 생성. } void UCParkourComponent::BeginPlay() { Super::BeginPlay(); TArray<FParkourData*> datas;//FParkourData 사용하여 파쿠르 관련 변수들을 담는 구조체 사용. DataTable->GetAllRows<FParkourData>("", datas);//DataTable에서 데이터를 가져온다. for (int32 i = 0; i < (int32)EParkourType::Max; i++) { TArray<FParkourData> temp;//FParkourData 배열 temp 생성. for(FParkourData* data : datas)//datas를 순회하여 검색 { if (data->Type == (EParkourType)i)//데이터의 타입 == UENUM인 EParkourType 이라면 temp.Add(*data);//해당 파쿠르 타입을 temp에 담는다. DataMap.Add((EParkourType)i, temp);//DataMap에 Key에 파쿠르 타입을 숫자로, Value에 FParkourData 배열 temp를 담는다. } } OwnerCharacter = Cast<ACharacter>(GetOwner());//해당 클래스를 가지고 있는 GetOwner인 캐릭터(여기서는 Player) OwnerCharacter로 설정. USceneComponent* arrow = CHelpers::GetComponent<USceneComponent>(OwnerCharacter, "ArrowGroup");//Arrows를 가져온다(=OwnerCharacter의 ArrowGroup을 가져온다). TArray<USceneComponent*> components;//components 변수에 SceneComponent들(=Arrows)을 가져와 담는다. arrow->GetChildrenComponents(false, components); for (int32 i = 0; i < (int32)EParkourArrowType::Max; i++) Arrows[i] = Cast<UArrowComponent>(components[i]);//Arrows[] 배열 변수에 components인 Arrows를 담는다. } void UCParkourComponent::TickComponent(float DeltaTime, ELevelTick TickType, FActorComponentTickFunction* ThisTickFunction) { Super::TickComponent(DeltaTime, TickType, ThisTickFunction); //값 초기화 HitObstacle = NULL; HitObstacleExtent = FVector::ZeroVector; HitDistance = 0; ToFrontYaw = 0; CheckTrace_Center(); if (!!HitObstacle)//HitObstacle이 있다면(=CheckTrace_Center의 hitResult가 있다면) { //나머지 Arrow들로도 LineTrace 검사한다. CheckTrace_Ceil(); CheckTrace_Floor(); CheckTrace_LeftRight(); } } void UCParkourComponent::LineTrace(EParkourArrowType InType) { UArrowComponent* arrow = Arrows[(int32)InType];//Trace할 화살을 가져온다. FLinearColor color = FLinearColor(arrow->ArrowColor); FTransform transform = arrow->GetComponentToWorld();//arrow의 위치를 가져온다. //위치를 활용하여 길이를 만든다. FVector start = transform.GetLocation(); FVector end = start + OwnerCharacter->GetActorForwardVector() * TraceDistance; TArray<AActor*> ignores;//Line Trace 시 무시할 것들을 담는 변수 ignores.Add(OwnerCharacter);//OwnerCharacter는 Line Trace에서 무시되게 한다. UKismetSystemLibrary::LineTraceSingle(GetWorld(), start, end, ETraceTypeQuery::TraceTypeQuery3, false, ignores, DebugType, HitResults[(int32)InType], true, color, FLinearColor::White);//TraceTypeQuery3는 새로 만든 TraceChannel인 Parkour다. } void UCParkourComponent::CheckTrace_Center() { EParkourArrowType type = EParkourArrowType::Center; LineTrace(type); const FHitResult& hitResult = HitResults[(int32)type]; CheckFalse(hitResult.bBlockingHit); //StaticMesh가 충돌체가 되므로 StaticMesh를 변수로 두고 StaticMesh와의 충돌 여부를 체크한다. UStaticMeshComponent* mesh = CHelpers::GetComponent<UStaticMeshComponent>(hitResult.GetActor()); CheckNull(mesh); HitObstacle = hitResult.GetActor(); FVector minBound, maxBound; mesh->GetLocalBounds(minBound, maxBound);//부피 float x = FMath::Abs(minBound.X - maxBound.X); float y = FMath::Abs(minBound.Y - maxBound.Y); float z = FMath::Abs(minBound.Z - maxBound.Z); HitObstacleExtent = FVector(x, y, z); HitDistance = hitResult.Distance;//충돌체까지의 거리 //충돌체에 대한 Normal을 뒤집는다. Player는 밖에서 안을 바라보기 때문에 -로 값을 뒤집는다. ToFrontYaw = UKismetMathLibrary::MakeRotFromX(-hitResult.ImpactNormal).Yaw; #ifdef LOG_UCParkourComponent CLog::Print(HitObstacle, 10); CLog::Print(HitObstacleExtent, 11); CLog::Print(HitDistance, 12); CLog::Print(ToFrontYaw, 13); #endif //LOG_UCParkourComponent } void UCParkourComponent::CheckTrace_Ceil() { LineTrace(EParkourArrowType::Ceil); } void UCParkourComponent::CheckTrace_Floor() { LineTrace(EParkourArrowType::Floor); } void UCParkourComponent::CheckTrace_LeftRight() { LineTrace(EParkourArrowType::Left); LineTrace(EParkourArrowType::Right); } bool UCParkourComponent::Check_Obstacle() { CheckNullResult(HitObstacle, false);//HitObstacle이 null이 아닌지 체크 //Arrow Center, Left, Right 모두 Hit되는지 체크. bool b = true; b &= HitResults[(int32)EParkourArrowType::Center].bBlockingHit; b &= HitResults[(int32)EParkourArrowType::Left].bBlockingHit; b &= HitResults[(int32)EParkourArrowType::Right].bBlockingHit; CheckFalseResult(b, false); //Arrow Center, Left, Right의 Normal이 모두 같은 방향인지 체크. 모서리인지 아닌지 판단 FVector center = HitResults[(int32)EParkourArrowType::Center].Normal; FVector left = HitResults[(int32)EParkourArrowType::Left].Normal; FVector right = HitResults[(int32)EParkourArrowType::Right].Normal; CheckFalseResult(center.Equals(left), false);//Arrow center와 left값이 같은지 체크 CheckFalseResult(center.Equals(right), false);//Arrow center와 right값이 같은지 체크 //impactNormal과 player가 바라보는 사이의 각도를 구하여 AvailableFrontAngle 각도보다 작을 때 수행하게 만든다. FVector start = HitResults[(int32)EParkourArrowType::Center].ImpactPoint;//Hit된 지점 FVector end = OwnerCharacter->GetActorLocation();//Player의 위치 float lookAt = UKismetMathLibrary::FindLookAtRotation(start, end).Yaw;//Player가 Hit된 위치를 바라보는 방향의 Yaw값을 구한다. FVector impactNormal = HitResults[(int32)EParkourArrowType::Center].ImpactNormal;//Hit된 지점의 Normal float impactAt = UKismetMathLibrary::MakeRotFromX(impactNormal).Yaw;//Normal 방향벡터의 Yaw값 float yaw = abs(abs(lookAt) - abs(impactAt));//두 개의 Yaw값의 차이(=impactNormal과 player가 바라보는 사이의 각도) CheckFalseResult(yaw <= AvailableFrontAngle, false);//AvailableFrontAngle로 설정한 각 15도 이하라면 return true;//수행한다. } void UCParkourComponent::DoParkour(bool bLanded) { CheckFalse(Type == EParkourType::Max);//Max는 파쿠르가 수행중이 아닌 상황 CheckFalse(Check_Obstacle());//장애물이 있는지 체크 if (Check_ClimbMode())//올라가기 파쿠르를 수행할 조건이 된다면 { DoParkour_Climb();//올라가기 파쿠르 수행 return; } } void UCParkourComponent::End_DoParkour() { switch (Type)//현재 수행중인 EParkourType { case EParkourType::Climb: End_DoParkour_Climb(); break; } Type = EParkourType::Max;//EParkourType을 원래대로 돌려준다. } bool UCParkourComponent::Check_ClimbMode() { CheckFalseResult(HitResults[(int32)EParkourArrowType::Ceil].bBlockingHit, false); const TArray<FParkourData>* datas = DataMap.Find(EParkourType::Climb);//Find는 값이 아닌 포인터를 리턴한다. const를 사용해서 고칠 수 없도록 만든다. CheckFalseResult((*datas)[0].MinDistance < HitDistance, false);//datas접근해서 0번의 MinDistance가 HitDistance보다 작은지 체크. CheckFalseResult((*datas)[0].MaxDistance > HitDistance, false);//datas접근해서 0번의 MaxDistance가 HitDistance보다 큰지 체크. CheckFalseResult(FMath::IsNearlyEqual((*datas)[0].Extent, HitObstacleExtent.Z, 10), false);//datas접근해서 0번의 Extent가 HitObstacleExtent.Z값과 같은지 체크. return true; } void UCParkourComponent::DoParkour_Climb() { Type = EParkourType::Climb;//EParkourType을 Climb으로 설정. OwnerCharacter->SetActorLocation(HitResults[(int32)EParkourArrowType::Center].ImpactPoint);//Player를 Arrow Center가 쏜 LineTrace에 Hit된 위치로 이동시킨다. OwnerCharacter->SetActorRotation(FRotator(0, ToFrontYaw, 0));//Player가 Hit된 방향을 바라보게 한다. (*DataMap.Find(EParkourType::Climb))[0].PlayMontage(OwnerCharacter);//Climb 몽타주를 재생 OwnerCharacter->GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_Flying);//기어올라가야 하므로 중력을 꺼줘야한다. 그래서 MovementMode를 MOVE_Flying로 변경한다. } void UCParkourComponent::End_DoParkour_Climb() { OwnerCharacter->GetCharacterMovement()->SetMovementMode(EMovementMode::MOVE_Walking); }
CheckTrace 함수 정의(=Arrow로 쏜 LineTrace를 체크하는 함수들)
- void UCParkourComponent::CheckTrace_Ceil()
- void UCParkourComponent::CheckTrace_Floor()
- void UCParkourComponent::CheckTrace_LeftRight()
장애물 여부를 판단하는 함수 정의
- bool UCParkourComponent::Check_Obstacle()
파쿠르를 수행하는 함수 정의
- void DoParkour(bool bLanded = false);
- void End_DoParkour();
올라가기 파쿠르 함수 정의
- bool UCParkourComponent::Check_ClimbMode();
- void UCParkourComponent::DoParkour_Climb();
- void UCParkourComponent::End_DoParkour_Climb();
CPlayer
CPlayer.h
#pragma once #include "CoreMinimal.h" #include "GameFramework/Character.h" #include "Components/CStateComponent.h" #include "Characters/ICharacter.h" #include "Parkour/CParkourComponent.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; /** 파쿠르 */ private: UPROPERTY(VisibleDefaultsOnly) class USceneComponent* ArrowGroup;//파쿠르를 위한 ArrowGroup UPROPERTY(VisibleDefaultsOnly) class UArrowComponent* Arrows[(int32)EParkourArrowType::Max]; UPROPERTY(VisibleDefaultsOnly) class UCParkourComponent* Parkour; /** 파쿠르 */ 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의 함수 오버라이드 public: void Click_RightButton(); };
함수 추가
- void Click_RightButton();
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" #include "Components/ArrowComponent.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"); CHelpers::CreateActorComponent<UCParkourComponent>(this, &Parkour, "Parkour"); 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); CHelpers::CreateComponent<USceneComponent>(this, &ArrowGroup, "ArrowGroup", GetCapsuleComponent());//ArrowGroup을 생성하고 GetCapsuleComponent 아래로 붙여준다. //파쿠르에 활용한 Arrows들을 생성한다. for (int32 i = 0; i < (int32)EParkourArrowType::Max; i++) { FString name = StaticEnum<EParkourArrowType>()->GetNameStringByIndex(i); CHelpers::CreateComponent<UArrowComponent>(this, &Arrows[i], FName(name), ArrowGroup); switch ((EParkourArrowType)i) { case EParkourArrowType::Center: Arrows[i]->ArrowColor = FColor::Red; break; case EParkourArrowType::Ceil: Arrows[i]->ArrowColor = FColor::Green; Arrows[i]->SetRelativeLocation(FVector(0, 0, 100)); break; case EParkourArrowType::Floor: Arrows[i]->ArrowColor = FColor::Blue; Arrows[i]->SetRelativeLocation(FVector(0, 0, -80)); break; case EParkourArrowType::Left: Arrows[i]->ArrowColor = FColor::Magenta; Arrows[i]->SetRelativeLocation(FVector(0, -30, 0)); break; case EParkourArrowType::Right: Arrows[i]->ArrowColor = FColor::Magenta; Arrows[i]->SetRelativeLocation(FVector(0, 30, 0)); break; case EParkourArrowType::Land: Arrows[i]->ArrowColor = FColor::Yellow; Arrows[i]->SetRelativeLocation(FVector(200, 0, 100)); Arrows[i]->SetRelativeRotation(FRotator(-90, 0, 0)); break; } } } 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("Warp", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetWarpMode); PlayerInputComponent->BindAction("Around", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetAroundMode); PlayerInputComponent->BindAction("Bow", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SetBowMode); PlayerInputComponent->BindAction("Action", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::DoAction); //PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SubAction_Pressed); PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Pressed, this, &ACPlayer::Click_RightButton); PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Released, Weapon, &UCWeaponComponent::SubAction_Released); } 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상태로 돌려줌. } void ACPlayer::Click_RightButton() { if (Weapon->IsUnarmedMode()) { Parkour->DoParkour(); return; } Weapon->SubAction_Pressed(); }
void ACPlayer::Click_RightButton()
- 우클릭을 했을 때 UnarmedMode이면 파쿠르를 실행하고 UnarmedMode가 아니라면 SubAction이 실행되게 만든다.
void ACPlayer::SetupPlayerInputComponent(UInputComponent* PlayerInputComponent)
- 우클릭 관련 수정
- 수정 전: PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Pressed, Weapon, &UCWeaponComponent::SubAction_Pressed);
- 수정 후: PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Pressed, this, &ACPlayer::Click_RightButton);
- 우클릭 떼었을때 부분은 변경사항 없이 동일하다.
- PlayerInputComponent->BindAction("SubAction", EInputEvent::IE_Released, Weapon, &UCWeaponComponent::SubAction_Released);
CAnimNotify_End_Parkour 생성
새 C++ 클래스 - AnimNotify - CAnimNotify_End_Parkour 생성


CAnimNotify_End_Parkour.h
#pragma once #include "CoreMinimal.h" #include "Animation/AnimNotifies/AnimNotify.h" #include "CAnimNotify_End_Parkour.generated.h" UCLASS() class U2212_06_API UCAnimNotify_End_Parkour : public UAnimNotify { GENERATED_BODY() public: FString GetNotifyName_Implementation() const override; virtual void Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation) override; };
CAnimNotify_End_Parkour.cpp
#include "Notifies/CAnimNotify_End_Parkour.h" #include "Global.h" #include "Parkour/CParkourComponent.h" FString UCAnimNotify_End_Parkour::GetNotifyName_Implementation() const { return "Parkour"; } void UCAnimNotify_End_Parkour::Notify(USkeletalMeshComponent* MeshComp, UAnimSequenceBase* Animation) { Super::Notify(MeshComp, Animation); CheckNull(MeshComp); CheckNull(MeshComp->GetOwner()); UCParkourComponent* parkour = CHelpers::GetComponent<UCParkourComponent>(MeshComp->GetOwner()); CheckNull(parkour); parkour->End_DoParkour();//End_DoParkour를 콜해 파쿠르를 끝낸다. }
Climb 몽타주 수정 - Run_Climb_Montage

위에서 만든 CAnimNotify_End_Parkour를 넣어준다.
실행화면

'⭐ Unreal Engine > UE RPG Skill' 카테고리의 다른 글
[UE] Feet IK, 마우스 Zoom, Enemy AI (0) | 2023.07.21 |
---|---|
[UE] 파쿠르, Feet IK (0) | 2023.07.20 |
[UE] 파쿠르 구현하기 (0) | 2023.07.18 |
[UE] 화살 (0) | 2023.07.13 |
[UE] 활 시위에 손 맞추기 (0) | 2023.07.10 |
댓글
이 글 공유하기
다른 글
-
[UE] Feet IK, 마우스 Zoom, Enemy AI
[UE] Feet IK, 마우스 Zoom, Enemy AI
2023.07.21마우스의 휠을 이용하면 화면의 Zoom In과 Out을 구현했다. 'DeltaTime' (전 프레임과 현재 프레임 사이의 시간 차이)와 'InterpSpeed' (보간 속도)를 사용하여 'TargetArmLength'를 부드럽게 변경했다. 마우스 휠의 변경 값을 'InValue'로 넣고 'Speed'를 곱한 값을 'CurrentValue'에 더하고, 이 값을 'Range.X'와 'Range.Y' 사이의 값으로 제한하여 사용하였다. 목차 Plugins Weapon Resource Icon128.pngweapon_thumbnail_icon.png Source Weapon SWeaponCheckBoxes.h .cppSWeaponDetailsView.h .cppSWeaponD… -
[UE] 파쿠르, Feet IK
[UE] 파쿠르, Feet IK
2023.07.20Feet IK(Inverse Kinematics)는 캐릭터의 발이 지면에 정확하게 위치하도록 하는 기술이다. 캐릭터 발의 위치를 조정할 수 있는 가상 본(virtual bone)을 생성한 후 사용한다. Animation Blueprint에 Two Bone IK을 사용하여 발의 위치를 정확하게 조정한다. 이를 위해 Foot IK 노드에는 목표 위치(Target Location)와 목표 회전(Target Rotation)을 입력하여 이 목표 위치와 회전은 발이 지면에 어떻게 위치해야 하는지를 정의한다. 목차 Plugins Weapon Resource Icon128.pngweapon_thumbnail_icon.png Source Weapon SWeaponCheckBoxes.h … -
[UE] 파쿠르 구현하기
[UE] 파쿠르 구현하기
2023.07.18파쿠르 시스템은 캐릭터가 벽이나 장애물과 부딪힐 때의 처리를 통해 구현할 수 있다. Unreal Engine에서는 충돌 처리를 위해 Collision Component와 Physics Engine을 사용할 수 있다. 이를 통해 캐릭터가 벽이나 장애물과 부딪힐 때 알맞은 반응을 하도록 설정할 수 있다. 오늘은 Foot IK를 C++ 코드로 구현할 것이다. 발에 가상 본을 만들고 이 가상 본을 사용하여 Trace로 바닥과 충돌을 검사한다. 양발의 높낮이 차이를 이 Trace 충돌값으로 알아내고 Foot IK 구현에 활용한다. 목차 Plugins Weapon Resource Icon128.pngweapon_thumbnail_icon.png Source Weapon SWeapo… -
[UE] 화살
[UE] 화살
2023.07.13화살을 생성하여 발사하여 데미지를 전달한다. 활을 장착(=Equip) 시에 화살을 생성하고 장착 해제(=Unequp) 시에 화살을 소멸시켜준다. 조준 후 화살을 발사하면 Projectile 값이 1000.0으로 적용되어 날라가고 충돌이 켜진다. 발사 후에는 Owner(여기서는 플레이어)의 손에 화살을 생성하여 붙여준다. 목차 Plugins Weapon Resource Icon128.pngweapon_thumbnail_icon.png Source Weapon SWeaponCheckBoxes.h .cppSWeaponDetailsView.h .cppSWeaponDoActionData.h .cppSWeaponEquipmentData.h .cppSWeaponHitData.h .c…
댓글을 사용할 수 없습니다.