1. 좌표계
유니티에 월드 스페이스(World Space)와 로컬 스페이스(Local Space) 개념이 있듯이
코코스 크리에이터에도 월드 좌표계(World Coordinate)와 로컬 좌표계(Local Coordinate)가 있다.
이는 공식 레퍼런스 사이트에서의 명칭이며
실제로 API 함수들의 이름을 보면 월드 스페이스(World Space)와 노드 스페이스(Node Space)라고 부른다.
(공식 레퍼런스 링크 https://docs.cocos.com/creator/manual/en/concepts/scene/coord.html)
동일한 오브젝트를 기준으로 월드 스페이스에서의 포지션을 월드 포지션,
로컬 스페이스에서의 포지션을 로컬 포지션이라고 부른다.
월드 포지션은 전체 3D 월드의 원점(0,0,0)을 기준으로 오브젝트의 절대적인 위치를 의미하고
로컬 포지션은 부모 오브젝트를 기준으로 오브젝트의 상대적인 위치를 의미한다.
유니티는 하나의 오브젝트에서 transform.position으로 월드 포지션을 얻을 수 있고
transform.localPosition으로 로컬 포지션을 얻을 수 있다.
하지만 코코스 크리에이터에서 node.position은 노드 포지션(=로컬 포지션)을 의미하며
cc.Node가 월드 포지션은 멤버 변수로 가지고 있지 않아서 따로 변환 과정을 거쳐 얻어야 한다.
1. 월드 포지션과 노드 포지션이 필요한 이유
이러한 구조에서 Coin을 Area01~03 노드 위치로 이동시키려면 어떻게 해야 할까?
Area01~03의 노드 포지션 값을 구해서 Coin이 그만큼 이동하도록 코드를 작성하면 원하는 결과를 얻을 수 없을 것이다.
이유는 부모 노드의 포지션이 어떤지에 따라서, Coin과 Area01을 둘 다 (0,0) 좌표에 두어도 겹치지 않을 수 있다.
각자 다른 부모 노드가 아닌, 동일한 노드 또는 월드를 기준으로 포지션을 새로 구해서 비교해야 한다.
2. 좌표계 변환
// World Space에서 Area의 World Position
let areaWorldPosition = this.area[0].parent.convertToWorldSpaceAR(this.area[0].position);
// Coin의 Node Space 안에서 Area의 Node Position
let areaNodePosition = this.coin.parent.convertToNodeSpaceAR(areaWorldPosition);
// Coin을 Area 위치로 이동
cc.tween(this.coin).to(1.0, {position:areaNodePosition}).start();
방법은 간단하다. 먼저 Area01의 노드 포지션을 월드 포지션으로 변경한다.
그렇게 얻은 월드 포지션을 Coin 노드가 속해있는 노드 스페이스 기준의 노드 포지션으로 다시 변환한다.
최종적으로 얻은 포지션으로 Coin을 이동시키면 원하는 결과를 얻을 수 있다.
주의할 점은, convertToWorldSpaceAR, convertToNodeSpaceAR 함수를 실행하는 노드는
coin이나 area[0] 노드가 아닌, 그 노드의 parent 노드여야한다.
그래야 coin과 area[0] 노드에 적용돼있는 scale과 rotation 값까지 포함해서 좌표를 계산하기 때문이다.
let areaNodePosition = this.coin.convertToNodeSpaceAR(areaWorldPosition)
.multiplyScalar(this.coin.scale)
.rotate(this.coin.chip.angle * Math.PI / 180);
그렇지 않으면 이런 식으로 scale과 rotation 값을 추가로 계산해줘야 한다.
3. 응용
씬의 구조는 위와 같다. A Side의 노드 포지션은 (-400,0), B Side의 노드 포지션은 (400,0) 이다.
A Side에 속해있는 jewel 오브젝트를 B Side로 옮기면
화면 상에서 jewel 오브젝트는 오른쪽으로 이동하지 않고 제자리에 멈춰있다. 대신 jewel의 노드 포지션이 변경된다.
const {ccclass, property} = cc._decorator;
@ccclass
export default class WorldTest extends cc.Component {
@property(cc.Node) sideA: cc.Node = null;
@property(cc.Node) sideB: cc.Node = null;
@property(cc.Node) jewel: cc.Node = null;
start () {
this.jewel.setParent(this.sideB);
}
}
위와 같은 스크립트를 만들어서 런타임 중에 실행해보자.
그럼 에디터에서 jewel 노드를 A Side에서 B Side를 옮겼을 때와 다른 결과가 나온다.
정리하자면 아래와 같다.
- 에디터에서 노드의 부모를 바꿈 -> 화면 상에서 노드는 움직이지 않고 노드의 노드 포지션이 바뀜.
- 스크립트에서 노드의 부모를 바꿈 -> 화면 상에서 노드가 움직이고 노드의 노드 포지션은 바뀌지 않음.
// case 1: 부모 노드 유지 & 화면 상에서 위치 움직이지 않음
// Do Nothing
// case 2: 부모 노드 유지 & 화면 상에서 위치 움직임
let afterPos = this.sideA.convertToNodeSpaceAR(this.sideB.convertToWorldSpaceAR(this.jewel.position));
this.jewel.setPosition(afterPos);
// case 3: 부모 노드 교체 & 화면 상에서 위치 움직이지 않음
let afterPos = this.sideB.convertToNodeSpaceAR(this.sideA.convertToWorldSpaceAR(this.jewel.position));
this.jewel.setParent(this.sideB);
this.jewel.setPosition(afterPos);
// case 4: 부모 노드 교체 & 화면 상에서 위치 움직임
this.jewel.setParent(this.sideB);
네 가지 케이스에 대한 코드 정리는 위와 같다.
'Cocos Creator' 카테고리의 다른 글
오브젝트 풀링 (Ojbect Pooling) (0) | 2022.04.07 |
---|---|
Layout Update (0) | 2022.04.06 |
[2.4.5 버그] cc.lerp (0) | 2022.04.01 |
클릭(터치)한 지점의 좌표 구하기 (0) | 2022.03.25 |
ParticleSystem, Animation 재시작 (0) | 2022.03.18 |