가구를 45도 회전시켰다.
근데 뭔가 이상하다.
문제
100x50 사각형을 45도 회전하면?
원본:
┌────────────┐
│ │ 50px
└────────────┘
100px
45도 회전 후 바운딩 박스:
┌──────────────────┐
│ ╱╲ │
│ ╱ ╲ │ ~106px
│ ╱ ╲ │
│ ╱______╲ │
└──────────────────┘
~106px
회전하면 바운딩 박스가 커진다.
getClientRect()
Konva에서 회전된 객체의 실제 바운딩 박스:
const rect = node.getClientRect();
// { x, y, width, height } - 회전 반영된 값
원래 width/height와 다르다.
충돌 감지 문제
가구끼리 겹치는지 확인하려면?
function isOverlapping(a: Furniture, b: Furniture) {
// 단순 AABB 충돌
return !(
a.x + a.width < b.x ||
a.x > b.x + b.width ||
a.y + a.height < b.y ||
a.y > b.y + b.height
);
}
회전 안 했으면 이게 맞는데, 회전하면 틀림.
해결 1: AABB 확장
회전된 바운딩 박스로 체크:
function isOverlapping(nodeA: Konva.Node, nodeB: Konva.Node) {
const rectA = nodeA.getClientRect();
const rectB = nodeB.getClientRect();
return !(
rectA.x + rectA.width < rectB.x ||
rectA.x > rectB.x + rectB.width ||
rectA.y + rectA.height < rectB.y ||
rectA.y > rectB.y + rectB.height
);
}
근데 이건 정확하진 않음. 실제론 안 겹치는데 겹친다고 나올 수 있다.
해결 2: SAT 알고리즘
정확한 충돌 감지하려면 SAT (Separating Axis Theorem).
function getCorners(node: Konva.Node) {
// 회전된 네 꼭짓점 좌표 계산
const transform = node.getAbsoluteTransform();
const points = [
{ x: 0, y: 0 },
{ x: node.width(), y: 0 },
{ x: node.width(), y: node.height() },
{ x: 0, y: node.height() }
];
return points.map(p => transform.point(p));
}
function satCollision(cornersA: Point[], cornersB: Point[]) {
// ... SAT 구현
}
복잡하다. 평면도 도구에선 오버스펙.
타협: AABB로 충분
어차피 가구 겹쳐도 에러는 아님. 사용자가 알아서 조절하면 됨.
그냥 AABB 체크만 하고, 살짝 겹치는 건 무시하기로 했다.
충돌 감지는 “대충 경고” 정도로만 쓰면 됨.
회전 중심점
Konva는 기본적으로 좌상단이 회전 중심.
중앙 기준으로 회전하려면:
{
offsetX: width / 2,
offsetY: height / 2,
x: x + width / 2,
y: y + height / 2
}
offset 설정하면 그 점이 기준이 됨.
다음 글에서 문 시스템.