언리얼 퍼즐 시스템

민트맛치킨·2026년 1월 15일

Unreal

목록 보기
26/26

퍼즐 시스템

Tag기반으로 다양한 퍼즐 요소들의 상태를 관리하고 조건 만족 시 퍼즐 성공, 실패 처리를 하는 시스템

설계

  • Tag 기반 상태 관리
    • ActivatedTag - 퍼즐 요소 활성화 시 브로드캐스트
    • DeactivatedTag - 퍼즐 요소 비활성화 시 브로드캐스트
  • 중앙 집중 상태 추적 - PuzzleChecker와 연결된 모든 퍼즐 요소의 Tag 관리
  • 3계층 역할 분리 - 확장성을 위해 입력(Element), 검증(Checker), 반응(ReactActor)을 분리한 시스템

PuzzleElement

퍼즐의 상호작용을 담당

  • 구현
    • 플레이어의 상호작용 또는 Inspection 입력 받기
    • 고유한 ActivatedTag 또는 DeactivatedTag을 Checker에 브로드캐스트
    • 자신의 활성화 상태만 관리
    • 일회성, Toggle, HoldToggle 모드별로 다양한 상호작용 방식 존재
  • 동작 예시
    • 회전 퍼즐
      올바른 방향 → Puzzle.Rotation.Element.Correct 태그 전송
      정답이 아닌 방향 → Puzzle.Rotation.Element.Correct 태그 삭제
    • 레버
      레버를 올릴 경우 → Puzzle.Lever.Activated 태그 전송
      레버를 내릴 경우 → Puzzle.Lever.Activated 태그 삭제

PuzzleElement는 각각 독립적으로 동작하고 상호작용의 결과만 Checker에 전송

  • PuzzleElement가 새로 추가 되어도 Checker에서 Tag만 추가해주면 된다

PuzzleChecker

퍼즐의 성공 조건을 확인하는 담당

  • 퍼즐 조건
    • 순서 - 지정된 Tag가 순서대로 들어와야 함, 실패 시 초기화
    • AND - 지정된 모든 Tag가 들어와야 퍼즐 성공
    • OR - 지정된 Tag 중에서 하나라도 들어오면 퍼즐 성공
  • 초기화/비활성화
    • 초기화 : 퍼즐이 초기화가 필요한 경우 연결된 모든 PuzzleElement에 초기화를 브로드캐스트
      각 PuzzleElement는 자신이 가지고 있는 초기화 함수를 실행
    • 비활성화 : 퍼즐이 성공한 경우 연결된 모든 PuzzleElement를 비활성화

ReactActor

실제로 반응하는 액터

  • 퍼즐 성공
    • 퍼즐이 성공되었을 때 각 ReactActor의 동작을 수행(카오스 디스트럭션, 문 열림 등)
  • 퍼즐 요소
    • PuzzleElement의 동작으로 즉시 ReactActor를 동작시킬 수 있음(발판을 밟고 있을 때만 열리는 문 등)

스테이지1

회전 퍼즐 (Rotation Puzzle)

플레이어가 상호작용하면 일정 각도씩 회전하고 정답인 방향일 때만 성공 태그 전송

  • 순환 회전
    • CurrentRotationIndex % NumRotationSteps으로 한쪽 방향으로 계속 회전, 원위치
    • 실제 돌아간 각도가 계산한 각도보다 오차가 0.5이상일 경우 보정하여 스냅
  • 정답 체크
    • 회전할 때만 정답인 방향인지 체크
    • 정답 방향 → Checker에 ActivatedTag 추가, DeactivatedTag제거
    • 오답 방향 → Checker에 ActivatedTag제거, DeactivatedTag추가
  • 회전 중에는 상호작용 입력 무시
  • FMath::RInterpTo로 부드럽게 회전 애니메이션

핀볼 퍼즐 (Pinball Puzzle)

물리 기반의 Inspection 퍼즐로 오버뷰 카메라 상태에서 각자 부여된 막대를 회전시켜 공을 골인시키는 4인 협동 퍼즐

  • 성공, 실패 체크
    • 성공 Trigger 박스에 공이 골인할 경우 퍼즐 성공
    • 실패 Trigger 박스에 공이 들어간 경우 공 위치 초기화
  • Inspection 모드
    • 핀볼 영역을 한눈에 볼 수 있는 오버뷰 카메라
    • 스페이스 바로 막대 조작
  • 각 플레이어마다 개별적으로 할당된 막대 조작으로 협동

압력 발판 (Pressure Plate)

Overlap 기반으로 바닥에 있는 발판에 플레이어나 아이템이 올라가면 활성화, 내려가면 비활성화

  • Overlap 액터 관리
    • OverlappingActors 배열 : 여러 플레이어 동시 밟기 가능
    • Num == 1 체크 : 첫 번째 액터만 활성화 트리거
    • Num == 0 체크 : 마지막 액터가 나갈 때만 비활성화
  • Progress 시스템
    • 0.1초마다 ProgressSpeed로 증가/감소
    • LinkedReactionActors에 실시간 전달
    • 밟으면 증가, 안 밟으면 감소

밟으면 부서지는 바닥 함정 (Destructible Floor)

플레이어가 밟으면 일정 시간 후 바닥의 GeometryCollection이 파괴되어 플레이어를 낙하시키는 함정

  • AAO_DestructibleCacheActor 캐시를 사용하는 디스트럭션 액터를 상속받아 사용
  • 파편 충돌 처리
    • 플레이어와 디스트럭션 파편이 동시에 떨어질 경우 빠른 충돌로 인해
      메타휴먼의 Groom Component의 헤어가 플레이어를 빠르게 따라가지 못하는 상황 발생
    • CollisionDisableDelay 라는 추가 타이머와 박스 콜리전을 사용하여
      파편이 빠르게 먼저 떨어지기 시작하고 0.1초 뒤에 플레이어가 같이 떨어지게 하여 디스트럭션 초기에 발생하는 강한 충돌을 막음

스테이지2

격자 퍼즐 (Grid Puzzle)

소코반(Sokoban) 스타일의 격자 퍼즐로 플레이어가 바위를 밀어 목표 지점에 모든 바위를 배치하면 성공
다른 인원들은 오버뷰 카메라로 위에서 격자 퍼즐의 전체부분을 관찰하고 다른 플레이어에게 지시하는 협동 퍼즐

GridManager

격자 퍼즐을 관리하는 중앙 매니저

  • 격자 설정
    • CellSize : 각 셀의 크기
    • GridSize : 격자 크기 (10x10)
    • GridOrigin : 격자 시작 좌표
  • 좌표 변환
    • WorldToGrid() : 월드 좌표 → 격자 좌표
    • GridToWorld() : 격자 좌표 → 월드 좌표 (셀 중심)
  • 충돌 관리
    • RockMap : 각 셀에 바위가 있는지 추적
    • Walls : 격자 벽 목록
    • HasWallBetween() : 두 셀 사이에 벽이 있는지 체크

GridWall

바위 이동을 막는 장애물 벽

  • 방향 설정 타입
    • Horizontal : 가로 벽 (셀의 아래쪽 경계)
    • Vertical : 세로 벽 (셀의 오른쪽 경계)
  • 자동 정렬
    • 에디터에서 벽 이동 시 자동으로 격자 경계 위치에 스냅
    • Horizontal → Rotation(0, 0, 0)
    • Vertical → Rotation(0, 90, 0)

PushableRockElement

플레이어가 밀어서 이동시키는 퍼즐 요소

  • 속성
    • CurrentGridCoord : 현재 격자 좌표
    • InitialGridCoord : 초기 위치 (리셋용)
    • GoalCells : 목표 셀 목록 (정답)
  • 이동 제약
    • 격자 범위 내에서만 이동
    • 다른 바위가 목표 위치에 있으면 이동 불가
    • 벽이 있으면 해당 방향으로 이동 불가

격자 퍼즐 플레이어 보호 처리

  • 목적지 사전 검증
    • 바위를 밀기 전에 목표 셀의 전방, 좌, 우 3방향 체크
    • 각 방향마다 벽 또는 다른 바위가 있는지 확인
    • 3면이 모두 막혀있는지 판단
    • 감지된 플레이어가 바위 전방에 있는지 DotProduct로 검증

  • 플레이어 갇힘 방지
    • 3면이 모두 막혀있을 경우 → 목표 셀에 플레이어 감지 (OverlapSphere)
    • 플레이어가 있으면 → return false (밀기 불가)
    • 플레이어가 없으면 → return true (밀기 가능)

  • 플레이어 탈출 방향 결정
    • 전방이 비어있는 경우 → 전방으로 밀어냄
    • 전방 막힘, 우측 비어있음 → 우측으로 탈출
    • 전방 막힘, 좌측 비어있음 → 좌측으로 탈출
    • 전방 막힘, 양쪽 비어있음 → 플레이어 위치 기준 가까운 쪽 선택

횃불 퍼즐 (Torch Puzzle)

패턴 매칭 퍼즐로 다른 한쪽 벽에 힌트로 주어진 횃불의 On/Off 패턴을 관찰하고 퍼즐 횃불을 동일한 패턴으로 맞추는 퍼즐

정답 패턴

반대쪽 퍼즐 횃불

  • 상태 체크
    • bIsTorchLit : 현재 횃불 켜짐/꺼짐 상태
    • bCorrectStateIsLit : 해당 횃불의 정답 설정
    • `TorchCorrectTag` : 정답일 때 Checker에 보낼 Tag
  • 상호작용
    • 토글할 때만 정답인 상태인지 체크
    • 정답이면 Checker에 Tag 전송, 오답이면 Tag 제거

케이블카

스플라인 경로 기반의 이동 플랫폼으로 플레이어가 버튼을 이용해 정방향/역방향으로 이동을 제어하는 맵 기믹

  • Toggle 제어
    • 버튼 3개 배치 (시작 구역, 케이블카 내부, 도착 구역)
    • 어느 버튼을 누르든 동일한 Toggle 동작으로 출발 또는 반대 방향 이동
  • 이동 시스템
    • SplineComponent로 시작점 → 도착점 경로 정의
    • EaseInOut으로 부드럽게 이동

캐논 (Cannon)

Inspection 기반의 캐논으로 플레이어가 WASD로 캐논을 조준할 수 있고 스페이스 바로 발사하여 AI를 기절시키는 기믹

  • 조작
    • W/S (Pitch) - 포신 상하 회전, 메시는 캐논 전체가 아닌 포신만 회전
    • A/D (Yaw) - 캐논 좌우 회전, 캐논 전체가 회전
    • 스페이스바 발사 - ProjectilePool에서 투사체 획득 후 MuzzlePoint에서 발사
  • 오브젝트 풀링
    • CannonProjectilePool 컴포넌트 - 투사체 사전 생성 및 관리

    • PoolSize 설정 - 기본 10개

    • 재사용 메커니즘

      발사 → ActiveProjectiles로 이동
      폭발/충돌 → AvailableProjectiles로 반환

    • 풀 부족 시 - 가장 오래된 ActiveProjectile 강제 회수

  • 폭발 효과
    • 광역 스턴 - ExplosionRadius 내 AI 감지
    • Event.AI.Stunned 전송, AI가 GameplayEvent 받아 스턴 실행

스테이지3

가스실 탈출 퍼즐 (Gas Room Escape Puzzle)

시간 제한 생존형 퍼즐로 플레이어가 밀폐된 가스실안에 갇혀 독가스를 버티며 랜덤 생성된 비밀번호를 찾아 비밀번호 패널에 입력해야 탈출하는 퍼즐

  1. 가스실 진입

    • 플레이어가 가스실 TriggerBox Overlap
    • 플레이어 첫 진입 시 타이머 시작
    • CurrentState : Idle → WaitingToStart
  2. 가스실 활성화

    • 문 닫힘, 잠금
      • 가스실의 모든 BunkerDoor 닫기
      • LockDoors() - 벙커문 상호작용 비활성화
    • 가스 이펙트 생성
      • 가스 VFX/SFX 재생
      • GasEffectSpawnInfos 배열 기반 여러 위치 스폰
    • 데미지존 활성화
      • 플레이어에게 지속적으로 데미지를 주는DamageZoneClass 스폰
      • TriggerBox 크기와 동일하게 설정
    • CurrentState : WaitingToStart → Active
  3. 비밀번호 생성

    • GenerateRandomPassword() - 4자리 랜덤 생성 (0~9)
    • SelectRandomCandidates() - 미리 지정한 데칼 위치 후보군에서 4개 랜덤 선택
    • 가스실 천장, 바닥, 벽에 데칼 표시
      • 빨강(1번) → 노랑(2번) → 초록(3번) → 파랑(4번) 순서
      • MaterialInstanceDynamic 생성
      • 숫자에 맞는 숫자 데칼 설정
      • 자릿수에 맞는 숫자 데칼 색상 설정
      • Decal 활성화 (SetVisibility, SetHiddenInGame)
  4. 카운트 다운

    • 타이머 시작
    • CheckAliveCharacters() - 1초마다 생존자 확인
      • 플레이어의 DeathTag 체크 (Status.Death)
      • 생존자 0명 → ResetPuzzle()
    • RemainingTime 시간 초과 → ResetPuzzle()
  5. 비밀번호 입력

    • 플레이어가 데칼 보고 숫자 확인
    • PasswordPanel에 4자리 입력
    • 비밀번호가 정답인 경우 퍼즐 성공
  6. 성공인 경우

    • CompletePuzzle()
      • CurrentState → Completed
      • 모든 타이머 정리
    • 가스 제거
      • VFX/SFX 정리
      • DeactivateDamageZone() - 데미지존 제거
    • 문 열림
      • 잠긴 모든 문 열기
      • UnlockDoors() - 상호작용 활성화
    • 데칼 숨김
    • Checker에 정답 태그 전송
  7. 리셋인 경우

    • 모든 플레이어 사망 - GetAliveCharacterCount() == 0
    • 시간 초과
    • 플레이어 전원 이탈

    새로운 플레이어가 TriggerBox 진입, 처음부터 다시 시작

엘레베이터

시퀀스 기반 엘레베이터 시스템으로 TArray를 큐처럼 사용하여 문 열림/닫힘, 이동, 대기를 순차적으로 상황에 맞게 실행하는 반응 액터

밸브 (Valve)

토글 방식 상호작용 액터로 밸브를 열거나 닫아서 특정 위치에 데미지 존과 증기 VFX를 제어하는 환경 요소

  • 토글 동작 방식
    • F키 → 열림 - bIsValveOpen = true
      • 증기 VFX/SFX 생성
      • 데미지존 활성화
      • InteractionLockDuration 동안 상호작용 불가
    • F키 → 닫힘 - bIsValveOpen = false
      • VFX/SFX 제거
      • 데미지존 제거
      • InteractionLockDuration 동안 상호작용 불가
  • 데미지 존 특징
    • 플레이어가 데미지 존에 들어가면 지속적으로 데미지를 입음
    • AI가 데미지 존에 들어가면 지속적으로 Stun 부여

롤링볼 기믹

물리 기반 장애물 시스템으로 굴러오는 거대한 눈덩이를 피하면서 파쿠르로 목적지에 도달하는 회피 파쿠르 기믹

  • RollingBall
    • 플레이어 충돌
      • Overlap 감지 및 데미지 적용 - Damage 수치만큼 HP 감소
      • 넉백 - KnockbackStrength로 플레이어 튕겨냄
      • 넉다운 이펙트 - Event.Combat.HitReact.Knockdown전송
      • HitCooldown - 같은 플레이어 연속 피격 방지
    • 리셋 기능
      • ResetToStart() - 초기 위치로 순간이동
      • 속도 제거
      • PlayerHitCooldowns 초기화
  • BallTrigger
    • PlayerDetection 타입 (주변에 플레이어가 없는데 공이 계속 굴러가는 것을 방지)
      • 플레이어 구역 진입 - Overlap 시 TargetBalls 활성화
      • 플레이어 이탈 - EndOverlap 시 TargetBalls 비활성화
      • 생존자 체크 - 살아있는 플레이어 카운트
      • 모두 사망 시 - 공 자동 정지
    • Reset 타입
      • TargetBalls 중 하나가 닿으면 ResetToStart() 호출, 해당 공을 초기 위치로 복귀

카오스 디스트럭션 : 공이 굴러오는 다리에 캐논 투사체를 발사하면 다리 파괴, 해당 라인의 공 제거

0개의 댓글