let rectLocal = this.node.getBoundingBox();
let rectWorld = this.node.getBoundingBoxToWorld();
코코스 크리에이터에는 유니티의 RectTransform에 대응되는 BoundingBox가 있다.
함수의 리턴값은 x, y, width, height로 구성된 cc.Rect 다.
이때 x, y는 노드의 왼쪽 하단 모서리를 의미한다.
let rectA = this.boxA.getBoundingBoxToWorld();
let rectB = this.boxB.getBoundingBoxToWorld();
if ((rectA.x <= rectB.x) && // Left
(rectA.x + rectA.width >= rectB.x + rectB.width) && // Right
(rectA.y + rectA.height >= rectB.y + rectB.height) && // Top
(rectA.y <= rectB.y)) // Bottom
{
return true;
}
씬에 Box A와 Box B가 위와 같이 배치돼 있을 때,
BoundingBox를 활용해 Box B가 Box A 안에 있는지, 조금이라도 밖으로 벗어났는지 확인할 수 있다.
위 기능을 활용해 ScrollView 안에 있는 아이템을 클릭하면 ScrollView는 이동하지 않고,
ScrollView를 벗어나는 아이템을 클릭하면 해당 아이템이 ScrollView 안에 들어오도록
ScrollView를 자동으로 움직이는 기능을 만드려고 했다.
위의 움짤은 구현이 완료된 상태고, 처음에 시행착오를 겪게 됐는데 그 과정을 정리해보려고 한다.
핑크색은 scrollView 노드, 초록색은 마스크에 의해 반쯤 잘린 targetToggle 노드다.
이 상태에서 targetToggle을 클릭한 후 디버깅 해봤다.
let svBox = this.scrollView.node.getBoundingBoxToWorld();
let toggleBox = targetToggle.getBoundingBoxToWorld();
눈에 보이는대로라면, Toggle Button Box(toggleBox)의 y값(Bottom)은 ScrollView Box(svBox)의 y 값보다 작아야 하지만
실제로는 그렇게 나오지 않았다.
이로 인해 Toggle Button이 ScrollView 안에 들어있는지 확인하는 코드가 정상적으로 작동하지 않았다.
그 이유는 ScrollView를 스크롤링할 때마다 svBox의 y 값이 항상 다르게 나오는 문제였다.
스크롤링을 하면 ScrollView 노드는 움직이지 않고, ScrollView 안의 Content 노드가 움직이는 게 맞기 때문에 이 현상이 이해가지 않았다.
let svWorldPos = this.scrollView.node.parent.convertToWorldSpaceAR(this.scrollView.node.position);
실제로 ScrollView의 월드 포지션은 항상 고정된 값을 유지했다.
정리하면, 노드 안에 노드가 들어있는지 확인할 때
노드 중 하나가 ScrollView면 BoundingBox 함수가 정확한 값을 리턴하지 않을 수 있다는 것이다.
let svTop = this.scrollView.node.parent.convertToWorldSpaceAR(svPos.add(new cc.Vec3(0, ((1 - this.scrollView.node.anchorY) * this.scrollView.node.height), 0)));
let svBottom = this.scrollView.node.parent.convertToWorldSpaceAR(svPos.sub(new cc.Vec3(0, this.scrollView.node.anchorY * this.scrollView.node.height, 0)));
let toggleTop = targetToggle.parent.convertToWorldSpaceAR(togglePos.add(new cc.Vec3(0, ((1 - targetToggle.anchorY) * targetToggle.height), 0)));
let toggleBottom = targetToggle.parent.convertToWorldSpaceAR(togglePos.sub(new cc.Vec3(0, targetToggle.anchorY * targetToggle.height, 0)));
// 다음 이동하려는 토글이 스크롤 뷰 바운더리 안에 있으면 이동할 필요 없음
if (toggleBottom.y >= svBottom.y && toggleTop.y <= svTop.y) {
return;
}
let top = toggleIdx * this.sourceToggle.height;
maxScrollOffsetX = this.scrollView.getScrollOffset().x;
maxScrollOffsetY = top;
this.scrollView.scrollToOffset(cc.v2(maxScrollOffsetX, maxScrollOffsetY), 0.5);
결국 ScrollView와 ToggleButton의 월드 포지션을 구한 뒤
ScrollView의 height, ToggleButton의 height를 더하거나 뺀 뒤 Top과 Bottom을 구해서
Toggle Button이 ScrollView를 벗어나는지 체크했다.
ScrollView와 ToggleButton의 월드 포지션은 해당 노드의 가운데가 아닐 수 있다.
anchorY가 1.0이면 월드 포지션은 노드의 Top을 의미하기 때문에, height를 더하거나 뺄 때는 anchorY도 고려해야 한다.
'Cocos Creator' 카테고리의 다른 글
노드를 화면 가득 차게 늘리는 법 #2 (1) | 2023.04.06 |
---|---|
간단한 미니 맵 (0) | 2023.04.03 |
Spine (2) | 2023.02.16 |
런타임 중에 노드의 뎁스(Depth) 정렬하기 (0) | 2023.01.19 |
스크롤 뷰(Scroll View)와 스크롤 바(Scroll Bar) (0) | 2022.12.13 |