파쿠르는 다음과 같은 과정을 통해 구현하였다. 먼저, 캐릭터 허리 높이 중앙에 있는 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