로블록스 스튜디오에서 자동차, 호버크래프트, 비행기 같은 복잡한 물리 메커니즘을 제작하려면 엔진의 PGS(Projected Gauss-Seidel) 솔버에 대한 깊은 이해가 필요합니다. 구형 BodyMover(BodyGyro, BodyVelocity)에 의존하면 멀티플레이 환경에서 극심한 물리 렉과 덜컹거림이 발생합니다.
현대 로블록스 물리는 제약 조건(Constraints) 기반 아키텍처로 작동합니다. 사실적인 노면 완충을 위한 SpringConstraint, 바퀴 회전을 위한 CylindricalConstraint, 차량 전복을 막는 AlignOrientation, 그리고 네트워크 오너십(Network Ownership) 핸드오프를 결합하여 안정적인 주행 메커니즘을 구축하는 방법을 다룹니다.
1. PGS 물리 솔버 & 어셈블리(Assembly) 구조
파트들이 하나의 물리 단위로 결합되는 기본 원리:
- 어셈블리와 RootPriority: 용접(Weld)된 부품 묶음은 단일 물리 어셈블리를 형성합니다. 차량 하판(Chassis)에
RootPriority를 높게 설정하여 루트 파트가 임의로 바뀌는 현상을 방지합니다. - CustomPhysicalProperties: 타이어 마찰력(Friction)과 탄성을 정밀 조절합니다. 바퀴 마찰력을 1.5 이상으로 높이고 차체 무게중심을 낮추면 전복을 예방할 수 있습니다.
- Massless 속성 활용: 스포일러, 범퍼, 의자 등 외형 장식용 파트는
Massless = true로 지정하여 무게중심이 흐트러지지 않도록 만듭니다.
2. SpringConstraint를 활용한 서스펜션 튜닝
모든 지형에서 안정적인 충격 흡수와 복원력 확보:
- FreeLength vs CurrentLength:
FreeLength는 스프링의 자연스러운 기본 길이를 나타냅니다. 휠의 상하 유격을 고려해 적절한 가동 범위를 설정합니다. - 강성(Stiffness)과 감쇠(Damping): Stiffness는 차체를 지탱하는 힘이며, Damping은 지속적인 통통 튐을 억제합니다. 적절한 감쇠값을 찾아 덜컹거림 없는 부드러운 승차감을 구현합니다.
- CylindricalConstraint와의 결합: 스프링 옆에 실린더 제약조건을 배치하여 바퀴가 수평으로 흔들리지 않고 수직 축으로만 정밀하게 왕복하도록 가이드합니다.
3. 차세대 모버: AlignOrientation & AlignPosition
구형 BodyMover를 대체하는 최신 제약 물리 기법:
- 구형 BodyMover의 한계: BodyVelocity와 BodyGyro는 PGS 솔버와 충돌하여 파트 떨림과 물리 연산 부하를 유발합니다.
- AlignOrientation 전복 복구: OneAttachment 모드의 AlignOrientation을 적용해 차량이 뒤집혔을 때 Pitch와 Roll 축을 자동으로 바로잡고, 조향(Yaw)은 자유롭게 둡니다.
- 반응성(Responsiveness) 조절: 반응성을 15~30 수준으로 설정하여 급회전 시 차체가 자연스럽게 기울어지는 현실감을 부여합니다.
-- 운전자 탑승 시 네트워크 오너십 동적 위임 스크립트
local VehicleSeat = script.Parent.VehicleSeat
local Chassis = script.Parent.Chassis
VehicleSeat:GetPropertyChangedSignal("Occupant"):Connect(function()
local occupant = VehicleSeat.Occupant
if occupant then
local character = occupant.Parent
local player = game.Players:GetPlayerFromCharacter(character)
if player then
-- 운전자 클라이언트에 물리 시뮬레이션 소유권 즉시 위임
local success, err = pcall(function()
Chassis:SetNetworkOwner(player)
end)
if not success then
warn("네트워크 오너십 설정 실패:", err)
end
end
else
-- 운전자 하차: 0.2초 후 소유권을 다시 서버로 환원
task.wait(0.2)
if not VehicleSeat.Occupant then
pcall(function()
Chassis:SetNetworkOwner(nil)
end)
end
end
end)
4. 네트워크 오너십(Network Ownership)과 물리 동기화
조작 딜레이와 고무줄 현상(Rubberbanding)의 완벽한 해결:
- 지연시간 문제: 운전자가 조작할 때 물리 연산이 서버에서 돌면 핑에 의한 반응 지연과 버벅임이 발생합니다.
- SetNetworkOwner(player): 운전석에 플레이어가 탑승하면 서버 스크립트에서
Chassis:SetNetworkOwner(player)를 호출하여 물리 시뮬레이션을 해당 클라이언트로 이관합니다. - 핵 방지 검증: 클라이언트가 물리 연산을 맡더라도 서버에서는 비정상적인 속도나 순간이동 좌표를 주기적으로 모니터링해야 합니다.
5. 충돌 그룹(CollisionGroups) & 물리 틱 최적화
대규모 서버 환경에서 60 FPS 물리 연산을 보장하는 팁:
- 충돌 그룹 필터링: 차체, 바퀴, 캐릭터를 각각 별도 CollisionGroup으로 분리합니다. 바퀴와 캐릭터 간 충돌을 비활성화하면 보행자를 쳤을 때 차가 하늘로 튀는 버그를 차단할 수 있습니다.
- CanTouch & CanQuery 비활성화: 차량 내부 기계 부품의
CanTouch와CanQuery를 false로 꺼서 불필요한 충돌 감지 연산을 제거합니다. - 물리 수면(Sleep): 차량이 정차하거나 비어 있을 때는 네트워크 오너십을 nil(서버)로 돌려 물리 엔진이 수면 모드에 들어가도록 유도합니다.
Frequently Asked Questions
멀티플레이에서 차량을 운전할 때 심하게 끊기고 덜컹거리는 이유는 무엇인가요?
물리 연산이 서버에서 수행되기 때문입니다. 운전자가 탑승할 때 Chassis:SetNetworkOwner(player)를 호출하여 로컬 클라이언트에서 즉각 계산하도록 설정해야 합니다.
차가 커브를 돌 때 쉽게 뒤집히지 않게 하려면 어떻게 하나요?
차체 상단 파트들을 Massless로 설정해 무게중심을 낮추고, AlignOrientation 제약조건을 적용해 롤/피치 축의 기울기를 자동으로 복원하도록 만듭니다.
SpringConstraint의 Stiffness와 Damping 값은 어떻게 맞추나요?
Damping은 대략 Stiffness 값의 10%~20%로 설정합니다. 차가 계속 통통 튀면 Damping을 높이고, 서스펜션이 너무 딱딱하면 Damping을 줄입니다.
신규 프로젝트에서 BodyVelocity와 BodyGyro 사용을 지양해야 하는 이유는?
구형 BodyMover는 PGS 물리 솔버와 충돌하여 비정상적인 관성 왜곡을 일으키고 서버 성능을 저하시킵니다. 최신 AlignOrientation이나 LinearVelocity를 사용해야 합니다.
CollisionGroups 설정이 차량 물리 성능에 어떤 도움을 주나요?
바퀴와 내부 부품, 보행자 간의 불필요한 충돌 계산을 원천 차단하여 매 프레임 수백 회의 접촉 연산 부하를 절감할 수 있습니다.