2026-05-21 TIL (62일차)
[포트폴리오] UE5 Chaos 기반 다이내믹 차량 주행 및 시뮬레이션 시스템 구현
1. Chaos Physics 기반 차종별 맞춤형 물리 및 주행 로직 설계
단순한 차량 이동을 넘어, 차량의 용도(스포츠카 vs 오프로드)에 따른 현실적인 물리 엔진 세팅과 구동계를 C++로 상세하게 구현했습니다.
오프로드 차량 (험지 돌파 및 안정성 극대화)
- 전복 방지 세팅: 차체가 크고 높은 오프로드 차량의 특성상 발생하기 쉬운 전복 사고를 방지하기 위해
CenterOfMassOverride를 활성화하여 무게 중심을 하단(Z=75.0f)으로 강제 고정(오뚝이 원리 적용)했습니다. - 지형 충돌 물리 버그 해결: 바퀴의 바닥 충돌 검사 시 선 검사(Raycast) 대신 도형 검사(Shapecast)를 도입하여, 울퉁불퉁한 바위나 틈새 지형에서 바퀴가 빠지는 물리 버그를 원천 차단했습니다.
- 서스펜션 및 구동계 튜닝: 서스펜션 가동 범위(
MaxRaise/Drop)를 20cm로 길게 주고 스프링 강도(SpringRate)를 100.0f로 부드럽게 세팅하여 지형의 충격을 흡수하도록 했으며, 5:5 비율의 사륜구동(AWD) 및 높은 공회전 RPM(1200)을 적용해 험지 돌파력을 구현했습니다. - 제동 안정성 확보: 미끄러운 진흙/눈길에서 브레이크를 밟았을 때 바퀴가 락(Lock)되어 미끄러지는 현상을 방지하기 위해 최대 제동력을 의도적으로 낮게(3000.0f) 튜닝하여 제동 안정성을 확보했습니다.
스포츠카 (고속 주행 및 코너링 특화)
- 다운포스 및 공기역학: 차량의 무게 중심 높이(
ChassisHeight)를 144.0f로 낮게 설정하고, 공기 저항 계수(DragCoefficient)를 0.31f로 맞춰 고속 주행 시 차량이 바닥에 밀착되도록 설계했습니다. - 롤링(Roll) 억제: 스프링 강도(
SpringRate)를 500~550.0f로 매우 단단하게 설정하여 급커브 시 차체가 기우는 현상(Roll)을 억제했습니다. - 정교한 조향 및 그립 주행: 회전 시 안쪽과 바깥쪽 바퀴의 궤적 차이를 계산하는 Ackermann 조향 구조를 적용하고, 뒷바퀴의 폭과 마찰력을 높인 후륜 구동 중심으로 설계하여 날카로운 코너링과 드리프트 억제(Grip 주행)를 구현했습니다.
2. 팀 협업 및 모듈 확장성을 극대화한 Event-Driven 환경(날씨/터널) 제어 아키텍처
단순한 차량 본체의 물리/시각 효과 제어를 넘어, 타 팀원들이 개발한 다양한 자율주행 센서 및 AI 모듈들이 글로벌 환경 변화에 즉각적으로 동기화될 수 있도록 결합도(Coupling)를 최소화한 중앙 통제형 델리게이트 시스템을 총괄 설계했습니다.
- 멀티캐스트 델리게이트(Multicast Delegate) 기반 결합도 분리: 차량 폰(
ATeam24VehiclePawn) 내부에FOnWeatherChanged및FOnTunnelStateChanged멀티캐스트 델리게이트를 선언하여 시스템의 ‘이벤트 허브(Broker)’ 역할을 하도록 설계했습니다. 차량 본체는 다른 컴포넌트의 내부 구현을 알 필요 없이 오직 ‘상태 변경’만을 방송(Broadcast)함으로써, 상호 의존성을 완벽히 분리하는 객체지향적 설계를 달성했습니다. - 팀원 컴포넌트를 위한 플러그앤플레이(Plug & Play) 연동 구조 제공: 타 팀원들이 라이다(LiDAR), 카메라 센서, 자율주행(
SplineFollower) 컴포넌트를 개발할 때, 환경 변화 로직을 개별적으로 구현할 필요가 없도록 아키텍처를 통합했습니다.BeginPlay단계에서 타 팀원의 컴포넌트 수신 함수(ApplyWeatherProfile등)를 폰(Pawn)의 델리게이트 채널에AddUObject로 구독(Bind)시키기만 하면 시스템이 통합되도록 직관적인 인터페이스를 제공했습니다. - 하향식(Top-Down) 데이터 전파를 통한 시스템 동기화: 글로벌
UWeatherSubsystem에서 발생한 날씨 이벤트가 등록된 차량에 1차 전파되고, 차량 폰이 다시 하위 센서들에게 2차 전파하는 계층적 파이프라인을 완성했습니다. - 차량 본체(Pawn) 단위의 디테일한 상태 제어: 이벤트 수신 시, 폰 내부의
ApplyWeather함수를 통해UChaosVehicleWheel의 기본 마찰력에 날씨 데이터 에셋의 마찰력 배율을 곱하여 노면 상태를 물리적으로 연산합니다. 동시에 터널 진입(SetInTunnel) 시 헤드라이트 가시성 및 머티리얼 발광을 조절하고 나이아가라(Niagara) 날씨 파티클을 일시 중지시키는 등, 단일 신호만으로 차량 전체의 시각/물리적 상태가 오차 없이 동기화되도록 구현했습니다.
3. 수학적 보간(Interpolation)을 활용한 동적 카메라 및 오디오 시스템
사용자의 조작감과 피드백을 극대화하기 위해 매 프레임(Tick) 부드러운 상태 전환을 구현했습니다.
- 다이내믹 오디오 제어: 차량의 현재 엔진 RPM 수치와 엑셀레이터 입력량(
GetThrottleInput)을 가져와FMath::Lerp및FMath::Clamp공식을 적용, 엔진 사운드(UAudioComponent)의 음높이(Pitch)와 볼륨(Volume)이 물리적 상태에 비례하여 동적으로 변하도록 오디오 시스템을 직접 제어했습니다. - 카메라 동역학 연출:
SpringArmComponent의CameraRotationLagSpeed를 활용해 차량 회전 시 카메라가 한 박자 늦게 따라오게 하였고,FMath::FInterpTo를 사용해 사용자가 조작하지 않을 때 카메라 시점이 서서히 차량 정면으로 복귀하도록 계산하여 묵직하고 역동적인 주행 뷰를 완성했습니다.
4. 페일세이프(Fail-Safe) 및 차량 복구 시스템
시뮬레이션 중 발생할 수 있는 이상 현상을 감지하고 안전하게 제어권을 되찾는 기능을 구현했습니다.
- 전복 감지 시스템: 월드의
UpVector와 차량의UpVector간의 내적(Dot Product)을 계산하여 일정 수치 이하로 기울어지면 차량이 전복된 것으로 판단하는 검사 로직(FlippedCheck)을 타이머 베이스로 가동했습니다. - 물리 버그 방지 차량 복구: 경로 이탈이나 전복 발생 시 차량을 강제 복구하는
LocationRecoveryVehicle함수를 구현했습니다. 단순히 위치만 이동시키는 것이 아니라, 순간이동 시 발생할 수 있는 충돌 오류를 막기 위해ETeleportType::TeleportPhysics를 사용하고 남은 관성(SetPhysicsLinearVelocity,SetPhysicsAngularVelocityInDegrees)을 0으로 초기화하여 안정적으로 스폰시켰습니다.
[포트폴리오2] UE5 시스템 아키텍처 및 데이터 기반(Data-Driven) 환경 제어 구현
1. UTickableWorldSubsystem 기반의 글로벌 날씨 제어 시스템 구축
레벨에 보이지 않는 매니저 액터를 배치하는 구시대적 방식에서 벗어나, 엔진 생명주기와 함께 동작하는 UWeatherSubsystem을 설계하여 전역적인 환경 제어를 구현했습니다.
- 메모리 누수 방지(Weak Pointer): 다수의 차량(
ATeam24VehiclePawn)과 도로(ARoadActor) 액터를 서브시스템에 등록할 때TArray<TWeakObjectPtr<>>를 사용하여, 차량이 파괴되거나 레벨이 변경될 때 발생할 수 있는 댕글링 포인터(Dangling Pointer) 문제와 가비지 컬렉션(GC) 방해 문제를 원천적으로 방지했습니다. - 최적화된 Tick 보간(Interpolation): 날씨가 바뀔 때 태양광(
DirectionalLight)의 밝기와 색상이 자연스럽게 전환되도록FMath::FInterpTo와FMath::CInterpTo를 적용했습니다. 특히, 평소에는 Tick 연산을 쉬다가 조명 전환이 일어날 때만bIsTransitioningLight스위치를 켜서 동작하게 함으로써 CPU 연산 낭비를 최소화(Tick 최적화)했습니다. - 에디터 UI 한계 극복:
LocalFogVolume등 특정 렌더링 액터에 태그를 달 수 없는 에디터의 한계를 파악하고,TActorIterator를 활용해 원본 클래스명(GetClass()->GetName())으로 액터를 런타임에 직접 찾아내어 날씨에 따라 렌더링을 켜고 끄는 페일세이프(Fail-Safe) 로직을 적용했습니다.
2. DataAsset 및 DeveloperSettings를 활용한 데이터 주도적(Data-Driven) 설계
기획자와 아티스트가 프로그래머의 코드 수정 없이도 날씨 환경을 세팅할 수 있도록 언리얼 엔진의 데이터 관리 시스템을 적극 활용했습니다.
- Data Asset 모듈화:
UWeatherPresetDataAsset을 생성하여 도로 마찰력(RoadPhysicsMaterial), 파티클(NiagaraSystem), 태양광 강도, 타이어 마찰 배율 등의 환경 파라미터를 에셋 형태로 캡슐화했습니다. - Project Settings 글로벌 노출:
UDeveloperSettings를 상속받은UWeatherSettings클래스를 작성하여, 에디터의 [프로젝트 세팅] 창에서 날씨별 프리셋 데이터를 직접 할당하고 관리할 수 있는 편의성을 제공했습니다. - 메모리 최적화 (Lazy Loading): 세팅 창에 등록된 수많은 파티클과 데이터 에셋이 게임 시작 시 한 번에 메모리에 올라가는 것을 막기 위해
TSoftObjectPtr(소프트 레퍼런스)를 사용했습니다. 실제 해당 날씨가 호출될 때만LoadSynchronous()로 에셋을 동적 로드하여 초기 로딩 속도와 메모리 효율을 극대화했습니다.
3. PlayerController 기반의 UI 및 생명주기 관리
입력 처리, UI 렌더링, 액터 생명주기(Respawn) 관리를 PlayerController로 집중시켜 객체지향적 책임을 분리했습니다.
- Enhanced Input 통합 관리:
IsLocalPlayerController()검사를 통해 로컬 플레이어에게만UInputMappingContext를 동적으로 할당하고, 키보드 입력 신호에 맞춰 카메라 센서 뷰, 라이다 뷰, 차량 리셋, 날씨 토글 등의 액션을 제어하도록 시스템을 통합했습니다. - 동적 리스폰(Respawn) 시스템: 차량이 파괴될 경우(
OnPawnDestroyed델리게이트 수신), 월드의 PlayerStart 액터를UGameplayStatics::GetAllActorsOfClass로 찾아내 그 위치의 Transform을 추출하고, 즉시 새로운 차량을SpawnActor로 생성하여Possess(빙의)하는 끊김 없는 리스폰 파이프라인을 구축했습니다. - Timer 기반 UI 비동기 업데이트: 센서 뷰 및 데이터 뷰 위젯(
UDataViewWidget)을 생성하고 우선순위(Z-Order)를 배정했습니다. 특히 차량의 속도(km/h) 데이터를 UI로 넘겨줄 때, 무거운 매 프레임 Tick 함수 대신GetWorldTimerManager().SetTimer를 활용해 0.1초 간격으로 업데이트하도록 분리하여 UI 렌더링 부하를 줄였습니다.
[포트폴리오] 자율주행 스플라인 추종 제어 및 페일세이프(Fail-Safe) 시스템 구현
[팀원 파트 기여] > 아래 내용은 팀원이 메인으로 담당했던 자율주행 모듈(
SplineFollowerComponent) 파트였으나, 엔진 코어 단의 물리 버그 발생 및 고도화된 페일세이프 로직 구현에 있어 병목이 발생했을 때 적극적으로 지원하고 페어 프로그래밍하여 함께 문제를 해결하고 로직을 완성한 핵심 기여 파트입니다.
1. Chaos Physics 코어 분석을 통한 제동 버그(Reverse Bug) 트러블슈팅
- 문제 상황: 자율주행 차량이 목적지에 도달했을 때(
HandlePathCompleted), 차량을 정차시키기 위해DoBrake(1.f)로 100% 브레이크를 가동했습니다. 그러나 차량이 정지한 후에도 브레이크 입력이 계속 유지되면서 차량이 뒤로 후진해 버리는 크리티컬한 버그가 발생했습니다. - 원인 분석 및 해결 (엔진 코어 분석 역량): * 블루프린트나 틱(Tick)에서 억지로 속도를 0으로 묶어버리는 임시방편(Hack)을 사용하지 않았습니다. 대신 언리얼 엔진의
UChaosWheeledVehicleMovementComponent내부 C++ 코드를 직접 뜯어보며 물리 제동 로직을 분석했습니다.- 분석 결과, 카오스 비히클 무브먼트에 브레이크와 후진이 통합되어 작동하는
bReverseAsBrake변수가 기본적으로 활성화되어 있어 발생하는 문제임을 정확히 찾아냈습니다. - 생성자에서
ChaosVehicleMovement->bReverseAsBrake = false;로 해당 로직을 명시적으로 비활성화하여, 후진 기어와 브레이크를 완벽히 분리하고 근본적인 원인을 깔끔하게 해결했습니다.
- 분석 결과, 카오스 비히클 무브먼트에 브레이크와 후진이 통합되어 작동하는
2. 경로 이탈 감지 및 자동 복구 시스템 (Fail-Safe & Recovery)
- 설계 의도: 시뮬레이션 중 물리 충돌이나 급커브 슬립으로 인해 차량이 도로(Spline)를 이탈했을 때, 시스템이 멈추지 않고 스스로 복구하는 예외 처리 시스템을 팀원과 함께 설계 및 구축했습니다.
- 구현 디테일:
- 지연 시간 기반 감지: 차량과 도로 중앙선 사이의 거리(
FVector::Dist)가 허용 오차(MaxRoadDeviation)를 벗어나면 즉시 텔레포트시키지 않고,CurrentOffRoadTime타이머를 누적시킵니다. 허용 시간(MaxOffRoadTime) 내라면 브레이크를 밟으며 대기하고, 시간을 초과했을 때만 복구를 가동하여 일시적인 흔들림과 진짜 이탈을 구분했습니다. - 안전한 스폰 좌표 계산: 복구 시 무작정 도로 위로 올리지 않고, 가장 마지막으로 안전하게 주행했던 거리(
LastValidDistance)를 기억해 두었다가 해당 지점의 위치와 방향(GetLocationAtDistance,GetDirectionAtDistance)을 가져옵니다. - 물리 글리치 방지: 복구 과정에서 차량이 바닥에 파묻히는 물리 버그를 막기 위해 Z축으로 50.0f 띄워서 스폰하고, 차량이 누워있던 상태로 복구되지 않도록
ResetRotation.Pitch와Roll을 강제로 0.0f로 초기화하는 디테일을 챙겼습니다.
- 지연 시간 기반 감지: 차량과 도로 중앙선 사이의 거리(
3. 데드존(Deadzone)을 활용한 부드러운 가감속 제어
- 구현 내용: 목표 속도(
TargetSpeed)와 현재 속도(CurrentSpeed)의 오차를 기반으로 엑셀과 브레이크 입력을 결정하는ApplySpeedCommand를 구현했습니다. - 기술적 디테일:
- 오차 값에
ThrottleGain을 곱하여[-1.0 ~ 1.0]사이의 명령값으로 변환(Clamp)하는 비례 제어 방식을 사용했습니다. - 단순히 가속/감속만 반복하면 목표 속도 근처에서 차가 앞뒤로 덜컹거리는 진동(Oscillation) 현상이 발생합니다. 이를 방지하기 위해
CoastDeadzone이라는 임계값을 설정하여, 미세한 오차 범위 내에서는 가속도 브레이크도 밟지 않고 관성으로 주행(DoThrottle(0.f))하도록 설계하여 승차감과 주행의 자연스러움을 극대화했습니다.
- 오차 값에