1. 앵커의 정의화 position과의 관계
2. 부노노드의 앵커의 변화에 따른 자식노드에 끼치는 영향 과 부노노드에 액션이 작용할때
자식노드가 어떤 영향을 받는가?
3. Z-order에 대한 설명 간략히
4. Tag의 유일성과 중첩성(분류)
5. removechild()의 영향과 자식 노드의 재사용에 대해서
6. 부모노드가 할매노드에서 제거 될때 자식노드의 상태
액션 콜백과 콜백.
1.예제 분석 목적:
=>CCNode 주요속성의 변경방법과 속성이 변경될때 화면에 어떻게 나타 나는가를 확인
2.확인속성
* 코드 설명중 속성의 변화에 따른 액션 부분은 제외 하였습니다.
3-1 Test1 ( Transform Anchor )
Sprite sp0 = Sprite.sprite("grossini.png");
Sprite sp1 = Sprite.sprite("grossinis_sister1.png");
Sprite sp2 = Sprite.sprite("grossinis_sister2.png");
Sprite point0 = Sprite.sprite("r1.png");
Sprite point1 = Sprite.sprite("r1.png");
Sprite point2 = Sprite.sprite("r1.png");
point0.scale(0.25f);
point1.scale(0.25f);
point2.scale(0.25f);
sp0.setPosition(s.width/2, s.height / 2);
point0.setPosition(sp0.getPositionX(), sp0.getPositionY());
sp0.setAnchorPoint(0.5f, 0.5f);
sp1.setPosition(s.width/2 - 100, s.height / 2);
point1.setPosition(sp1.getPositionX(), sp1.getPositionY());
sp1.setAnchorPoint(0, 0);
sp2.setPosition(s.width/2 + 100, s.height / 2);
point2.setPosition(sp2.getPositionX(), sp2.getPositionY());
sp2.setAnchorPoint(1, 1);
addChild(sp0);
addChild(sp1);
addChild(sp2);
addChild(point0, 1);
addChild(point1, 1);
addChild(point2, 1);
사전 필요 지식
1. sprite는 기본적으로 앵커점을 0.5f 0.5f 로 잡고 시작합니다.(이미지의 센터점)
2. cocos2d의 좌표계는 Top-Left 가 아니라 Bottom-Left 입니다.
이에 반해 안드로이드의 화면 좌표계는 Top-Left 라서 처음 cocos2d를 접하시는 분들이
좀헷갈려합니다.
코드 설명
sp0, sp1,sp2 를 화면센터에 수평정렬입니다.
point0,point1,point2 는 sp0, sp1, sp2의 앵커 포인트를 가리키고 있습니다.
그리고 나서 sp0 sp1 sp2 의 앵커 포인트를 변형합니다. 그리고 나타난 화면은
처음 앵커 포인트를 알게된사람들은 언듯 이해가 가지 않습니다.
이에 대해서 자세한 설명은 앵커포인트와 비슷한 이름을 지닌 position 과 비교하면 좀 더
이해가 잘 될듯합니다.
position은 부모Node 의 0,0 좌표에서 얼마나 떨어져 있는 지를 x와 y로 나타 낸것입니다.
Node가 (100,200)이면 부모노드에서 x 100만큼 y 200만큼 떨어진 곳에 이란것입니다.
이때 자신의 기준은 무엇일까요? 머 앵커를 설명하는 자리니까 당연히 앵커가 되겟죠.
다시말해 사이즈 가로50 세로50인 이미지를 부모노드에서 (100,200)만큼 움직이라고 하는데
어디를 기준으로 잡아야 할까요? 이미지의 왼쪽아래? 오른쪽아래? 정가운데?
이게 바로 앵커입니다. Node의 크기가 사용자마다 다르니 특정 크기값으로 하지 말고
이미지=Node의 원래 사이즈를 가로 세로 1 로 잡고 그 비율로 나타낸것입니다.내부적으로 화면
에 표시 될때는 이미지크기에 맞추어 특정 좌표로 표현되지만 우리가 그것까지 볼필요는
업습니다.
(추후 강좌를 전체적인 업데이트 할 때 이미지도 포함하여 반영하겟습니다.)
3-2 Test2 ( Transform Anchor and Children )
Sprite sp1 = Sprite.sprite("grossinis_sister1.png");
Sprite sp2 = Sprite.sprite("grossinis_sister2.png");
Sprite sp3 = Sprite.sprite("grossinis_sister1.png");
Sprite sp4 = Sprite.sprite("grossinis_sister2.png");
sp1.setPosition(100, s.height / 2);
sp2.setPosition(s.width - 100, s.height / 2);
addChild(sp1);
addChild(sp2);
sp3.scale(0.25f);
sp4.scale(0.25f);
sp1.addChild(sp3);
sp2.addChild(sp4);
IntervalAction a1 = RotateBy.action(2, 360);
IntervalAction a2 = ScaleBy.action(2, 2);
Action action1 = RepeatForever.action(Sequence.actions(a1, a2, a2.reverse()));
Action action2 = RepeatForever.action(Sequence.actions(a1.copy(), a2.copy(), a2.reverse()));
sp2.setAnchorPoint(0, 0);
sp1.runAction(action1);
sp2.runAction(action2);
이미 3-1에서 설명을 잘 이해 하셨다면 이번 내용은 어렵지 않겟 받아 들일것이라 생각합니다.
자식Node의 위치=position은 부모의 0.0 점을 기준으로 해서 결정된다 라고 위에서 이야기 드렸습니다. 그럼 그 부모노드가 속해있는 부모노드 그러니까 할배노드라 합시다.
부모노드의 position은 할배노드의 0,0을 기준하겟죠, 결국 자식노드의 위치는 부모노드뿐만 아니라 할배노드에게도 영향을 받습니다.
이것을 액션의 rotate(회전변화)을 이용하여 상당히 적절하게 표현되고 있습니다. 실제 코드를
돌려보기 전에 머리속으로 한번 그려보세요
할배노드 = Test2
부모노드 = sp1, sp2
자식노드 = sp3, sp4
입니다. 그와 더불어 부모노드에 대한 액션은 자식 노드에도 영향을 끼칩니다.
(강좌 업데이트때 이미지추가)
3-3 Test3 (Z Order)
Sprite sp1 = Sprite.sprite("grossinis_sister1.png");
Sprite sp2 = Sprite.sprite("grossinis_sister2.png");
Sprite sp3 = Sprite.sprite("grossini.png");
sp1.setPosition(20, 80);
sp2.setPosition(70, 50);
sp3.setPosition(s.width / 2, s.height / 2);
xy 축에 더불어 한가지 축 z축 입니다. z값이 양수면 화면앞 그러니까 사용자의 눈쪽
가까이 위치하고 음수면 ,화면 너머에 위치합니다. 그러니까 이미지가 겹쳐질때 맨위로 오느냐
맨뒤로 가서 가려지느냐의 차이를 설명한것입니다.
(참고이미지는 강좌 업데이트 하면서추가 하겟습니다.)
3-4 Test4 (Tags )
{
Sprite sp1 = Sprite.sprite("grossinis_sister1.png");
Sprite sp2 = Sprite.sprite("grossinis_sister2.png");
sp1.setPosition(100, s.height / 2);
sp2.setPosition(s.width - 100, s.height / 2);
addChild(sp1, 0, 2);
addChild(sp2, 0, 3);
schedule("delay2", 2.0f);
schedule("delay4", 4.0f);
}
public void delay2(float dt) {
CocosNode node = getChild(2);
IntervalAction action1 = RotateBy.action(1, 360);
node.runAction(action1);
}
public void delay4(float dt) {
unschedule("delay4");
removeChild(3, false);
}
태그는 말그대로 꼬리표입니다.
안드로이드에서는 View클래스에 id 를 할당합니다.
그 아이디를 기반으로 R.java 클래스 변수로 등록되고 액티비티
어디에서든 접근 가능합니다.
그럼 cocos2d에 대한 구분자는 어떻게 할까요 ?
바로 TAG입니다
안드로이드 id는 유일한 값입니다 이는 어플리케이션 package에서 관리
하기때문입니다.
그럼 cocos2d에서는 tag는 어디서 관리할까요?
바로 자기 자신이 관리 합니다.
그럼 으로서 활용방법은 2가지 입니다.
Node의 독립성을 확보하기 위해 각기 고유 코드값으로 줄수도 있고
분류를 위한 비슷한 역활을 하는 Node들에서 공통의 값을 줄수도 있습니다.
3-5 remove and cleanup
public Test5() {
super();
CCSprite sp1 = CCSprite.sprite("grossinis_sister1.png");
CCSprite sp2 = CCSprite.sprite("grossinis_sister2.png");
sp1.setPosition(CGPoint.make(100, 160));
sp2.setPosition(CGPoint.make(380, 160));
CCIntervalAction rot = CCRotateBy.action(2, 360);
CCIntervalAction rot_back = rot.reverse();
//CCRepeatForever은 CCAction으로 받을것
CCAction forever = CCRepeatForever.action(
CCSequence.actions(rot, rot_back));
CCAction forever2 = forever.copy();
// forever.setTag(101);
// forever2.setTag(102);
addChild(sp1, 0, kTagSprite1);
addChild(sp2, 0, kTagSprite2);
sp1.runAction(forever);
sp2.runAction(forever2);
schedule("addAndRemove", 2.0f);
}
public void addAndRemove(float dt) {
CCNode sp1 = getChildByTag(kTagSprite1);
CCNode sp2 = getChildByTag(kTagSprite2);
removeChild(sp1, false);
removeChild(sp2, true);
addChild(sp2, 0, kTagSprite2);
addChild(sp1, 0, kTagSprite1);
}
기술됩니다. 이는 단지 화면에서만 사라지는 것이 아니라
자식노드가 가지고 있는 액션과 콜백/selector 는 어떻게 되는 것인가에 대한 예
보여 주고 있습니다
removeChild(sp1, false);
removeChild(sp2, true);
에서 보는 바와 같이 두번째 파라미터를 true로 하면 부모노드에서 자식노드를 삭제함과
동시에 자식노드의 액션과 콜백을 전부 초기화 하여 버립니다.
false로 한다면 액션과 콜백을 남겨두고 단지 소속만을 없애 버릴뿐입니다.
액션은 어디에 저장 되어 있을까?
removeChild(sp1, false);
removeChild(sp2, true);
분명 Layer의 child를 제거 했는데도 불구하고
액션이 남이 있다면 .child의 action은 최소한 부모에게로 등록되지 않는다.
그럼 ActionManager에 등록될때 child의 정보가 넘어간다는 소리인것 같은데 ㅎㅎ. ㅎ
소스 찾아 들어 가보니 역시 거기에 남아 있었다 .
ActionManager 의 ConcurrentArrayHashMap 에 저장 되어 있어다 .
private final ConcurrentArrayHashMap<CCNode, HashElement> targets;
그러니까 다시 활성화 되게 layer에 등록시키면 AcManager가 알아서 찾아서 쓴다
멀보고 할까?
addchild 안에 들어 가보면 뒤에 true와 false로 나뉜다
ActionManager는 이것을 보고 액션은 실행시킬지 말지를 결정한다.
무한 리핏액션이 아니면 액션이 종료되는 순간 이값은 false가 된다.
3-6 Test6 ( Remove with Children )
public Test6() {
CCSize s = Director.sharedDirector().winSize();
Sprite sp1 = Sprite.sprite("grossinis_sister1.png");
Sprite sp11 = Sprite.sprite("grossinis_sister1.png");
Sprite sp2 = Sprite.sprite("grossinis_sister2.png");
Sprite sp21 = Sprite.sprite("grossinis_sister2.png");
sp1.setPosition(100, s.height / 2);
sp2.setPosition(s.width - 100, s.height / 2);
IntervalAction rot = RotateBy.action(2, 360);
IntervalAction rot_back = rot.reverse();
Action forever1 = RepeatForever.action(Sequence.actions(rot, rot_back));
Action forever11 = forever1.copy();
Action forever2 = forever1.copy();
Action forever21 = forever1.copy();
addChild(sp1, 0, kTagSprite1);
sp1.addChild(sp11);
addChild(sp2, 0, kTagSprite2);
sp2.addChild(sp21);
sp1.runAction(forever1);
sp11.runAction(forever11);
sp2.runAction(forever2);
sp21.runAction(forever21);
schedule("addAndRemove", 2.0f);
}
public void addAndRemove(float dt) {
CocosNode sp1 = getChild(kTagSprite1);
CocosNode sp2 = getChild(kTagSprite2);
removeChild(sp1, false);
removeChild(sp2, true);
addChild(sp1, 0, kTagSprite1);
addChild(sp2, 0, kTagSprite2);
}
이번번 예제는 할배노드에서 부모노드를 삭제할때 자식노드의 액션과 콜백은 어떻게 되느
냐를 묻는 건데요.결론만 먼저 말하자면 모두 삭제 됩니다.
자세한 내용은 cocos2d 내부 소스를 보시면 이해가 빠를겁니다.^^ 결론은 간단한데
그 내부를 설명하려면 몇단계를 거쳐야 하기때문에 일단 여기서는 제외합니다.
3-7 번 보류 StressTest