#ifndef PuzzleGame_GameLayer
#define PuzzleGame_GameLayer
#include "Common.h"
#include "GameObject.h"
#include <stdio.h>
#include <string.h>
class CGameLayer : public cocos2d::Layer {
public:
// [ 기본 ]
// ==============================================================================================================
static cocos2d::Scene* createScene() {
auto pScene = Scene::create();
auto pLayer = CGameLayer::create();
pScene->addChild(pLayer);
return pScene;
}
virtual bool init() {
if (!Layer::init()) { return false; }
// 배경 이미지 출력
cocos2d::Sprite* pBackgroundSprite = cocos2d::Sprite::create("background.png");
pBackgroundSprite->setPosition(cocos2d::CCPointZero);
pBackgroundSprite->setAnchorPoint(ccp((float)0, (float)0));
addChild(pBackgroundSprite);
// 터치 초기화
EventListenerTouchAllAtOnce* listener = EventListenerTouchAllAtOnce::create();
listener->onTouchesBegan = CC_CALLBACK_2(CGameLayer::onTouchesBegan, this);
listener->onTouchesMoved = CC_CALLBACK_2(CGameLayer::onTouchesMoved, this);
listener->onTouchesEnded = CC_CALLBACK_2(CGameLayer::onTouchesEnded, this);
_eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
m_winSize = Director::sharedDirector()->getWinSize();
startGame();
return true;
}
void startGame() {
for (int x = 0; x < COLUMN_COUNT+1; x++) {
for (int y = 0; y < ROW_COUNT+1; y++) {
m_pBoard[x][y] = NULL;
}
}
srand(time(NULL));
for (int x = 0; x < COLUMN_COUNT; x++) {
for (int y = 0; y < ROW_COUNT; y++) {
if (x == COLUMN_COUNT - 1 && y % 2 != 0) continue;
int type = rand() % TYPE_COUNT;
Sprite* pGameObjectBack = Sprite::create("blockBack.png");
CGameObject* pGameObject = CGameObject::Create(type);
m_pBoard[x][y] = pGameObject;
// debug --------------------------------------------------------------
// 각 블록의 좌표를 출력
std::string str, str2, str3;
str = std::to_string(x);
str2 = ",";
str3 = std::to_string(y);
str.append(str2);
str.append(str3);
auto label = LabelTTF::create(str, "Arial", 50);
Point pos; pos.set(Common::ComputeXY(x, y));
label->setPosition(pos);
// end of debug -------------------------------------------------------
pGameObjectBack->setAnchorPoint(ccp(0.5f, 0.5f));
pGameObjectBack->setPosition(Common::ComputeXY(x, y));
pGameObject->setAnchorPoint(ccp(0.5f, 0.5f));
pGameObject->setPosition(Common::ComputeXY(x, y));
pGameObject->SetGameLayer(this);
addChild(pGameObjectBack, 1);
addChild(pGameObject, 2);
addChild(label, 3);
}
}
// 변수 초기화
m_bTouchStarted = false;
}
CREATE_FUNC(CGameLayer);
// [ 터치 초기화 ]
void onTouchesBegan(const std::vector<cocos2d::Touch*>&pTouches, cocos2d::Event* pEvent) {
if (!m_bTouchStarted) {
Touch* pTouch = (Touch*)pTouches.back();
Point point = pTouch->getLocation();
m_gestureStartBoardX = Common::ComputeBoardX(point);
m_gestureStartBoardY = Common::ComputeBoardY(point);
m_bTouchStarted = true;
}
}
void onTouchesMoved(const std::vector<cocos2d::Touch*>&pTouches, cocos2d::Event* pEvent) {
if (m_bTouchStarted) {
Touch* pTouch = (Touch*)pTouches.back();
Point point = pTouch->getLocation();
}
}
void onTouchesEnded(const std::vector<cocos2d::Touch*>&pTouches, cocos2d::Event* pEvent) {
if (m_bTouchStarted) {
Touch* pTouch = (Touch*)pTouches.back();
Point point = pTouch->getLocation();
m_bTouchStarted = false;
int boardX = Common::ComputeBoardX(point);
int boardY = Common::ComputeBoardY(point);
if (m_gestureStartBoardX != boardX || m_gestureStartBoardY != boardY)
if (isAdjacent(m_gestureStartBoardX, m_gestureStartBoardY, boardX, boardY))
swapObjects(m_gestureStartBoardX, m_gestureStartBoardY, boardX, boardY);
}
}
protected:
CGameObject* m_pBoard[COLUMN_COUNT+1][ROW_COUNT+1]; // 기존과 달리 +1씩 더 해줬다. 매칭검사할때 범위를 벗어나서 이렇게 때웠다
Size m_winSize;
bool m_bTouchStarted; // 터치가 시작되었는지
int m_gestureStartBoardX;
int m_gestureStartBoardY; // 터치가 시작된 블록이 어느 블록인지
// ==============================================================================================================
// [ 제어 - 블록 매칭 ]
// ==============================================================================================================
public:
bool isAdjacent(int x1, int y1, int x2, int y2) {
if (y1 % 2 == 0) {
if ((x1 == x2) && (y1 - 2 == y2 || y1 - 1 == y2 || y1 + 1 == y2 || y1 + 2 == y2))
return true;
if ((x1 - 1 == x2) && (y1 - 1 == y2 || y1 + 1 == y2))
return true;
}
else {
if ((x1 == x2) && (y1 - 2 == y2 || y1 - 1 == y2 || y1 + 1 == y2 || y1 + 2 == y2))
return true;
if ((x1 + 1 == x2) && (y1 - 1 == y2 || y1 + 1 == y2))
return true;
}
return false;
} // 두 블록이 서로 인접한 블록인지
void swapObjects(int x1, int y1, int x2, int y2) {
CGameObject* pTemp = m_pBoard[x1][y1];
m_pBoard[x1][y1] = m_pBoard[x2][y2];
m_pBoard[x2][y2] = pTemp;
m_pBoard[x1][y1]->SetTargetBoardX(x1);
m_pBoard[x1][y1]->SetTargetBoardY(y1);
m_pBoard[x2][y2]->SetTargetBoardX(x2);
m_pBoard[x2][y2]->SetTargetBoardY(y2);
m_pBoard[x1][y1]->ProcessSliding();
m_pBoard[x2][y2]->ProcessSliding();
}
void SlidingCompleteEvent() {
if (searchMacthedStreak());
clearRemovealObject();
}
// 매칭된 블록이 있는지 검사하고 제거대상으로 설정
bool searchMacthedStreak() {
bool isAnyMatched = false;
int x = 0, y = 0;
// 1행에서 검사 (0,0 / 1,0, / 2,0 / 3,0 / 4,0)
while (true) {
if (x < 0 || x >= COLUMN_COUNT) break;
if (y < 0 || y >= ROW_COUNT) break;
if (!m_pBoard[x][y]) break;
if (streakWay1(x, y) | streakWay2(x, y) | streakWay3(x, y)) isAnyMatched = true;
if (streakWay3(x, y)) isAnyMatched = true;
x++;
}
// 2행에서 검사(0,1 / 1,1 / 2,1 / 3, 1)
x = 0; y = 1;
while (true) {
if (x < 0 || x >= COLUMN_COUNT) break;
if (y < 0 || y >= ROW_COUNT) break;
if (!m_pBoard[x][y]) break;
if (streakWay2(x, y)) isAnyMatched = true;
x++;
}
// 좌측 열에서 검사
x = 0; y = 2;
while (true) {
if (x < 0 || x >= COLUMN_COUNT) break;
if (y < 0 || y >= ROW_COUNT) break;
if (!m_pBoard[x][y]) break;
if (streakWay1(x, y)) isAnyMatched = true;
y += 2;
}
// 우측 열에서 검사
x = COLUMN_COUNT - 1; y = 2;
while (true) {
if (x < 0 || x >= COLUMN_COUNT) break;
if (y < 0 || y >= ROW_COUNT) break;
if (!m_pBoard[x][y]) break;
if (streakWay3(x, y)) isAnyMatched = true;
y += 2;
}
return isAnyMatched;
}
// 제거 대상 블록을 처리
void clearRemovealObject() {
for (int x = 0; x < COLUMN_COUNT; x++) {
for (int y = 0; y < ROW_COUNT; y++) {
if (x == COLUMN_COUNT - 1 && y % 2 != 0) continue;
if (m_pBoard[x][y]->isRemovalObject()) {
m_pBoard[x][y]->setVisible(false);
}
}
}
}
protected:
// 매칭 라인 - 좌대각↘ 1줄 검사
bool streakWay1(int x, int y) {
int i = 0;
int countMatch = 1;
bool isAnyMatched = false;
int j = 0;
while (true) {
j++;
if (x < 0 || x >= COLUMN_COUNT) break;
if (y < 0 || y >= ROW_COUNT) break;
if (!m_pBoard[x][y]) break;
int nextX = x;
int nextY = y + 1;
i = 1 - i;
if (i % 2 == 0) nextX = x + 1;
if (countMatch > 2) {
m_pBoard[x][y]->setRemovalObject();
m_pBoard[(i % 2 == 0) ? x : x - 1][y - 1]->setRemovalObject();
m_pBoard[(i % 2 == 0) ? x-1 : x - 1][y - 2]->setRemovalObject();
isAnyMatched = true;
}
if (checkType(m_pBoard[x][y]->GetType(), nextX, nextY))
countMatch++;
else countMatch = 1;
x = nextX;
y = nextY;
}
return isAnyMatched;
}
// 매칭 라인 - 수직↓ 1줄 검사
bool streakWay2(int x, int y) {
int i = 1;
int countMatch = 1;
bool isAnyMatched = false;
while (true) {
if (x < 0 || x >= COLUMN_COUNT) break;
if (y < 0 || y >= ROW_COUNT) break;
if (!m_pBoard[x][y]) break;
int nextX = x;
int nextY = y + 2;
if (countMatch > 2) {
m_pBoard[x][y]->setRemovalObject();
m_pBoard[x][y - 2]->setRemovalObject();
m_pBoard[x][y - 4]->setRemovalObject();
isAnyMatched = true;
}
if (checkType(m_pBoard[x][y]->GetType(), nextX, nextY))
countMatch++;
else countMatch = 1;
x = nextX;
y = nextY;
}
return isAnyMatched;
}
// 매칭 라인 - 우대각↙ 1줄 검사
bool streakWay3(int x, int y) {
int i = 1;
int countMatch = 1;
bool isAnyMatched = false;
while (true) {
if (x < 0 || x >= COLUMN_COUNT) break;
if (y < 0 || y >= ROW_COUNT) break;
if (!m_pBoard[x][y]) break;
int nextX = x;
int nextY = y + 1;
i = 1 - i;
if (i % 2 == 0) nextX = x - 1;
if (countMatch > 2) {
m_pBoard[x][y]->setRemovalObject();
m_pBoard[(i % 2 == 0) ? x : x + 1][y - 1]->setRemovalObject();
m_pBoard[(i % 2 == 0) ? x+1 : x + 1][y - 2]->setRemovalObject();
isAnyMatched = true;
}
if (checkType(m_pBoard[x][y]->GetType(), nextX, nextY))
countMatch++;
else countMatch = 1;
x = nextX;
y = nextY;
}
return isAnyMatched;
}
// 블록 타입 검사
bool checkType(int type, int x, int y) {
if (x < 0 || x >= COLUMN_COUNT) return false;
if (y < 0 || y >= ROW_COUNT) return false;
if (!m_pBoard[x][y]) return 0;
return (type == m_pBoard[x][y]->GetType());
}
// ==============================================================================================================
};
#endif