개요

cocos2dx 자체의 버튼 클래스가 존재하는 것으로 알지만,

원하는 기능인 버튼이 눌린 상태를 체크할 방법과 여러 콜백함수 등록기능을 사용하기 위해 자체 클래스를 만들었습니다.

최대한 사용자가 버튼을 만들어 사용할 때 편리할 수 있도록 구현하였습니다.


코드 및 설명은 아래와 같습니다. 

(가독성을 위해 적당히 편집하였습니다.)


코드

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
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
/*--------------------------CMyButton--------------------------
 * strategy pattern
 * texture 혹은 label로 초기화하여 사용하는 Button
 * Lambda혹은 함수포인터, 함수객체를 인자로 받는다.
 * 눌렀을때 체크
 * 누르고 있을 때 체크
 * 끝났을 때 체크 
 * ------------------------------------------------------------*/
 
 
 
 
/* 버튼의 상태 */
enum eMYBUTTON_STATE{
    BEGIN = 0,
    EXECUTE = 1,
    END = 2,
}
 
 
/* 텍스쳐와 함께 버튼 생성 
 * normalImg와 selectedImg를 인자로 전달*/
CMyButton* CMyButton::createWithTexture(
    std::string normalTextureName,                // 선택 전 버튼의 텍스쳐 이름
    std::string selectedTextureName,              // 선택 중 버튼의 텍스쳐 이름
    eMYBUTTON_STATE state,                        // 버튼 상태 (해당 상태일 때 함수 호출됨)
    const std::function<void(void)> &func)        // 람다 혹은 함수포인터 혹은 함수객체 전달(매개 변수는 void)
 
 
/* 문자열과 함께 버튼 생성 */
CMyButton* CMyButton::createWithString(
    std::string normalTextureName,                // 버튼의 텍스쳐 이름
    std::string labelString,                      // 버튼의 label 내용
    int fontSize,                                 // 폰트 사이즈
    eMYBUTTON_STATE state,                        // 버튼 상태 (해당 상태일 때 함수 호출됨)
    const std::function<void(void)> &func)        // 람다 혹은 함수포인터 혹은 함수객체 전달(매개 변수는 void)
 
 
/* 버튼의 함수 포인터 리스트에 함수 포인터 추가 */
void AddState(eMYBUTTON_STATE state,             // 상태 (해당 상태일 때 함수 호출됨)
    const std::function<void(void)> &func)        // 람다 혹은 함수포인터 혹은 함수객체 전달(매개 변수는 void)
 
 
/* 터치된 좌표를 버튼의 좌표로 변환 한 후에 버튼이 터치되었는지 검사 */
bool touchHits(Touch  *touch)
{
    const Rect area(00, m_pNormalTexture->getContentSize().width, 
        m_pNormalTexture->getContentSize().height);
 
    // world to nodespace 좌표 변환
    return area.containsPoint(m_pNormalTexture->convertToNodeSpace(touch->getLocation()));
}
 
 
/* 버튼이 눌렸을 때 BEGIN */
bool onTouchBegan(Touch  *touch, Event  *event)
{
    CC_UNUSED_PARAM(event);
    if (m_pNormalTexture){
 
        // 좌표 변환 후 터치 체크
        m_IsSelect = touchHits(touch);
 
        // 버튼의 좌표에서 진짜로 터치되었을 경우
        if (m_IsSelect){
 
            // BEGIN 상태일때 호출해야할 함수가 있다면 호출
            std::for_each(m_BeginFuncList.begin(), m_BeginFuncList.end(), 
                [](const std::function<void(void)> &func){
                func();
            });
            
            // 선택 시 이미지가 있다면 이미지 교체
            if (m_SelectedTextureName != ""){                    
                m_pNormalTexture->setTexture(m_SelectedTextureName);
            }
            else { // 교체될 이미지가 없다면 크기를 키움                                                
                m_pNormalTexture->setScale(1.1f);
            }
        }
    }
    return m_IsSelect;
}
 
 
/* 버튼에서 떨어졌을 때 END */
void CMyButton::onTouchEnded(Touch  *touch, Event  *event)
{
    CC_UNUSED_PARAM(event);
    if (m_pNormalTexture){
 
        // END 상태일때 호출해야할 함수가 있다면 호출
        std::for_each(m_EndFuncList.begin(), m_EndFuncList.end(), 
            [](const std::function<void(void)> &func){
            func();
        });
 
        // 이미지가 바뀌었었다면 다시 원래대로 바꿈
        if (m_SelectedTextureName != ""){                        
            m_pNormalTexture->setTexture(m_NormalTextureName);
        }
        else// 바뀔이미지가 없다면 크기를 원래대로 바꿈                                                    
            m_pNormalTexture->setScale(1.0f);
        }
 
        // 버튼 눌림 종료
        m_IsSelect = false;
    }
}
 
 
/* 버튼이 눌리고 있는 중일때 EXECUTE */
void Execute(float delta)
{
    // 버튼 눌림 상태이며, EXECUTE 상태일 때 실행되어야 할 함수가 1개 이상일 때
    if (m_IsSelect && m_ExecuteFuncList.size())
    {
        // EXECUTE 상태일때 호출해야할 함수가 있다면 호출
        std::for_each(m_ExecuteFuncList.begin(), m_ExecuteFuncList.end(), 
            [](const std::function<void(void)> &func){
            func();
        });
    }
}
 
 
/* lambda, 함수 포인터를 리스트로 저장
 * 각 상태일 때 호출할 함수를 저장하는 리스트 */
std::vector<std::function<void(void)>> m_BeginFuncList;
std::vector<std::function<void(void)>> m_ExecuteFuncList;
std::vector<std::function<void(void)>> m_EndFuncList;
cs

CMyButton 클래스의 주요 함수 및 동작원리 설명

1. 전략 디자인 패턴의 변형으로 버튼 생성시 함수 포인터를 전달합니다.

2. 때문에 사용자는 버튼을 눌렀을 때의 상황에 대해 부담없이 정의할 수 있습니다.

3. 각 버튼은 Begin, Execute, End의 상태를 가질 수 있습니다.

4. 각 상태에 맞는 함수를 생성시 초기화 혹은 AddState 함수로 추가할 수 있습니다. 


사용 예

1
2
3
4
5
auto leftButton = CMyButton::createWithTexture(
        "leftButton_1.png",
        "leftButton_2.png",
        EXECUTE,
        std::bind(&CObjectManager::RotationObject, CObjectManager::Instance(), -1)); 
cs

1. 눌리기 전엔 leftButton_1.png, 눌린 상태엔 leftButton_2.png의 이미지를 보이는 버튼을 생성합니다.

2. 버튼이 눌린 상태(EXECUTE)일 때 CObjectManager::Instance()의 RotationObject(int dir) 함수를 호출합니다.

3. std::bind : 함수 호출 시 전달하는 매개변수를 -1로 고정하고, 호출하는 인스턴스는 CObjectManager::Instance()로써 bind합니다.



귀차니즘을 위한 2줄 요약

1. Button에는 Begin, Execute, End 3 가지의 상태가 존재한다.

2. Button을 create할때 각 상태에 호출될 함수를 넣을 수 있다.


'All > Project' 카테고리의 다른 글

매주 일요일 랭킹 초기화  (0) 2017.04.05
UI_ HealthBarUI  (0) 2016.04.12
별게임의 상태트리  (0) 2016.04.12
AI_ FSM / State  (0) 2016.04.12
Shooter / Bullet  (0) 2016.04.12

+ Recent posts