파쿠르 기능 개발

김혁·2025년 11월 4일

기술연구

목록 보기
9/10
post-thumbnail

파쿠르 가능한 블록 만들기

Spline Component 추가

  • 먼저 블록을 기준으로 파쿠르를 시도할 것이기 때문에 파쿠르를 시도할 모서리에 Spline Component를 부착해서 파쿠르를 적용할 지점을 선택하고자 함
  • 추후에 원형인 경우에는 원을 4등분해서 Spline Component를 원형으로 부착하면 동일하게 작동할 것으로 보임


파쿠르 시도할 시에 필요한 함수 정의

1. 생성자

  • Spline Component를 변수로 지정하고, 반대편 모서리를 파악하기 위해서 Map 자료구조를 사용해서 미리 할당

2. FindLedgeClosestToActor

  • 기능 : 현재 액터의 위치를 기준으로 가장 가까운 ledge를 반환하는 함수
  • 로직 : Ledges를 순회하면서 가장 가까운 거리를 계산해서 비교

3. GetLedgeTransforms

  • 기능 : 액터의 위치를 기반으로 파쿠르할 지점의 위치와 normal값을 저장하고, 향후에 계산에 사용하기 위해 파쿠르할 지점의 반대편 위치와 normal값을 저장


    (1) 위에서 선언한 FindLedgeClosestToActor 함수를 활용해서 가장 가까운 Ledge 찾기

    (2) Ledge가 충분히 길이가 있는지 확인 (MinLedgeWidth는 60.0 할당되어 있음)

    (3) 가장 가까운 Ledge에서 액터를 기준으로 가장 가까운 지점을 찾고, 위치를 보정함
    너무 가장자리에서 파쿠르를 실행하면 어색할 수 있기 때문에 어느 정도 떨어진 지점에서 실행하게끔 Front Ledge Location, Normal 값을 지정

    (4) 가장 가까운 Ledge를 기반으로 Map에 저장해놓은 반대편 Ledge를 임시 저장

    (5) 가장 가까운 지점을 기준으로 반대편 Ledge에서 가장 가까운 지점을 Back Ledge Location, Normal에 저장


파쿠르 시스템

  • 기본적으로 3인칭 템플릿에 있는 BP_ThirdPersonCharacter 에셋에 로직을 추가하여 기능 구현

파쿠르 분석

  • GASP에서는 파쿠르 시스템을 장애물의 높이캐릭터가 장애물을 처리하는 방식에 따라 Hurdle, Mantle, Vault 세 가지로 구분해서 처리를 함

1. Hurdle (허들)

  • 낮은 장애물을 뛰어넘거나 걸쳐 넘는 동작
  • 장애물 높이 : 가장 낮음
  • 동작 방식 : 장애물 위로 한 발 또는 두 발을 가볍게 올려놓거나, 무릎을 높이 들어 장애물을 넘음

2. Vault (볼트)

  • 중간 높이의 장애물을 손을 짚고 측면으로 넘어가거나 몸을 회전시켜 넘는 동작
  • 장애물 높이 : 중간 (허리 높이)
  • 동작 방식 : 캐릭터가 장애물에 손을 짚고 몸을 띄워 넘음

3. Mantle (맨틀)

  • 높은 장애물에 매달리거나 올라타는 동작
  • 장애물 높이 : 가장 높음 (가슴, 머리 높이)
  • 동작 방식 : 캐릭터가 장애물 표면을 잡고 몸을 위로 끌어올려 장애물 위로 완전히 올라감


파쿠르 시스템을 위한 구조체 분석

  • GASP에서는 파쿠르 시스템을 위해 총 4개의 구조체를 사용하고 있는데, 그 중에서 가장 중요하다고 생각되어지는 2개를 살펴보고자 함

1. S_TraversalCheckResult

  • 현재 상태 및 파쿠르 가능한 지점, 장애물의 높이부터 애님 몽타주까지 많은 정보를 가지고 있는 구조체
  • 어떤 파쿠르를 선택할지와 해당 몽타주의 정보까지 가지고 있어서 전반적으로 파쿠르의 핵심 정보를 다 가지고 있는 파쿠르 시스템의 핵심적인 구조체

2. S_TraversalChooserInputs

  • 이름 그대로 모션 매칭을 연결할 때, 선택자 테이블에서 인풋을 담당할 구조체
  • 위의 S_TraversalCheckResult의 구조체 기반의 정보를 가지고 있고, 해당 구조체의 정보를 기반으로 애님 몽타주를 선택하는 역할을 함


파쿠르 기능

  • 기본적으로 파쿠르의 경우에는 점프 키와 같은 키(SpaceBar)를 사용하게끔 구현을 했음
  • 파쿠르 동작을 하고 있는지 확인한 후에 파쿠르를 실행시키는 함수를 실행시키고, 파쿠르가 불가능한 경우에는 점프가 실행되게끔 로직을 작성
  • Get Traversal Check Inputs 함수
    : Try Traversal Action 함수의 Input으로 S_TraversalCheckInputs라는 구조체를 넘겨주게 되는데, 해당 구조체를 넘겨주기 위해서 현재 Movement Mode와 이동 속력을 기반으로 Trace 해야되는 거리 및 벡터를 계산함


파쿠르 시도하는 함수 (Try Traversal Action)

  • 내부적으로 매우 많은 로직을 통해 파쿠르를 실행하게 된다는 점을 아래 그림을 통해 확인을 할 수 있음
  • 파쿠르 정보를 구조체로 저장을 해놓고, 실행하는 것은 아님
  • 먼저 Input과 Output을 보자면, trace하고자 하는 거리와 offset을 저장해놓은 구조체와 디버깅 타입을 입력받고 있고, 정상적으로 파쿠르를 실행하는지와 몽타주가 정상적으로 선택되었는지 여부를 boolean 값으로 반환하고 있음
  • 크게 5가지의 로직이 있는데, 5개를 구분해서 정리해보고자 함

1. 사용할 변수들 Local Variable로 캐싱해놓기

  • 현재 액터 위치와 캡슐 컴포넌트의 반지름과 높이를 변수로 저장

2. Trace를 통해 파쿠르할 액터를 찾고 액터를 통해 파쿠르를 실행할 지점 찾기

  • Input 정보를 기반으로 Trace 기반을 실행해서 파쿠르 가능한 액터인지 확인하기
  • 만약에 여러 가지를 만든다면, Interface를 통해 확장을 하면 될 것으로 보임
  • 파쿠르 가능한 액터라고 한다면, 앞, 뒤 Ledge 가능 여부와 Location, Normal 값을 구조체로부터 받아옴
  • 따라서 GetLedgeTransforms의 Input은 당연히 Pass-by-Reference로 받아야 함

3. Trace를 통해 파쿠르 중에 장애물이 있는지 없는지 검사하기

  • 2번 과정으로 Ledge 정보를 받아왔는데, 해당 정보가 옳은지 검사
  • 캐릭터가 장애물을 넘거나 올라선 후에 자유롭게 움직일 수 있는 공간(room)이 있는지 확인함
  • 처음 잡는 위치로부터 캐릭터의 캡슐 높이 및 반지름을 활용해서 계산한 후에 해당 위치까지 Trace를 통해 부딪히는 지점이 있다면 fail을 리턴해서 파쿠르 실행을 하지 않음
  • 해당 동작은 파쿠르 동작의 실행 가능성 및 시각적 품질을 보장하는 안전 장치임
  • 처음 잡을 위치를 기반으로 장애물의 높이를 계산해서 구조체에 저장
  • Front Ledge에서부터 Back Ledge까지 위에 장애물이 있는지 없는지 확인
  • 만약에 있다면 뛰어넘는 애니메이션은 실행시키지 못하기 때문에 이를 위한 검사
  • 만약에 장애물이 없다면 Front Ledge에서 Back Ledge 뺀 거리를 장애물의 너비로 저장
  • 캐릭터가 장애물을 완전히 넘어갔을 때, Back Ledge 바로 아래에 지면이 있는 검사하기 위한 로직
  • 지면이 있다면 해당 위치를 저장하고, 만약에 없다면 Has Back Floor를 false로 저장
  • 만약에 Front Ledge에서부터 Back Ledge까지 위에 장애물이 있다면, 충돌 지점에서부터 Front Ledge 뺀 거리를 장애물의 너비로 설정한 후에 Has Back Floor를 false로 저장

-> 먼저 Front Ledge로부터 수직으로 캐릭터만큼 설 수 있는지 확인
-> Front Ledge 위에서부터 Back Ledge 위까지 장애물이 있는지 확인한 후에, 이를 기반으로 장애물 너비 저장
-> 장애물이 있다면, Back Ledge에 도달하지 못하기 때문에 Has Back Ledge를 false로 저장
-> 장애물이 없다면, 지면을 검사해서 여부에 따라 지면의 위치와 Has Back Floor 값을 true/false 저장

4. 저장한 값을 기준으로 실행가능한 파쿠르 애니메이션들을 선택

  • 2~3번 과정을 통해 얻어온 데이터를 기반으로 Chooser Table을 통해 가능한 애니메이션들을 선택해서 저장

5. 모션 매칭을 통해 가장 알맞은 애님 몽타주를 선택

  • 유효한 애님 몽타주를 반환했는지 검사
  • ABP에 파쿠르를 실행할 위치 정보를 전달
  • 유효한 몽타주 중에서 궤적 정보를 통해 모션 매칭을 실행해서 가장 맞는 애니메이션을 선택해서 실행할 몽타주를 구조체에 저장
  • 외부 변수에 저장 및 실제로 파쿠르 실행


CHT_TraversalAnimations

  • Chooser Table의 Table Settings에서 Input과 Output을 아래와 같이 세팅
  • Input을 통해 가능한 파쿠르 애니메이션 몽타주를 반환해주는 Chooser Table
  • 가장 큰 범주로, 장애물을 넘을 수 있는지, 뒤에 바닥이 있는지 등의 여부에 따라 Nest Chooser를 통해 먼저 어떤 파쿠르 동작인지 구분함
  • Hurdle 파쿠르 액션만 보자면, 장애물 너비, 높이, 속도, MovementMode를 기준으로 애니메이션 몽타주를 선택함


파쿠르 실행하는 이벤트 (Perform Traversal)

  • 실질적으로 파쿠르를 실행하는 이벤트
  • 구조체 데이터를 기반으로 선택한 애님 몽타주를 실행
  • 애님 몽타주를 실행하는 도중에는 원활한 몽타주를 실행을 위해 Capsule Component를 파쿠르 가능한 액터와의 충돌을 무시하고, Movement Mode를 Flying으로 지정
  • 애님 몽타주가 종료되면 기존의 것으로 되돌리고, 멀티플레이를 위해 딜레이를 주고 속성 값을 다시 변경함


결과

추가적으로 수정해야될 부분

  • 왜인지 모르겠지만, 달리고 있는 상황에서 허들 파쿠르를 실행하면 뚫고 지나가다가 공중에서 파쿠르를 실행함
  • 파쿠르 도중에 벽을 뚫는 경우가 있음


개인 샘플 프로젝트 : Github - Motion Matching

참고

Fab 샘플 프로젝트 : Epic Games - Game Animation Sample

profile
게임 개발자를 향해..

0개의 댓글