안드로이드/cocos2d-x2016. 1. 17. 03:34

지난 게시물에 이어서

터치를 사용해 오브젝트를 제어할 것이다.

먼저 퍼즐 블록이 터치를 통해 제대로 선택되는지 확인해야 한다.

 

블록 선택하기

CGameLayer.cpp

1
2
3
4
5
6
7
8
9
10
11
12
 
void CGameLayer::onTouchesBegan(const std::vector<cocos2d::Touch*>&pTouches, cocos2d::Event* pEvent) {
    Touch* pTouch = (Touch*)pTouches.back();
 
    Point point = pTouch->getLocation();
 
    int boardX = Common::ComputeBoardX(point);
    int boardY = Common::ComputeBoardY(point);
 
    CCSprite* pCGameObject = m_pBoard[boardX][boardY];
    pCGameObject->setVisible(!pCGameObject->isVisible());
}
cs

 빨간 색으로 표시한 부분이 추가된 부분이다.

7,8행 - Common에 추가할 ComputeBoardX, Y함수를 통해

          터치한 좌표에 위치한 블록이 어느 블록인지 2차원 배열 좌표값을 얻어온다.

         ex) 500,500 터치 -> m_pBoard[2][3] ( 이 예시는 실제와 다름 )

10,11행 - 선택된 블록을 켜고 끈다 (보였다 안보였다 한다)

 

Common.cpp

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
// 화면좌표 to 내부좌표
int Common::ComputeBoardX(Point point) {
    for (int x = 0; x < COLUMN_COUNT; x++) {
        for (int y = 0; y < ROW_COUNT; y++) {
            Point hexagonPoint;
            hexagonPoint.set(ComputeXY(x, y));
            if (isInHexagon(hexagonPoint, point))
                return x;
        }
    }
    return 0;
}
int Common::ComputeBoardY(Point point) {
    for (int x = 0; x < COLUMN_COUNT; x++) {
        for (int y = 0; y < ROW_COUNT; y++) {
            Point hexagonPoint;
            hexagonPoint.set(ComputeXY((float)x, (float)y));
            if (isInHexagon(hexagonPoint, point))
                return y;
        }
    }
    return 0;
}
 
// 임의의 점이 두 점을 지나는 직선보다 아래에 위치하는지 검사
bool Common::isUnderLine(Point lines1, Point lines2, Point point) {
    float m = (lines2.y - lines1.y) / (lines2.x - lines1.x);    // 기울기
    //float n = lines1.y - m*lines1.x;                            // y절편
    float n = (lines2.x*lines1.y - lines1.x*lines2.y) / (lines2.x - lines1.x);
 
    return point.y <= (m*point.x + n);
}
 
// 임의의 점이 육각형 블록 내부에 위치하는지 검사
bool Common::isInHexagon(Point point, Point anyPoint) {
    Point p1, p2, p3, p4, p5, p6;
    p1.setPoint(point.x - (float)(OBJECT_WIDTH / 4), point.y + (float)(OBJECT_HEIGHT) / 2);
    p2.setPoint(point.x + (float)(OBJECT_WIDTH / 4), point.y + (float)(OBJECT_HEIGHT) / 2);
    p3.setPoint(point.x - (float)(OBJECT_WIDTH / 2), point.y);
    p4.setPoint(point.x + (float)(OBJECT_WIDTH / 2), point.y);
    p5.setPoint(point.x - (float)(OBJECT_WIDTH / 4), point.y - (float)(OBJECT_HEIGHT) / 2);
    p6.setPoint(point.x + (float)(OBJECT_WIDTH / 4), point.y - (float)(OBJECT_HEIGHT) / 2);
 
    if (!isUnderLine(p1, p2, anyPoint)) return false;
    if (!isUnderLine(p2, p4, anyPoint)) return false;
    if ( isUnderLine(p4, p6, anyPoint)) return false;
    if ( isUnderLine(p6, p5, anyPoint)) return false;
    if ( isUnderLine(p5, p3, anyPoint)) return false;
    if (!isUnderLine(p3, p1, anyPoint)) return false;
    return true;
}
cs

 터치된 좌표가 육각형 테두리 안에 속하는 지를 검사해야 하는데

참고하고 있는 책의 예시는 사각형 퍼즐이라 간단하게

배열좌표 to 화면좌표 함수의 역함수를 만들어

터치된 좌표를 통해 배열의 좌표를 역추적할 수가 있는데

 

 여기선 육각형이라서 서로 좌표가 겹치는 부분 때문에 다른 방식을 취해야 한다.

 

원리부터 얘기하면

 우리가 육각형테두리를 그릴 때 육각형의 중심을 0,0으로 정했던 것을 기억할 것이다.

육각형 하나만 놓고 봤을 때 터치된 지점을 임의의 점으로 보고

육각형을 2차원 좌표에 위치하는 도형으로 생각한다.

 

대충 이런 느낌이다.

6각형은 6개의 선분으로 이루어져 있고

6개의 선분은 6개의 꼭짓점을 이용해 직선 방정식으로 표현할 수 있다.

이 6개의 직선 사이에 임의의 점이 위치하면

육각형을 클릭한 것으로 보는 것이다.

 

해설들어간다

26~32행 - 2점 사이를 지나는 직선의 방정식을 구하는 함수이다.

              y = ax + b의 형태로 표현하는데

              주어진 두점 x1,y1, x2,y2를 계산해 직선의 방정식을 구하고

              임의의 점 x3,y3를 대입했을 때 y3가 방정식의 해보다 작거나 같으면

              임의의 점이 직선과 겹치거나 혹은 직선 보다 아래쪽에 있다는 것을 계산한다.

              겹치는 경우를 포함하지 않으면 정확하게 육각형의 테두리를 터치했을 때가 처리가 안되기 때문이다.

 

35~42행 - 육각형의 중심을 0,0으로 잡았으므로 도형의 가로, 세로 길이를 알고 있기 때문에

              6개의 꼭짓점을 구할 수 있다. x = { -가로길이/2, -가로길이/4, +가로길이/4, +가로길이/2 } 가 있고

              y =  { +세로길이/2, 0, -세로길이/2 }가 있다.

              왼쪽 위 꼭짓점부터 z자를 그리며 점 1,2,3,4,5,6의 좌표를 지정했다.

 

44~50행 - 26행의 isUnderLine() 함수를 활용해 임의의 점이

              육각형의 내부에 있는지를 검사한다.

 

1~23행 - 이렇게 만들어진 isInHexagon() 함수를 사용해

            모든 육각형에 대해서 터치된 지점이 해당 육각형에 포함되는 지를 검사하고

            해당하는 육각형의 배열 좌표를 반환한다.

 

 

 터치된 지점의 블록이 잘 켜고 꺼짐을 확인했다.

 

Posted by gharlic