구조 결합(Structure Cohesion)
이 모듈은 여러 파트로 구성된 네트워크 오브젝트를 협력하여 구축하는 기능을 제공합니다.
목표
이 시스템의 설계 목표는 다음과 같습니다:
- 하나의 구조는 여러 개의 구조 파트(Structure Parts)로 구성되며, 각각 독립적으로 움직일 수 있어야 합니다 (대부분 잡을 수 있음)
- 구조 파트가 하나 움직일 때, 같은 구조에 속한 모든 파트가 자연스럽게 함께 움직여야 합니다
- 여러 사용자가 동시에 파트를 추가하거나 제거할 수 있어야 하며, 충돌이나 전환 시간을 최소화하기 위해 권한 변경을 최소화해야 합니다
- 구조 파트를 기존 구조(또는 단일 파트) 근처에 놓으면 사전 정의된 결합 지점을 통해 스냅 되어야 합니다
- 두 개의 서로 다른 구조 파트를 잡으면 구조가 둘로 나뉘어야 하며, 가장 최근에 결합된 지점을 기준으로 분리되어야 합니다
- 한 손으로 구조를 분리할 수 있도록, 일부 파트는 "가벼운 무게"를 가질 수 있어야 하며, 이 파트를 잡을 경우 구조가 쉽게 분리되어야 합니다
- 선택적으로, 구조 이동 시 모든 파트의 위치를 네트워크로 전송하지 않고, 변경된 지점만 네트워크로 전송하여 대역폭을 절약할 수 있도록 설정할 수 있어야 합니다
로직 개요
여러 파트로 구성된 구조를 협력적으로 조작할 수 있도록 다음과 같은 로직을 따릅니다:
구조 파트와 파트 간 연결은 네트워크를 통해 동기화됩니다. 구조는 로컬에서 재구성되며, 생성/삭제된 결합 정보를 감지하여 재구성됩니다 (권한이 없는 파트도 포함)
구조 파트에는 여러 결합 지점이 있을 수 있으며, 다른 구조 파트의 결합 지점과 연결될 수 있습니다
결합은 한쪽 결합 지점에만 저장되므로, 해당 지점에 대한 권한만 있으면 네트워크 정보를 수정할 수 있습니다
구조 파트의 상태 권한은 여러 사용자 간에 공유될 수 있습니다. 파트를 조작하거나 결합할 때 권한이 필요합니다
구조 파트는 네트워크상에
IsMoving
프로퍼티를 저장합니다. 이를 통해 움직이는 구조를 감지하여 분리할 수 있습니다모든 결합에는 순서가 부여되어 최근 결합 여부를 판단할 수 있습니다. 이는 구조 분리 시 사용됩니다
구조는 두 가지 경우에 분리될 수 있습니다:
- 두 개 이상의 파트가 동시에 움직이는 경우
- 가벼운 무게를 가진 파트를 통해 구조가 조작되는 경우
StructureManager
는 전체 구조를 추적하고 새로운 구조를 생성하는 역할을 합니다StructurePartsManager
는 모든 파트와 결합 지점 태그를 관리하는 데 도움을 줄 수 있습니다

놓을 때(언그랩) 결합 생성
구조 파트를 놓으면 AttachClosestPartInProximity()
가 호출됩니다.
이 함수는 현재 구조 내 다른 파트의 결합 지점 중 가장 가까운 지점을 찾아 결합을 생성합니다.
결합 정보는 놓은 파트에 저장되며, 만약 권한이 없다면 먼저 권한을 가져온 후 결합을 설정합니다.

놓은 파트는 기존 파트에 맞춰 위치를 조정합니다. (움직이지 않던 파트를 기준으로 스냅)
AttachmentPoint
는 추상 클래스이며, 다음 메서드를 구현해야 합니다:
TryFindClosestAttachmentPoint(out AttachmentPoint closestPoint, out float minDistance, bool excludeSameGroupId = true)
Snap(AttachmentPoint other)
동시에 움직일 때 결합 삭제
같은 구조 안에서 두 파트가 동시에 움직이면,
가장 최근 결합된 지점을 찾아 구조를 분리합니다.

가벼운 파트 하나만 움직일 때 결합 삭제
하나의 파트만 움직이고, 구조의 StructuralCohesionMode
가 WeightBasedCohesion
일 경우,
움직이는 파트의 무게가 다른 파트보다 가벼우면 구조를 분리합니다.
만약 이 파트가 "끝"에 연결된 경우, 바로 해당 결합을 끊습니다.
그렇지 않으면 가장 무거운 섹션으로 이어지는 결합을 찾아 분리합니다.
재배치
구조가 유지되도록, 파트들이 함께 이동해야 합니다.
다음 기준에 따라 기준 파트를 선택하여 재배치합니다:
- 움직이는 파트가 기준 (있다면)
- 없다면 가장 낮은 ID를 가진 파트가 기준
- 가능한 경우 마지막 사용된 기준 파트를 계속 유지하여 불필요한 점프를 방지
재배치는 FixedUpdateNetwork
에서 실행되며, LateUpdate
에서도 렌더링 일관성을 위해 수행됩니다.
태그 호환성
AttachmentPoint
에서는 다음을 관리합니다:
AttachmentPointTags
: 결합 지점의 태그CompatibleAttachmentPointTags
: 연결할 수 있는 결합 지점의 태그 목록
스냅 감지 기반
StructurePart
클래스는 그 자체로 잡기(Grabbing) 기능을 가지지 않습니다.
GrabbableStructurePart
가 XRShared 애드온을 통해 IsMoving
을 설정하고, 결합 처리를 담당합니다.
스냅 로직은 Magnets 애드온을 기반으로 구현되었습니다.

선택적 컨테인먼트(Containment)
대역폭 최적화를 위해 NetworkTransform
의 부모-자식 관계를 이용할 수 있습니다.
부모가 움직이면 자식들의 네트워크 업데이트가 필요하지 않게 됩니다.
ContainmentHandler
는 구조 파트들을 자동으로 하나의 컨테이너에 묶습니다.
ProxyGrabbing
은 실제로 컨테이너를 움직이도록 동작을 재정의합니다.
안정된 구조 상태(변동 없음, 모두 컨테이너 있음)에서는 구조 파트들의 재배치를 건너뛸 수 있습니다.
주의: 현재 구현은 컨테이너를 반복 생성/제거하기 때문에, 추후 풀링 최적화가 필요합니다.
설정 방법
StructureManager
를 씬에 추가해야 합니다.
선택적 컨테인먼트 설정
ContainmentManager
를 추가해야 합니다.- 모든
GrabbableStructurePart
옆에ContainmentHandler
와ProxyGrabbing
컴포넌트를 추가해야 합니다. ContainmentManager
의disableContainerParenting
옵션을 통해 빠르게 비교할 수 있습니다.
독립적인 AttachmentPoint 사용
AttachmentPoint
클래스는 구조 없이도 사용할 수 있습니다.
단순히 두 개의 오브젝트 간 "연결"을 동기화하고 알리는 역할을 합니다.
구조 내부에서 사용하려면 IStructurePartPoint
를 구현해야 합니다 (MagnetStructureAttachmentPoint
참고).
MagnetAttachmentPoint 예시
두 마그넷이 서로 스냅 할 때의 연결 추적에 사용할 수 있습니다.
이 예시는 MagnetAttachmentPoint
클래스에서 보여줍니다.
의존성
- XRShared 애드온
- Magnets 애드온
다운로드
이 애드온의 최신 버전은 Industries 애드온 프로젝트에서 다운로드할 수 있습니다.
지원 토폴로지
- 공유 모드
변경 기록
- 버전 2.0.0: 첫 번째 릴리스