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, 0, 50); 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, 1, 50); pChar->setPosition(100, 176.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(1100, 0); 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(0, 64 + 128); addChild(g2, 1, 2); } // 2층 -> 1층이면 마지막타일에도 2층 올려줌 else if (gno == 12) { Sprite* g2 = Sprite::create("res/Tiles/3.png"); g2->setPosition(0, 64 + 128); addChild(g2, 1, 2); } // 1층 -> 2층이면 2층올려줌 else if (gno == 15) { Sprite* g2 = Sprite::create("res/Tiles/1.png"); g2->setPosition(0, 64 + 128); addChild(g2, 1, 2); } //////////////////////////////////////////////////// 위치 // 공중이면 위치올림 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(0, 300); else g1->setPosition(0, 500); } // 아니면 기본위치 else g1->setPosition(0, 64); //////////////////////////////////////////////////// 기본 장애물 추가 - 1층 (물은 추가안함) if(gno != 10) addChild(g1, 1, 1); //////////////////////////////////////////////////// 물은 장애물 상관없이 항상 따라나오게. Sprite* g3 = Sprite::create("res/Tiles/10.png"); g3->setPosition(0, 49); addChild(g3, 0, 3); } // 장애물은 화면밖에서 생성되므로 게임시작하면 보일 한 화면정도의 기본 장애물 생성 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], 1, 200 + i); } //////////////////////////////////////////////////// 물은 장애물 상관없이 항상 따라나오게. Sprite* g3 = Sprite::create("res/Tiles/10.png"); g3->setPosition(128 * i + startpointX, 49); addChild(g3, 0, 3); } } | cs |
별건없는데 코드가 쪼끔 길어졌다.
장애물을 하나씩 잘라 붙여서 경우에 따른 케이스마다 구현하여서 길어진듯.
실행화면
이번에도 만족스럽게 만들진 못했지만 그래도 이렇게 구현해봤으니 다음번에 만들게 되면 더 잘 만들수 있을 것 같다.
'프로그래밍 공부 > 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 |