Update README.md

This commit is contained in:
2026-05-04 15:44:57 +00:00
parent 3538374b83
commit 19a6c21701

View File

@@ -65,43 +65,13 @@
### 5. 카트 시스템
<img src="/readme/cart1.png" width="400">
<img src="/readme/cart2.png" width="200"> 해당 영역에 아이템이 들어오면,
아이템의 움직임이 없어질 때(혹은 0.3초가 지났을 때) 물리영향을 끄고 카트의 움직임을 ParentConstraint 로 추적한다.
VR에서 "물건을 카트에 담는다"는 단순해 보여도 실제로는 네 가지 문제가 동시에 발생한다. 각 문제를 다음과 같이 해결했다.
**(1) 플레이어가 카트와 함께 움직이게 만들기 — `ParentConstraint`**
- 카트에 `ParentConstraint`를 붙이고 source로 `XROrigin`을 잡음. 결과적으로 **XROrigin(=플레이어)이 카트의 자식처럼 따라다님**.
- `ActiveRide()` / `DeactiveRide()`로 constraint 활성/비활성 토글 → 카트에서 내릴 때는 constraint만 끊으면 되고, XROrigin 계층은 건드리지 않음.
**(2) 물건이 카트와 같이 안 움직이는 문제 — Reparent + Kinematic**
- `Rigidbody` 상태로 바구니에 얹혀 있어도 카트가 움직이면 충돌·관성으로 즉시 튀어나옴.
- 정착이 확정되면 `transform.SetParent(_itemRoot)`로 카트 하위에 부착하고 `isKinematic = true`로 전환. 이때부터는 카트의 transform을 그대로 따라가고 물리 시뮬레이션에서 빠짐.
**(3) 관성으로 물건이 빠져나오는 문제 — 정착 타이머**
- 단순히 "트리거 진입 = 부착"으로 하면 던져 넣자마자 위로 튀는 운동량 때문에 카트 밖으로 다시 튀어나감. 게다가 한 번 부착되면 더 이상 던질 수 없음(움직이는 카트 바깥으로 떨어뜨릴 수 없음).
- `OnDetectionStay`에서 매 프레임 검사:
- `linearVelocity.magnitude > _settleVelocity`(임계 속도)면 타이머 리셋 — 아직 움직이는 중
- 임계 속도 이하 상태가 `_settleDuration` 동안 **연속으로 유지**되면 부착 확정
- `XRGrabInteractable.isSelected`(현재 손에 잡혀있음)면 타이머 무효화 — 잡고 있는 동안엔 절대 부착되지 않음
- `_settleTimer``Dictionary<Rigidbody, float>`로 아이템별 타이머를 독립 관리.
**(4) 물건 위에 물건을 쌓는 문제**
- 위 정착 타이머는 **각 Rigidbody별로** 독립적으로 흐름. 아래 물건이 먼저 정착해 kinematic이 되면, 그 위에 떨어뜨린 물건은 단단한 받침대 위에서 속도가 0에 수렴 → 자기 차례에 정착 → 다음 물건의 받침대가 됨.
- 트리거 영역(`RideDetectionZone`)을 카트 바구니보다 충분히 높게 잡아 쌓인 물건도 검사 대상에 포함.
**(5) 카트에서 다시 꺼낼 때의 함정 — `retainTransformParent` & isKinematic 복원 덮어쓰기**
- `XRGrabInteractable`**잡힐 때 부모/kinematic 상태를 스냅샷**해 두고, 놓을 때 그 상태로 되돌린다. 카트에서 부착될 때 부모=ItemRoot, kinematic=true로 잡혔으니, 손으로 꺼냈다가 어딘가 놔도 **다시 ItemRoot 자식으로 + kinematic 상태로** 복원되어 공중에 박제되는 버그.
- 두 단계로 차단:
- 부착 시 `grab.retainTransformParent = false` — 부모 복원 비활성화.
- 꺼낼 때 `selectEntered` → 즉시 부모 해제, `selectExited`에서 `isKinematic = false`를 다시 강제로 덮어쓰기.
```
물건 던져넣기 → 트리거 진입 → [속도 < 임계 && 잡혀있지 않음] 0.3s 유지
→ SetParent(ItemRoot) + isKinematic=true + retainTransformParent=false
→ 카트 이동에 종속
손으로 다시 잡음 → SetParent(null) → 일반 물리로 복귀
→ 놓을 때 isKinematic=false 강제 복원
```
### 6. 씬 전환 라이프사이클
- `ITransScenePossible` 인터페이스 — 씬 로드 직후 `OnSceneLoaded()`를 일괄 호출해 **씬을 가로지르는 매니저(GameManager 등)가 새 씬의 매니저(GameSceneUIManager)와 다시 결선**되도록 함. 싱글톤이 죽지 않은 채 새 씬의 UI 참조만 갱신.