cocos2d-x 공부용2014. 9. 12. 14:55

원글 주소 : http://horns.tistory.com/9


-6- 인접 코인 인식


1. 처음 터치된 위치의 코인을 확인


HelloWorldScene.cpp

checkPushGameCoin에서 아래 내용을 삭제합니다.

int HelloWorld::checkPushGameCoin(Point &touchPos) {
    int index;
    GameCoin *tmpCoin;
 
    for (index = 0; index < _gameCoins->count(); index++) {
        tmpCoin = (GameCoin*) _gameCoins->objectAtIndex(index);
        if (tmpCoin->boundingBox().containsPoint(touchPos)) {
            if (tmpCoin->isVisible() == true) {
                tmpCoin->setVisible(false);
            } else {
                tmpCoin->setVisible(true);
            }
            return index;
        }
    }
    return -1;
}

HelloWorldScene.h

다음과 같이 변수를 추가합니다.

class HelloWorld : public cocos2d::Layer
{
private:
	Size _screenSize;

	Action* _enemyMove;
	Action* _treeMove;

	Array* _gameCoins;

	int _lastCoin; //마지막 코인 위치를 저장하기 위한 변수 추가


다시 cpp로 돌아와 변수 초기값 및 터치 함수를 수정합니다.


HelloWorldScene.cpp

void HelloWorld::initGameCoin() {
	int coinX = 0;
	int coinY = 0;
	int diffX = _screenSize.width * 0.135f; //코인 x 간격
	int diffY = _screenSize.height * 0.097f; //코인 y 간격
	int initCoinX = _screenSize.width * 0.095f; //초기 코인 x 위치
	int initCoinY = _screenSize.height * 0.613f; //초기 코인 y 위치

	GameCoin* gameCoin;
	_lastCoin = -1;
...
}

bool HelloWorld::onTouchBegan(Touch* touch, Event* event) {
	//getCurrentTarget은 Node를 반환한다. 이것이 터치한 오브젝트가 된다.
	auto target = event->getCurrentTarget();
	Point location = target->convertToNodeSpace(touch->getLocation());

	_lastCoin = checkPushGameCoin(location);
	if(_lastCoin>=0){
		addSelectCoins(_lastCoin);
	}
	return true;
}


2. 터치 상태에서 움직이는 동안 선택된 코인이 1에서 선택된 것과 같은지 확인


HelloWorldScene.h

인접 코인을 검사하기 위해 enum변수 위치 변경 밑 배열 추가 합니다.

private:
	enum{
			BOARD_X = 7, //코인 x 개수
			BOARD_Y = 6, //코인 y 개수
			TOTAL_COIN_TYPE = 4, //코인 종류의 수
			TOTAL_ADJ_COIN = 6, //검사할 최대 주변 코인의 개수
		};
	Size _screenSize;

	Action* _enemyMove;
	Action* _treeMove;

	Array* _gameCoins;

	int _lastCoin; //마지막 코인 위치를 저장하기 위한 변수 추가
	static int _adjCoin[BOARD_X * BOARD_Y][TOTAL_ADJ_COIN];

public:
    // there's no 'id' in cpp, so we recommend returning the class instance pointer
    static cocos2d::Scene* createScene();
...


HelloWorldScene.cpp

인접 코인을 검사하기 위한 배열을 다음 값으로 초기화 합니다.

숫자에 대해서는 따로 설명하지 않습니다.

#include "HelloWorldScene.h"

USING_NS_CC;

int HelloWorld::_adjCoin[BOARD_X * BOARD_Y][TOTAL_ADJ_COIN] = {
		    {-1, -1,  1,  7,  6, -1},   // 0, line 1
		    {-1, -1,  2,  8,  7,  0},
		    {-1, -1,  3,  9,  8,  1},
		    {-1, -1,  4, 10,  9,  2},
		    {-1, -1,  5, 11, 10,  3},
		    {-1, -1, -1, -1, 11,  4},
		    {-1,  0,  7, 12, -1, -1},   // 6, line 2
		    { 0,  1,  8, 13, 12,  6},
		    { 1,  2,  9, 14, 13,  7},
		    { 2,  3, 10, 15, 14,  8},
		    { 3,  4, 11, 16, 15,  9},
		    { 4,  5, -1, 17, 16, 10},
		    { 6,  7, 13, 19, 18, -1},   // 12, line 3
		    { 7,  8, 14, 20, 19, 12},
		    { 8,  9, 15, 21, 20, 13},
		    { 9, 10, 16, 22, 21, 14},
		    {10, 11, 17, 23, 22, 15},
		    {11, -1, -1, -1, 23, 16},
		    {-1, 12, 19, 24, -1, -1},   // 18, line 4
		    {12, 13, 20, 25, 24, 18},
		    {13, 14, 21, 26, 25, 19},
		    {14, 15, 22, 27, 26, 20},
		    {15, 16, 23, 28, 27, 21},
		    {16, 17, -1, 29, 28, 22},
		    {18, 19, 25, 31, 30, -1},   // 24, line 5
		    {19, 20, 26, 32, 31, 24},
		    {20, 21, 27, 33, 32, 25},
		    {21, 22, 28, 34, 33, 26},
		    {22, 23, 29, 35, 34, 27},
		    {23, -1, -1, -1, 35, 28},
		    {-1, 24, 31, 36, -1, -1},   // 30, line 6
		    {24, 25, 32, 37, 36, 30},
		    {25, 26, 33, 38, 37, 31},
		    {26, 27, 34, 39, 38, 32},
		    {27, 28, 35, 40, 39, 33},
		    {28, 29, -1, 41, 40, 34},
		    {30, 31, 37, -1, -1, -1},   // 36, line 7
		    {31, 32, 38, -1, -1, 36},
		    {32, 33, 39, -1, -1, 37},
		    {33, 34, 40, -1, -1, 38},
		    {34, 35, 41, -1, -1, 39},
		    {35, -1, -1, -1, -1, 40},
};


3. 같은 타입의 코인인 경우 하얗게 이미지를 덮어씌워 표시


이제 코인을 터치하여 쭉 움직였을 때, 같은 타입인 경우엔 코인 위에 하햫고 반투명한 이미지를 덮어씌워 표시하도록 합니다.


HelloWorldScene.h

헤더파일에 아래와 같이 두개의 변수를 추가합니다.

class HelloWorld : public cocos2d::Layer
{
private:
	enum{
			BOARD_X = 7, //코인 x 개수
			BOARD_Y = 6, //코인 y 개수
			TOTAL_COIN_TYPE = 4, //코인 종류의 수
			TOTAL_ADJ_COIN = 6, //검사할 최대 주변 코인의 개수
		};
	Size _screenSize;

	Action* _enemyMove;
	Action* _treeMove;

	Array* _gameCoins;
	Array* _selectMask;
	Array* _selectCoins;

	int _lastCoin; //마지막 코인 위치를 저장하기 위한 변수 추가
	static int _adjCoin[BOARD_X * BOARD_Y][TOTAL_ADJ_COIN];

HelloWorldScene.cpp

HelloWorld::~HelloWorld() {
	CC_SAFE_RELEASE(_enemyMove);
	CC_SAFE_RELEASE(_treeMove);
	CC_SAFE_RELEASE(_gameCoins);
	CC_SAFE_RELEASE(_selectCoins);
	CC_SAFE_RELEASE(_selectMask);
}

void HelloWorld::initGameCoin() {
..
	//배열 설정
	_gameCoins = Array::createWithCapacity(BOARD_X * BOARD_Y);
	_gameCoins->retain();

	_selectCoins = Array::createWithCapacity(BOARD_X * BOARD_Y);
	_selectCoins->retain();

	_selectMask = Array::createWithCapacity(BOARD_X * BOARD_Y);
	_selectMask->retain();

..
	//selectMask 설정
	Sprite* selectMask;

	for (int xIndex = 0; xIndex < BOARD_X; xIndex++) {
		coinX = initCoinX + (xIndex * diffX);
		coinY = initCoinY;
		if (xIndex % 2 == 0) {
			coinY -= diffY / 2;
		}

		for (int yIndex = 0; yIndex < BOARD_Y; yIndex++) {
			selectMask = Sprite::create("selectTile.png");
			selectMask->setVisible(false);
			selectMask->setScale(_screenSize.width * 0.0011f);
			selectMask->setPosition(coinX, coinY);
			this->addChild(selectMask);
			_selectMask->addObject(selectMask);

			coinY -= diffY;
		}
	}
}

setScale 부분은 기기 해당도마다 달라질 수 있으니 적절하게 변경해 사용하세요.

제가 사용하는 기기는 1024*600의 태블릿이고, 좀 더 작은 스마트폰에 빌드해보니 크기가 맞지 않더군요.

하지만 일단 이대로 진행하고, 차후에 해상도 관련해서 수정해야겠습니다.


HelloWorldScene.h

다음과 같은 순서대로 동작하기 위해 헤더파일에 함수를 추가합니다.

    int checkPushGameCoin(Point &touchPos);
    bool inLastCoin(Point &touchPos); //1. 이동한 위치의 코인이 처음 코인과 다른 경우
    int checkAdjacentCoin(Point &touchPos); //2. 이동한 위치의 코인이 처음 코인의 인접 코인인지 확인
    bool compareCoinType(int index1, int index2); //3. 처음 코인과 인접 코인의 종류가 같으면
    int addSelectCoins(int index); //4. 선택된 코인, 코인 갯수등의 정보를 업데이트한다.
    
};

HelloWorldScene.cpp

이제 각 함수를 작성합니다.


1) inLastCoin()

bool HelloWorld::inLastCoin(Point &touchPos) {
	if (_lastCoin == -1) {
		return false;
	}

	GameCoin* lastCoin = (GameCoin*) _gameCoins->objectAtIndex(_lastCoin);
	if (lastCoin->boundingBox().containsPoint(touchPos)) {
		return true;
	}
	return false;
}

2) checkAdjacentCoin()

int HelloWorld::checkAdjacentCoin(Point &touchPos) {
	int index;
	GameCoin* tmpCoin;

	if (_lastCoin < 0) {
		return -1;
	}

	for (index = 0; index < 6; index++) {
		if (_adjCoin[_lastCoin][index] == -1) {
			continue;
		}
		tmpCoin = (GameCoin*) _gameCoins->objectAtIndex(_adjCoin[_lastCoin][index]);
		if (tmpCoin->boundingBox().containsPoint(touchPos)) {
			return _adjCoin[_lastCoin][index];
		}
	}

	return -1;
}

3) compateCoinTyrp()

bool HelloWorld::compareCoinType(int index1, int index2) {
	if (index1 < 0 || index2 < 0) {
		return false;
	}

	GameCoin* tmpCoin1 = (GameCoin*) _gameCoins->objectAtIndex(index1);
	GameCoin* tmpCoin2 = (GameCoin*) _gameCoins->objectAtIndex(index2);

	if (tmpCoin1->getType() == tmpCoin2->getType()) {
		return true;
	}
	return false;
}

4) addSelectCoins()

int HelloWorld::addSelectCoins(int index) {
	if (index < 0) {
		return -1;
	}

	GameCoin* tmpCoin = (GameCoin*) _gameCoins->objectAtIndex(index);
	Sprite* selectMask = (Sprite*) _selectMask->objectAtIndex(index);

	if (tmpCoin->getState() != GameCoin::SELECT) {
		tmpCoin->setState(GameCoin::SELECT);
		_selectCoins->addObject(tmpCoin);

		selectMask->setVisible(true);
	}

	return 0;
}

각 함수의 동작에 대한 설명은 원글을 봐주세요.

이제 실제로 동작할 수 있도록 onTouchMoved에 내용을 추가하도록 합니다.


HelloWorldScene.cpp

void HelloWorld::onTouchMoved(Touch* touch, Event* event) {
	auto target = event->getCurrentTarget();
	Point location = target->convertToNodeSpace(touch->getLocation());
	int newCoin = -1;

	if (!inLastCoin(location)) {
		newCoin = checkAdjacentCoin(location);

		if (compareCoinType(_lastCoin, newCoin)) {
			_lastCoin = newCoin;
			addSelectCoins(_lastCoin);
		}
	}
}


그리고 반드시 잊지 말고 리스너에 콜백을 추가해줍니다. 이걸 하지 않으면 터치가 전혀 동작하지 않습니다.

bool HelloWorld::init() {
	//////////////////////////////
	// 1. super init first
	if (!Layer::init()) {
		return false;
	}

	_screenSize = Director::sharedDirector()->getWinSize();

	this->setTouchEnabled(true);

	//디스패처. 리스너와 오브젝트를 연결해주는 역할
	EventDispatcher* dispatcher = Director::getInstance()->getEventDispatcher();
	//터치 위치를 알려주는 리스너. 단일 터치.
	//바로 만들어쓰는 식별자는 auto를 사용한다.
	auto positionListener = EventListenerTouchOneByOne::create();
	//zOrder에 따라 밑에 깔린애도 동작할지 아닐지를 결정한다.
	positionListener->setSwallowTouches(true);
	//콜백 함수 대입
	positionListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
	positionListener->onTouchMoved = CC_CALLBACK_2(HelloWorld::onTouchMoved, this);
	//디스패처를 이용해 객체와 리스너를 이어준다. 화면 전체를 터치할 수 있게 만들어야 하므로 객체는 this
	dispatcher->addEventListenerWithSceneGraphPriority(positionListener, this);

	createGameAction();
	createGameScene();

	return true;
}

여기까지 하고 실행하면 다음과 같이 잘 실행되는 것을 확인할 수 있습니다.



꽤 많은 내용이 한꺼번에 진행되었기 때문에 오타로 인해 문제가 생길 수 있으니 잘 확인해 주시고요

무엇보다 이전버전과는 터치의 동작이 달라졌기 때문에 헷갈리실 수 있어요.

캡쳐를 보면 이미지 크기가 살짝 맞지 않는 부분이 있지만 일단은 넘어가도록 하겠습니다.


Posted by 아이시네프
cocos2d-x 공부용2014. 9. 11. 18:29

원글 출처 : http://horns.tistory.com/8


이전 터치관련 포스팅에서 언급했던 문제를 해결하였으므로 계속 작성합니다.

터치 문제가 아니라 제가 소스 한 줄을 빼먹어서 발생한 문제였습니다ㅠ


------------------------------------------------------------------------------------------------


-5- Touch


1. 터치 함수 추가


HelloWorldScene.h

    void initGameCoin(void);
    GameCoin* createGameCoin(const Point &pos, int type, int state);

    virtual bool onTouchBegan(Touch* touch, Event* event);
    virtual void onTouchMoved(Touch* touch, Event* event);
    virtual void onTouchEnded(Touch* touch, Event* event);

    int checkPushGameCoin(Point &touchPos);
};

이상태로 빌드하지 마시고 반드시 HelloWoridScene.cpp에 다음과 같이 작성한 후 빌드해주세요.

오버라이드 함수라 헤더파일에만 추가하고 빌드하면 반드시 에러가 납니다.


HelloWorldScene.cpp

우선 init()함수 안에 아래 내용을 추가합니다.

bool HelloWorld::init() { ////////////////////////////// // 1. super init first if (!Layer::init()) { return false; } _screenSize = Director::sharedDirector()->getWinSize(); this->setTouchEnabled(true); //디스패처. 리스너와 오브젝트를 연결해주는 역할 EventDispatcher* dispatcher = Director::getInstance()->getEventDispatcher(); //터치 위치를 알려주는 리스너. 단일 터치. //바로 만들어쓰는 식별자는 auto를 사용한다. auto positionListener = EventListenerTouchOneByOne::create(); //zOrder에 따라 밑에 깔린애도 동작할지 아닐지를 결정한다. true면 상위 리스너만 동작한다. positionListener->setSwallowTouches(true); //콜백 함수 대입 positionListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this); //디스패처를 이용해 객체와 리스너를 이어준다. 화면 전체를 터치할 수 있게 만들어야 하므로 객체는 this dispatcher->addEventListenerWithSceneGraphPriority(positionListener, this); createGameAction(); createGameScene(); return true; }

그리고 하단부에 아래와 같이 Touch관련 함수를 작성합니다.

bool HelloWorld::onTouchBegan(Touch* touch, Event* event) {
	//getCurrentTarget은 Node를 반환한다. 이것이 터치한 오브젝트가 된다.
	auto target = event->getCurrentTarget();
	Point location = target->convertToNodeSpace(touch->getLocation());
}

void HelloWorld::onTouchMoved(Touch* touch, Event* event) {
	auto target = event->getCurrentTarget();
	Point location = target->convertToNodeSpace(touch->getLocation());
}

void HelloWorld::onTouchEnded(Touch* touch, Event* event) {
	auto target = event->getCurrentTarget();
	Point location = target->convertToNodeSpace(touch->getLocation());
}

여기까지 빌드가 무사히 되셨다면 좋겠습니다.


2. 코인 동작


이제 터치해서 코인이 반응하도록 합니다.


HelloWorldScene.cpp

onTouchBegan 안에 다음과 같은 내용을 추가합니다.

bool HelloWorld::onTouchBegan(Touch* touch, Event* event) {
	//getCurrentTarget은 Node를 반환한다. 이것이 터치한 오브젝트가 된다.
	auto target = event->getCurrentTarget();
	Point location = target->convertToNodeSpace(touch->getLocation());

	checkPushGameCoin(location);
	return true;
}

그런 다음, 아래와 같이 함수를 추가합니다.

int HelloWorld::checkPushGameCoin(Point &touchPos) {
	int index;
	GameCoin *tmpCoin;

	for (index = 0; index < _gameCoins->count(); index++) {
		tmpCoin = (GameCoin*) _gameCoins->objectAtIndex(index);
		if (tmpCoin->boundingBox().containsPoint(touchPos)) {
			if (tmpCoin->isVisible() == true) {
				tmpCoin->setVisible(false);
			} else {
				tmpCoin->setVisible(true);
			}
			return index;
		}
	}
	return -1;
}

이제 빌드 시도해서 성공하면, 기기로 실행해봅니다.



터치하는대로 코인이 사라지면 성공입니다.


------------------------------------------------------------------------------------------------

자연스럽게 쓰다 보면 말투가 왔다갔다 하네요.

오늘은 일이 있어서 이것밖에 못했습니다.


Posted by 아이시네프
cocos2d-x 공부용2014. 9. 11. 11:26

추석 잘들 지내셨나요?

얼마나 보고 계실지 모르겠지만 그래도 포스팅 해봅니다.



캡쳐를 해두지 않았지만 3.2버전을 깔면서 계속 문제가 생겼습니다.

포스팅을 시작하면서 한 번 언급은 했었지만, 컴퓨터를 껐다 켜면 'Android Library Update'에 문제가 생겼다면서 프로젝트를 로딩을 못하는 상황이 발생합니다.

오류 내용은 Null Point Exception이라고 뜨고요. 캡쳐를 떠놓질 않아서 정확한 오류 내용을 쓰기가 어렵네요.


제 개발 환경에서만 발생하는지도 모르겠습니다.

윈도우8 노트북 (아마도 포터블 버전인것같습니다. 파일질라도 포터블 버전만 실행 가능했고.)

64bit

이클립스는 키플러고 ndk도 구버전인 r8e였던거같습니다.

문제 과정은 다음과 같습니다.


1. cocos2d-x 3.2로 프로젝트를 생성한다.

2. 이클립스에 임포트 하고 실행, 수정하면 전부 잘 동작한다. (이 시점에서는 단순히 이클립스를 재시작 하는 것으론 잘 발생하지 않는다.)

3. PC를 재부팅한다. 

4. 이클립스를 실행하면, 'Android Library Update'에서 에러가 발생했다고 뜬다.

이때 detail을 눌러보면 다음과 같이 표시된다.


An internal error occurred during: "Android Library Update"

. java.lang.NullPointerException


5. 이 오류를 해결하기 위해 이것저것 하다보면 설상 가상으로 위와 같은 포맷에 아래 오류까지 뜬다.


An internal error occurred during: "C/C++ Indexer"

. java.lang.NullPointerException


6. C/C++ 에디터가 문제가 있다면서 cpp 파일이 실행되지도 않고, 프로젝트 내용도 보이지 않게 된다.

7. 다시 1번부터 새 프로젝트를 만들어서 실행하면 PC를 끄기 전까진 또 실행이 된다.


위와 같은 과정을 서너번 거쳐서 3.2로 프로젝트 만드는 걸 포기할까 하는 생각도 했습니다..만, 며칠에 걸친 검색 끝에 다음과 같은 내용을 찾았습니다.


http://www.cocoachina.com/bbs/simple/?t219768.html


중국어로 되어있습니다만, 구글 번역을 통해 보니 이러한 문제가 3.2버전에서만 발생하는 걸로 보입니다.


http://stackoverflow.com/questions/24882026/eclipse-project-disappearance-and-an-internal-error-occurred-during-launching


구글 번역의 도움을 얻어 보면, .cproject 내에 <cconfiguration> 항목이 중복되어있어서 발생하는 문제라고 합니다.

위 사이트에서 힌트를 얻어서 다음과 같이 해결합니다.


*우선 이클립스를 전부 종료해주세요.

1. <내 프로젝트>/proj.android/.cproject 를 에디터로 실행합니다.

2. 라인넘버 80~85 사이에 </cconfiguration><cconfiguration> 부분을 찾습니다.




제 파일은 위와 같이 되어있습니다.


3. 83번 라인의 cconfiguration, 즉 첫 번쨰 cconfiguration을 제외한 두 번째부터의 cconfiguration을 전부 지워주세요.




제 파일 기준으로는 여기까지 입니다.


4. 다시 프로젝트를 실행하면 오류 없이 정상적으로 실행됩니다. PC를 재부팅해도 오류가 없습니다.


다만, 이 방법이 정말 안전한 방법인지는 모르겠습니다. 우선 만약을 대비해 기존 .cproject 파일을 백업해두긴 했습니다.

저 값들이 정말 지워버려도 아무 상관없는값인지? 다시 같은 오류가 발생하지 않는지?는 계속 작업해 봐야 알 것 같습니다.

다만 저처럼 안되는 영어로 열심히 검색했는데도 계속 같은 문제가 발생하고, 또 매번 프로젝트를 새로 만들어 쓸 수도 없어서 곤란하신 분들께 당장의 문제 해결은 되리라 생각합니다.


이 외에도 fmod에 관한 문제도 있었지만 이게 영향을 미치는지 아닌지는 모르겠으므로, 혹여나 관련 문제에 대해 묻는 분이 계시면 그때 포스팅 하겠습니다.


*

사담. 하이퍼링크 자동으로 걸렸음 좋겠다..

Posted by 아이시네프
cocos2d-x 공부용2014. 9. 5. 16:42

터치 관련으로 문제가 많아서ㅡㅡ; 그거 좀 해결하느라 하루종일 아무것도 못적었네요.

우선 터치 관련만 정리해둡니다.


참조

http://mightyfine.egloos.com/viewer/294494

http://plming.tistory.com/83

http://blog.naver.com/cdyho/220068792495


그리고 중간에 이상한 문제가 터져서 그걸 고쳐보겠다고 GCC바꾸고 별 난리를 치다가..포기하고 프로젝트를 새로 만들었습니다. 그리고 어느 고마우신 분이 3.2버전 수정 소스를 올리셨다고 해서 덮어씌웠고, 지금은 문제 없이 진행중입니다.

관련 주소 : http://cafe.naver.com/cocos2dxusers/20933 (로긴 및 가입 필요)


터치에 반응하는건 성공 했는데, 다른 중대한 문제가 생겼네요. 머리 터지겠습니다 아주.

아래는 TouchBegan만 적용하는 소스입니다.


1. 싱글 터치

HelloWorldScene.h

using namespace cocos2d;

class HelloWorld : public cocos2d::Layer
{ ..
virtual bool onTouchBegan(Touch* touch, Event* event);
..
};

cpp에 해당하는 함수를 빈상태라도 구현하지 않으면 위에만 써놓고 빌드했을때 에러납니다.


HelloWorldScene.cpp

bool HelloWorld::init() {
	//////////////////////////////
	// 1. super init first
	if (!Layer::init()) {
		return false;
	}

	_screenSize = Director::sharedDirector()->getWinSize();

	this->setTouchEnabled(true);

	//디스패처. 리스너와 오브젝트를 연결해주는 역할
	EventDispatcher* dispatcher = Director::getInstance()->getEventDispatcher();
	//터치 위치를 알려주는 리스너. 단일 터치.
	//바로 만들어쓰는 식별자는 auto를 사용한다.
	auto positionListener = EventListenerTouchOneByOne::create();
	//zOrder에 따라 밑에 깔린애도 동작할지 아닐지를 결정한다.
	positionListener->setSwallowTouches(true);
	//콜백 함수 대입
	positionListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
	//디스패처를 이용해 객체와 리스너를 이어준다. 화면 전체를 터치할 수 있게 만들어야 하므로 객체는 this
	dispatcher->addEventListenerWithSceneGraphPriority(positionListener, this);

	createGameAction();
	createGameScene();

	return true;
}

..

bool HelloWorld::onTouchBegan(Touch* touch, Event* event) {
	//getCurrentTarget은 Node를 반환한다. 이것이 터치한 오브젝트가 된다.
	auto target = event->getCurrentTarget();
	Point location = target->convertToNodeSpace(touch->getLocation());

	return true;
}

2. 멀티 터치


HelloWorldScene.h

using namespace cocos2d;
using namespace std;

class HelloWorld : public cocos2d::Layer
{
..

    virtual void onTouchesBegan(const std::vector<Touch*> &touches, Event* event);

..
};

HelloWorldScene.cpp

bool HelloWorld::init() {
	//////////////////////////////
	// 1. super init first
	if (!Layer::init()) {
		return false;
	}

	_screenSize = Director::sharedDirector()->getWinSize();

	this->setTouchEnabled(true);

	//디스패처. 리스너와 오브젝트를 연결해주는 역할
	EventDispatcher* dispatcher = Director::getInstance()->getEventDispatcher();
	//터치 위치를 알려주는 리스너. 단일 터치.
	//바로 만들어쓰는 식별자는 auto를 사용한다.
	auto positionListener = EventListenerTouchAllAtOnce::create();
	//콜백 함수 대입
	positionListener->onTouchesBegan = CC_CALLBACK_2(HelloWorld::onTouchesBegan, this);
	//디스패처를 이용해 객체와 리스너를 이어준다. 화면 전체를 터치할 수 있게 만들어야 하므로 객체는 this
	dispatcher->addEventListenerWithSceneGraphPriority(positionListener, this);

	return true;
}

void HelloWorld::onTouchesBegan(const std::vector<Touch*> &touches, Event* event) {
	for (auto iter = touches.begin(); iter != touches.end(); iter++){
	      Point location = (*iter)->getLocation();

	    }
}

멀티 터치에서는 onTouchesBegan이 void로 바뀝니다. 이거 중요합니다. 이걸 몰라서 오류랑 많이 놀았습니다..

여튼 싱글터치도 멀티 터치도 잘 됩니다. 


여튼 추석 잘 보내시구요, 추석때는 다른 할일이 있어서 추석 끝나고 다시 이어서 할 것 같습니다.

Posted by 아이시네프
cocos2d-x 공부용2014. 9. 4. 15:18

원글 출처: http://horns.tistory.com/7


시작하기 전에..


HelloWorldScene.cpp

// on "init" you need to initialize your instance
bool HelloWorld::init() {
	//////////////////////////////
	// 1. super init first
	if (!Layer::init()) {
		return false;
	}

	_screenSize = Director::sharedDirector()->getWinSize();

	createGameAction();
	createGameScene();

	return true;
}

별로 쓸데없는거지만 _screenSIze를 init으로 옮겼습니다.

2.0.4버전에서는 함수마다 일일히 저걸 넣어주었던거같은데 지금 해보니 한번만 선언해줘도 다 되네요.
예전에 제가 몰랐던건가? 여튼 위치 이동했습니다.
특별한 이유는 없고요 그냥...저 보기 좋으라구요.


-4- Gaim Coin


1. Gaim Coin Class

Classes 밑에 GameCoin.h와 GameCoin.cpp를 생성한다.

이클립스에서 Classes 폴더를 우클릭하고 New에서 Header File, Source File로 추가한다.


GameCoin.h

#ifndef GAIMCOIN_H_
#define GAIMCOIN_H_

#include "cocos2d.h"

using namespace cocos2d;

class GameCoin : public Sprite
{
private:

public:
	enum gameState{
		LIVE,
		DEAD,
		SELECT,
	};

	CC_SYNTHESIZE(int, _type, Type);
	CC_SYNTHESIZE(int, _state, State);

	static GameCoin* spriteWithFile(const char* pszFileName);

	GameCoin();
	~GameCoin();
};

#endif /* GAIMCOIN_H_ */


CC_SYNTHESIZE는 다음과 같이 정의되어 있다.

#define CC_SYNTHESIZE(varType, varName, funName)\
protected: varType varName;\
public: virtual varType get##funName(void) const { return varName; }\
public: virtual void set##funName(varType var){ varName = var; }

varType varName에 대한걸 funName으로 된 getter/setter를 만들어주는 모양.

풀어보자면,

CC_SYNTHESIZE(int, _type, Type);
 
protected int _type;
public int getType() { return _type; }
public void setType(int var) { _type = var; }

이런건가봄.

*참고 : http://digitanomad.blogspot.kr/2012/12/ccproperty-ccsynthesize.html



GameCoin.cpp

#include "GameCoin.h"

GameCoin::~GameCoin()
{
}

GameCoin::GameCoin()
: _type(0),
  _state(GameCoin::LIVE)
{
}

GameCoin* GameCoin::spriteWithFile(const char* pszFileName)
{
	GameCoin* sprite = new GameCoin();
	if(sprite && sprite->initWithFile(pszFileName)){
		sprite->autorelease();
		return sprite;
	}
	CC_SAFE_DELETE(sprite);
	return NULL;
}

Sprite를 상속받아서 initWithFile를 이용한 함수를 하나 정의한다.

파일명을 통해 sirite를 만든다.


2. GameCoinArray


HelloWorldScene.h

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"
#include "GameCoin.h"

using namespace cocos2d;

class HelloWorld : public cocos2d::Layer
{
private:
	Size _screenSize;

	Action* _enemyMove;
	Action* _treeMove;

	Array* _gameCoins;

public:
	enum{
		BOARD_X = 7, //코인 x 개수
		BOARD_Y = 6, //코인 y 개수
		TOTAL_COIN_TYPE = 4, //코인 종류의 수
	};
    // there's no 'id' in cpp, so we recommend returning the class instance pointer
    static cocos2d::Scene* createScene();

    // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone
    virtual bool init();  
    
    // implement the "static create()" method manually
    CREATE_FUNC(HelloWorld);

    ~HelloWorld(void);//클래스 소멸자 추가

    void createGameScene(void);
    void createGameAction(void);
    void initGameCoin(void);
    GameCoin* createGameCoin(const Point &pos, int type, int state);
};

#endif // __HELLOWORLD_SCENE_H__


이제부터 코인을 배치한다.

이미지는 원출처 horns님의 블로그에 있는 이미지를 그대로 사용하므로 따로 업로드 하지 않음.


HelloWorldScene.cpp

HelloWorld::~HelloWorld() {
	CC_SAFE_RELEASE(_enemyMove);
	CC_SAFE_RELEASE(_treeMove);
	CC_SAFE_RELEASE(_gameCoins);
}

소멸자 추가.

void HelloWorld::initGameCoin() {
	int coinX = 0;
	int coinY = 0;
	int diffX = _screenSize.width * 0.135f; //코인 x 간격
	int diffY = _screenSize.height * 0.097f; //코인 y 간격
	int initCoinX = _screenSize.width * 0.095f; //초기 코인 x 위치
	int initCoinY = _screenSize.height * 0.613f; //초기 코인 y 위치

	GameCoin* gameCoin;

	//배열 설정
	_gameCoins = Array::createWithCapacity(BOARD_X * BOARD_Y);
	_gameCoins->retain();

	//gameCoin 초기화
	for (int xIndex = 0; xIndex < BOARD_X; xIndex++) {
		coinX = initCoinX + (xIndex * diffX);
		coinY = initCoinY;
		if (xIndex % 2 == 0) {
			coinY -= diffY / 2;
		}
		for (int yIndex = 0; yIndex < BOARD_Y; yIndex++) {
			gameCoin = createGameCoin(ccp(coinX, coinY), rand() % TOTAL_COIN_TYPE + 1, GameCoin::LIVE);
			_gameCoins->addObject(gameCoin);
			coinY -= diffY;
		}
	}
}

createGameCoin을 호출해서 x,y 개수 및 간격에 따라 코인의 위치, 타입을 부여하고 코인의 상태를 LIVE로 지정한뒤 추가한다.

각 값들은 현재 내가 사용하고 있는 태블릿 사이즈에 맞춘것이며 다른 비율의 화면에선 위치가 안맞을 수 있음.


GameCoin* HelloWorld::createGameCoin(const Point &pos, int type, int state){
	GameCoin* gameCoin;
	String* name;

	name = String::createWithFormat("coin_0%i.png", type);
	gameCoin = GameCoin::spriteWithFile(name->getCString());
	gameCoin->setVisible(true);
	gameCoin->setScale(_screenSize.width*0.0012f);
	gameCoin->setPosition(pos);
	gameCoin->setState(state);
	gameCoin->setType(type);

	this->addChild(gameCoin);

	return gameCoin;
}

initGameCoin()에서 받아온 rand()값을 기준으로 랜덤으로 게임 코인을 생성한다.

gameCoin->setScale(_screenSize.width*0.0012f);

요부분은 게임 코인 크기를 조절한것으로 자기 화면 비율에 맞춰 변경하면 될듯.


빌드하고 오타가 없는지 확인하고, 수정 다 한뒤 실행해본다.


실행화면:


앱을 종료했다 재시작하면 코인이 랜덤으로 생기는 것을 확인할 수 있다.


-----------------------------------------------------------------------------------------------------------------

코드 뷰어를 바꿨는데 세세한 설정이 가능한건 좋긴 한데

매번 HTML 모드를 왔다갔다 하는 건 불편한거같기도 하네요...

추석이 코앞이라 그런지 집중도 잘 안되고 술렁술렁한듯.


Posted by 아이시네프