Character 클래스는 아래와 같다

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
#pragma once
#include <cocos2d.h>
USING_NS_CC;
 
class Character : public Node
{
private:
    float fjump;
    int jumpcount;
    bool enableAni;
    int cstop;
    float gravity;
 
public:
    Character();
    ~Character();
 
    void runAnimation();
    void jump();
    void resetjumpcount();
    bool getenableAni();
    void fjumpinit();
    int getstop();
    void astop();
    void astart();
    void gravityon();
    void gravityoff();
 
    bool init();
    void update(float dt);
    
 
    virtual bool onTouchBegan(Touch *touch, Event *unused_event);
    virtual void onTouchMoved(Touch *touch, Event *unused_event);
    virtual void onTouchEnded(Touch *touch, Event *unused_event);
    virtual void onTouchCancelled(Touch *touch, Event *unused_event);
    CREATE_FUNC(Character);
};
cs


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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
#include "Character.h"
 
 
Character::Character()
{
    fjump = 0;         // 점프값 수치조정
    jumpcount = 0;      // 이단점프 제한하기위해 카운트
    enableAni = true;// 애니메이션 실행체크
    cstop = 0;         // 게임을 잠깐 멈추기위해
    gravity = 300.0f;
}
 
 
Character::~Character()
{
 
}
 
// 달리는 애니메이션을 실행하는 함수
void Character::runAnimation()
{
    Animation* ani = Animation::create();
    for (int i = 1; i <= 11; i++)
    {
        std::string fileName = StringUtils::format("p3_walk%02d.png",i);
        ani->addSpriteFrameWithFile(fileName);
    }
 
    ani->setLoops(true);
    ani->setDelayPerUnit(0.08f);
 
    Animate* animate = Animate::create(ani);
    auto pChar = (Sprite*)getChildByTag(50);
    pChar->stopAllActions();
    RepeatForever* pRepeat = RepeatForever::create(animate);
    pChar->runAction(pRepeat);
 
    enableAni = false;    
}
 
// 점프할시 점프모션으로 바꿔주는 함수
void Character::jump()
{
    Sprite* pSprite = Sprite::create("p3_jump.png");
    Sprite* oldSprite = (Sprite*)getChildByTag(50);
    pSprite->setPosition(oldSprite->getPosition());
    oldSprite->removeFromParent();
    addChild(pSprite, 050);
 
    enableAni = true;
}
 
void Character::resetjumpcount()
{
    jumpcount = 0;
}
 
bool Character::getenableAni()
{
    return enableAni;
}
 
void Character::fjumpinit()
{
    fjump = 0;
}
 
int Character::getstop()
{
    return cstop;
}
 
void Character::astop()
{
    cstop = 1;
}
 
void Character::astart()
{
    cstop = 0;
}
 
void Character::gravityon()
{
    gravity = 300.0f;
}
 
void Character::gravityoff()
{
    gravity = 0;
}
 
bool Character::init()
{
    // 기본 캐릭터 생성
    FileUtils::getInstance()->addSearchPath("res/Character");
    Sprite* pChar = Sprite::create("p3_walk01.png");
    addChild(pChar, 150);
    pChar->setPosition(100176.6f);
 
    runAnimation();
 
    // 터치효과(점프) 추가
    auto listener = EventListenerTouchOneByOne::create();
    listener->setSwallowTouches(true);
 
    listener->onTouchBegan = CC_CALLBACK_2(Character::onTouchBegan, this);
    _eventDispatcher->addEventListenerWithSceneGraphPriority(listener, this);
 
    scheduleUpdate();
    return true;
}
 
void Character::update(float dt)
{
    auto pChar = (Sprite*)getChildByTag(50);
    // 주인공이 널이면 실행안하게 예외처리
    if (pChar)
    {
        pChar->setPositionY(pChar->getPositionY() + (fjump - gravity) * dt);
 
        // 점프 테스트하기 위해 가상의 바닥을 생성
        if (pChar->getPositionY() < 176.6f)
        {
            pChar->setPositionY(176.6f);
            resetjumpcount();
        }
        
        if (getenableAni())
        {
            runAnimation();
        }
    }
 
    if (fjump != 0)
        fjump -= 1000.0f * dt;
    
    if (fjump <= 0)
        fjump = 0;
}
 
bool Character::onTouchBegan(Touch * touch, Event * unused_event)
{
    if (jumpcount < 2)
    {
        fjump += 950.0f;
        if (fjump >=950.0f)
            fjump = 950.0f;
    }
    jumpcount++;
 
    // 점프동작으로 sprite 바꿔줌
    jump();
 
    return true;
}
cs

점프는 플래피버드처럼 기본적으로 구현한것에 조금 더 수정하고 애니메이션을 추가하였다.

그 외에는 필요한 함수들을 작성함.




Ground 클래스는 아래와 같다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
class Ground : public Node
{
private:
    int type;
    int gno;
 
public:
    Ground();
    ~Ground();
    bool init();
    void update(float dt);
    void print();
    void basicgroundprint();
    CREATE_FUNC(Ground);
};
cs


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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
#include "Ground.h"
#include "GameLayer.h"
#include "UILayer.h"
#include "Character.h"
 
 
Ground::Ground()
{
    gno = 0;
}
 
 
Ground::~Ground()
{
}
 
bool Ground::init()
{
    setPosition(11000);
 
    scheduleUpdate();
    return true;
}
 
void Ground::update(float dt)
{
    auto gl = (GameLayer*)getParent();
    auto pChar = (Character*)gl->getChildByTag(100);
    auto pHero = pChar->getChildByTag(50);
    auto pGr = getChildByTag(1);
    auto pGr2 = getChildByTag(2);
 
    if (pHero)
    {
        Rect HeroRect = pHero->getBoundingBox();
        // 충돌처리
        if (pGr)
        {
            Rect GrRect = pGr->getBoundingBox();
            GrRect.origin += getPosition();
 
            // 장애물과 충돌하면
            if (HeroRect.intersectsRect(GrRect))
            {
                // 위에서 충돌하면 장애물위로 옮기고 점프카운트 초기화
                if (HeroRect.origin.x + pHero->getContentSize().width >= GrRect.origin.x && HeroRect.origin.y >= GrRect.origin.y)
                {
                    pChar->astart();
                      
                    pChar->fjumpinit();
                    pChar->gravityoff();
 
                    float alpha = pGr->getPositionY();
                    alpha += pGr->getContentSize().height / 2.0f;
                    alpha += pHero->getContentSize().height / 2.0f;
 
                    pHero->setPositionY(alpha);
                    pChar->resetjumpcount();
 
                    if (pChar->getenableAni())
                    {
                        pChar->runAnimation();
                    }
                }
                // 아래쪽에서 충돌하면
                else if (HeroRect.origin.x + pHero->getContentSize().width >= GrRect.origin.x && HeroRect.origin.y < GrRect.origin.y)
                {
                    pChar->fjumpinit();
                    // HP를 깎음
                    auto ul = (UILayer*)gl->getParent()->getChildByName("UI");
                    int hp = ul->gethp();
                    if (hp >= 1)
                    {
                        ul->getChildByTag(hp)->setVisible(false);
                        ul->hpdown();
                    }
                }
                // 왼쪽에서 충돌하면(구현이 조금 잘 안됨)
                else if (HeroRect.origin.x < GrRect.origin.x && HeroRect.origin.y < GrRect.origin.y + pGr->getContentSize().height && HeroRect.origin.y + pHero->getContentSize().height > GrRect.origin.y)
                {
                    if (pGr->getUserData() == (void*)10)
                    {
                        pChar->fjumpinit();
                        pChar->astop();
                        //pHero->setPositionY(GrRect.origin.y - 50);
                        auto ul = (UILayer*)gl->getParent()->getChildByName("UI");
                        int hp = ul->gethp();
                        if (hp >= 1)
                        {
                            ul->getChildByTag(hp)->setVisible(false);
                            ul->hpdown();
                        }
                    }
                }
            }
            else
                pChar->gravityon();
        }
 
        // 2층이 존재하면 2층 충돌처리
        if (pGr2)
        {
            Rect GrRect2 = pGr2->getBoundingBox();
            GrRect2.origin += getPosition();
 
            if (HeroRect.intersectsRect(GrRect2))
            {
                if (HeroRect.origin.x >= GrRect2.origin.x && HeroRect.origin.y >= GrRect2.origin.y)
                {
                    float alpha = pGr2->getPositionY();
                    alpha += pGr2->getContentSize().height / 2.0f;
                    alpha += pHero->getContentSize().height / 2.0f;
 
                    pHero->setPositionY(alpha);
                    pChar->resetjumpcount();
 
                    if (pChar->getenableAni())
                    {
                        pChar->runAnimation();
                    }
                }
            }
        }
 
        // 장애물의 이동
        if(!pChar->getstop())
            setPositionX(getPositionX() - 256.0f * dt);
 
        if (getPositionX() < -400)
            removeFromParent();
    }
}
 
// 장애물을 출력하는 함수
void Ground::print()
{
    auto gl = (GameLayer*)getParent();
    int p = gl->getgno();
 
    // 이전 장애물이 마지막이나 물이면 -> 다음거 시작 아무거나
    if (p == 3 || p == 6 || p == 9 || p == 10)        
    {
        int t = rand() % 4// 0~3 사이 랜덤
        gno = 3 * t + 1;
 
        //같은층이 나오거나, 3->4가 나오거나, 6->1이 나오면 다시돌림
        while (gno == p - 2 || (p==3&&gno==4|| (p==6&&gno==1))
        {
            // 1,4,7이 시작
            int t = rand() % 4// 0~3 사이 랜덤
            gno = 3 * t + 1;
        }
    }
    // 이전 장애물이 1층이면
    else if (p == 1 || p == 13)
    {
        gno = rand() % 2 + 2// 2~3 사이 랜덤
    }
    else if (p == 2)
    {
        gno = rand() % 3 + 2// 2~4 사이 랜덤
        if (gno == 4)
            gno = 14;
    }
    
    // 이전 장애물이 2층이면
    else if (p == 4 || p == 15)
    {
        gno = rand() % 2 + 5// 5~6 사이 랜덤
    }
    else if (p == 5)
    {
        gno = rand() % 3 + 5// 5~7 사이 랜덤
        if (gno == 7)
        {
            gno = 12;
        }
    }
 
    // 이전 장애물이 공중이면
    else if (p == 7 || p == 8)
    {
        gno = rand() % 2 + 8// 8~9 사이 랜덤
    }
 
    // 이전 장애물이 1층에서 2층으로 올라가면
    else if (p == 12)
    {
        gno = 13;
    }
 
    // 이전 장애물이 2층에서 1층으로 내려오면
    else if (p == 14)
    {
        gno = 15;
    }
 
    gl->setgno(gno);
    
    std::string fileName = StringUtils::format("res/Tiles/%d.png", gno);
    //log(fileName.c_str());
    Sprite* g1 = Sprite::create(fileName);
    if (gno == 1 || gno == 4 || gno == 7)
        // 첫번째일때만 userdata를 10. 10일때만 왼쪽충돌
        g1->setUserData((void*)10);
    else
        g1->setUserData((void*)20);
 
 
    //////////////////////////////////////////////////// 2층추가
    
    // 2층이면 2층 추가
    if (gno == 4 || gno == 5 || gno == 6)
    {
        std::string fileName = StringUtils::format("res/Tiles/%d.png", gno-3);
        Sprite* g2 = Sprite::create(fileName);
        g2->setPosition(064 + 128);
        addChild(g2, 12);
    }
    // 2층 -> 1층이면 마지막타일에도 2층 올려줌
    else if (gno == 12)
    {
        Sprite* g2 = Sprite::create("res/Tiles/3.png");
        g2->setPosition(064 + 128);
        addChild(g2, 12);
    }
    // 1층 -> 2층이면 2층올려줌
    else if (gno == 15)
    {
        Sprite* g2 = Sprite::create("res/Tiles/1.png");
        g2->setPosition(064 + 128);
        addChild(g2, 12);
    }
    
 
    //////////////////////////////////////////////////// 위치
    // 공중이면 위치올림
    if (gno == 7 || gno == 8 || gno == 9)
    {
        if (p == 1 || p == 2 || p == 3 || p == 13)
            gl->setairno(1);
        else if(p == 4 || p == 5 || p == 6 || p == 15)
            gl->setairno(0);
 
        if(gl->getairno())
            g1->setPosition(0300);
        else
            g1->setPosition(0500);
    }
    // 아니면 기본위치
    else
        g1->setPosition(064);
 
    
    //////////////////////////////////////////////////// 기본 장애물 추가 - 1층 (물은 추가안함)
    if(gno != 10)
        addChild(g1, 11);
 
    
 
    //////////////////////////////////////////////////// 물은 장애물 상관없이 항상 따라나오게. 
    Sprite* g3 = Sprite::create("res/Tiles/10.png");
    g3->setPosition(049);
    addChild(g3, 03);
}
 
 
// 장애물은 화면밖에서 생성되므로 게임시작하면 보일 한 화면정도의 기본 장애물 생성
void Ground::basicgroundprint()
{
    float startpointX = -1023.0f;
    Sprite* g[9];
    for (int i = 0; i < 9; i++)
    {
        if (i == 0)
            g[i] = Sprite::create("res/Tiles/1.png");
        else if (i < 6)
            g[i] = Sprite::create("res/Tiles/2.png");
        else if (i == 6)
            g[i] = Sprite::create("res/Tiles/3.png");
    
        if (i < 7)
        {
            g[i]->setPosition(128 * i + startpointX, 64);
            addChild(g[i], 1200 + i);
        }
 
        //////////////////////////////////////////////////// 물은 장애물 상관없이 항상 따라나오게. 
        Sprite* g3 = Sprite::create("res/Tiles/10.png");
        g3->setPosition(128 * i + startpointX, 49);
        addChild(g3, 03);
    }
}
 
cs

별건없는데 코드가 쪼끔 길어졌다.


장애물을 하나씩 잘라 붙여서 경우에 따른 케이스마다 구현하여서 길어진듯.



실행화면

이번에도 만족스럽게 만들진 못했지만 그래도 이렇게 구현해봤으니 다음번에 만들게 되면 더 잘 만들수 있을 것 같다.


RunningGame.mp4

'프로그래밍 공부 > cocos2d-x' 카테고리의 다른 글

Tank Game 만들기 - 2  (0) 2018.03.28
Tank Game 만들기 - 1  (0) 2018.03.28
Running Game 만들기 - 1  (0) 2018.03.28
기타 잡다한 팁들  (0) 2018.03.28
사운드 사용하기 (오디오 엔진)  (0) 2018.03.28
Posted by misty_
,