wan의 개발일기

RoomCraft 개발일지 #4. 충돌 감지 — 벽 밖 제한 + 겹침 경고 본문

1인 게임개발 활동/가구배치 시뮬레이터

RoomCraft 개발일지 #4. 충돌 감지 — 벽 밖 제한 + 겹침 경고

wan_ 2026. 6. 27. 21:25
소스코드 → github.com/Jywan/RoomCraft

들어가며

지난 편에서 가구를 드래그로 움직이는 건 됐는데, 벽 밖으로 나가거나 가구끼리 겹치는 게 가능했다. 실제로 가구를 배치할 때 이러면 안 되니까, 이번에는 충돌 감지를 추가한다.

구현할 기능:

  • 가구가 방 범위를 벗어나면 빨간색 경고
  • 다른 가구와 겹치면 빨간색 경고
  • 마우스를 떼는 순간 무효한 위치면 마지막 유효 위치로 자동 복귀

경계 검사 설계

방의 크기를 알고 있으니까, 가구의 Collider bounds가 방 범위를 벗어나는지 계산하면 된다.

방의 중심이 (0, 0, 0)이고 크기가 4m × 3m이면, X축으로 -2 ~ +2, Z축으로 -1.5 ~ +1.5가 유효 범위다. 가구의 bounds.min/max가 이 범위를 넘으면 밖으로 나간 거.

FurnitureBounds 구현

방 경계 검사

public bool IsInsideRoom(FurnitureObject furniture)
{
    Bounds bounds = furniture.GetComponent<Collider>().bounds;

    float halfWidth = roomWidth / 2f;
    float halfDepth = roomDepth / 2f;

    // 가구의 경계가 방 범위를 벗어나는지 체크
    if (bounds.min.x < -halfWidth || bounds.max.x > halfWidth)
        return false;
    if (bounds.min.z < -halfDepth || bounds.max.z > halfDepth)
        return false;

    return true;
}

Collider.bounds는 월드 좌표 기준으로 오브젝트가 차지하는 영역을 반환한다. 회전해도 제대로 계산해주니까 따로 회전 처리를 할 필요가 없다.

가구 겹침 검사

public bool IsOverlapping(FurnitureObject furniture)
{
    Bounds myBounds = furniture.GetComponent<Collider>().bounds;

    FurnitureObject[] allFurniture = FindObjectsByType<FurnitureObject>(FindObjectsSortMode.None);

    foreach (FurnitureObject other in allFurniture)
    {
        if (other == furniture) continue; // 자기 자신은 스킵

        Bounds otherBounds = other.GetComponent<Collider>().bounds;

        if (myBounds.Intersects(otherBounds))
            return true;
    }

    return false;
}
Bounds.Intersects()가 두 경계 상자가 겹치는지 한 줄로 알려준다. 가구 수가 적으니 성능 문제는 없다.

종합 검증 + 시각 피드백

public bool ValidatePosition(FurnitureObject furniture)
{
    bool insideRoom = IsInsideRoom(furniture);
    bool overlapping = IsOverlapping(furniture);

    Renderer renderer = furniture.GetComponent<Renderer>();

    if (!insideRoom || overlapping)
    {
        // 빨간색 경고
        renderer.material.color = warningColor;
        return false;
    }
    else
    {
        // 정상: 선택 색으로 복귀
        furniture.Select();
        return true;
    }
}

드래그에 연동

기존 HandleDrag()를 수정해서, 드래그 중에 매 프레임 ValidatePosition()을 호출한다.

private void HandleDrag()
{
    if (selectedFurniture == null || !isDragging) return;

    if (Input.GetMouseButtonUp(0))
    {
        isDragging = false;

        // 최종 위치가 무효하면 마지막 유효 위치로 복귀
        if (bounds != null && !bounds.ValidatePosition(selectedFurniture))
        {
            selectedFurniture.MoveTo(lastValidPosition);
            selectedFurniture.Select();
        }
        return;
    }

    Ray ray = mainCamera.ScreenPointToRay(Input.mousePosition);
    RaycastHit hit;

    if (Physics.Raycast(ray, out hit, 100f, floorLayer))
    {
        selectedFurniture.MoveTo(hit.point);

        // 드래그 중 실시간 검증
        if (bounds != null)
        {
            bool valid = bounds.ValidatePosition(selectedFurniture);
            if (valid)
                lastValidPosition = hit.point;
        }
    }
}
핵심은 “드래그 중에는 경고만 보여주고, 마우스를 뗐을 때 비로소 복귀시킨다”는 점이다. 드래그 도중에 강제로 못 가게 막으면 UX가 답답해진다.

실행 결과

벽 밖이나 겹친 위치로 드래그하면 빨간색으로 경고
정상 위치에 배치된 상태

마우스를 떼면 빨간색이었던 가구가 자동으로 마지막 유효 위치로 돌아간다.


정리

기능핵심 구현
방 경계 검사Collider.bounds의 min/max를 방 크기와 비교
겹침 검사Bounds.Intersects()로 다른 가구와 교차 여부 판단
시각 피드백무효 위치면 빨간색, 유효면 선택 색으로 복귀
자동 복귀마우스 업 시 무효 → lastValidPosition으로 이동

다음 편에서는 사용자가 직접 카테고리/치수/색상을 선택해서 가구를 만드는 UI를 구현할 예정이다.