5가지 실전 게임으로 배우는 코코스2d-x(cocos2d-x) 모바일 2D 게임 개발 두번째 예제(4)
- Study/Cocos2d-x 3.x
- 2014. 8. 28. 20:52
게임 완성 코드입니다.
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 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587 | #include "GameLayer.h" USING_NS_CC; using namespace CocosDenshion; Scene* GameLayer::createScene() { // 'scene' is an autorelease object auto scene = Scene::create(); // 'layer' is an autorelease object auto layer = GameLayer::create(); // add layer as a child to scene scene->addChild(layer); // return the scene return scene; } // on "init" you need to initialize your instance bool GameLayer::init() { CC_SAFE_RELEASE(_growBomb); CC_SAFE_RELEASE(_rotateSprite); CC_SAFE_RELEASE(_swingHealth); CC_SAFE_RELEASE(_groundHit); CC_SAFE_RELEASE(_explosion); ////////////////////////////// // 1. super init first if ( !Layer::init() ) { return false; } auto listener = EventListenerTouchAllAtOnce::create(); listener->onTouchesBegan = CC_CALLBACK_2(GameLayer::onTouchesBegan, this); Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(listener, 1); _clouds.clear(); _meteorPool.clear(); _healthPool.clear(); _fallingObjects.clear(); initBS(); createGameScreen(); _running = false; //create object pools createPools(); //create CCActions createActions(); //create main loop this->schedule(schedule_selector(GameLayer::update)); return true; } void GameLayer::initBS() { SimpleAudioEngine::getInstance()->playBackgroundMusic("background.mp3",true); SimpleAudioEngine::getInstance()->setBackgroundMusicVolume(0.4f); } void GameLayer::createGameScreen() { auto bg = Sprite::create("bg.png"); bg->setPosition(Point(winSize.width/2,winSize.height/2)); bg->setAnchorPoint(Point(0.5,0.5)); this->addChild(bg); SpriteFrameCache::getInstance()->addSpriteFramesWithFile("sprite_sheet.plist"); _gameBatchNode = SpriteBatchNode::create("sprite_sheet.png"); this->addChild(_gameBatchNode,BATCH_TAG); auto sprite=Sprite::create(); for (int i=0; i<2; i++) { sprite = Sprite::createWithSpriteFrameName("city_dark.png"); sprite->setPosition(Point(winSize.width*(0.25f+i*0.5f),sprite->getContentSize().height*0.5f)); _gameBatchNode->addChild(sprite,kForeground); sprite=Sprite::createWithSpriteFrameName("city_light.png"); sprite->setPosition(Point(winSize.width*(0.25f+i*0.5f),sprite->getContentSize().height*0.9f)); _gameBatchNode->addChild(sprite,kBackground); } for (int i=0; i<3; i++) { sprite=Sprite::createWithSpriteFrameName("trees.png"); sprite->setPosition(Point(winSize.width*(0.2f+i*0.3f),sprite->getContentSize().height*0.5f)); _gameBatchNode->addChild(sprite,kForeground); } _scoreDisplay = LabelBMFont::create("0", "font.fnt",winSize.width*0.3f); _scoreDisplay->setAnchorPoint(Point(1,0.5)); _scoreDisplay->setPosition(winSize.width*0.8f,winSize.height*0.94f); this->addChild(_scoreDisplay); _energyDisplay = LabelBMFont::create("100%", "font.fnt",winSize.width*0.1f,TextHAlignment::RIGHT); _energyDisplay->setPosition(Point(winSize.width*0.3f,winSize.height*0.94f)); this->addChild(_energyDisplay); auto icon = Sprite::createWithSpriteFrameName("health_icon.png"); icon->setPosition(Point(winSize.width*0.15f,winSize.height*0.94f)); _gameBatchNode->addChild(icon,kBackground); auto cloud=Sprite::create(); float cloud_y; for (int i=0; i<4; i++) { cloud_y= i%2==0? winSize.height*0.4f:winSize.height*0.5f; cloud =Sprite::createWithSpriteFrameName("cloud.png"); cloud->setPosition(Point(winSize.width*0.1f+i*winSize.width*0.3f,cloud_y)); _gameBatchNode->addChild(cloud,kBackground); _clouds.pushBack(cloud); } _bomb = Sprite::createWithSpriteFrameName("bomb.png"); _bomb->getTexture()->generateMipmap(); _bomb->setVisible(false); Size size = _bomb->getContentSize(); auto sparkle = Sprite::createWithSpriteFrameName("sparkle.png"); sparkle->setPosition(Point(size.width*0.72f,size.height*0.72f)); _bomb->addChild(sparkle,kMiddleground,kSpriteSparkle); auto halo = Sprite::createWithSpriteFrameName("halo.png"); halo->setPosition(Point(size.width*0.4f,size.height*0.4f)); _bomb->addChild(halo,kMiddleground,kSpriteHalo); _gameBatchNode->addChild(_bomb,kForeground); _shockWave = Sprite::createWithSpriteFrameName("shockwave.png"); _shockWave->getTexture()->generateMipmap(); _shockWave->setVisible(false); _gameBatchNode->addChild(_shockWave); _introMessage = Sprite::createWithSpriteFrameName("logo.png"); _introMessage->setPosition(Point(winSize.width*0.5,winSize.height*0.6)); _introMessage->setVisible(true); _gameBatchNode->addChild(_introMessage,kBackground); _gameOverMessage = Sprite::createWithSpriteFrameName("gameover.png"); _gameOverMessage->setPosition(Point(winSize.width*0.5f,winSize.height*0.65f)); _gameOverMessage->setVisible(false); this->addChild(_gameOverMessage,kForeground); } void GameLayer::createPools() { auto sprite=Sprite::create(); int i; _meteorPoolIndex =0; for(i=0;i<50;i++){ sprite = Sprite::createWithSpriteFrameName("meteor.png"); sprite->setVisible(false); _gameBatchNode->addChild(sprite,kMiddleground,kSpriteMeteor); _meteorPool.pushBack(sprite); } _healthPoolIndex = 0; for (i=0; i<20; i++) { sprite = Sprite::createWithSpriteFrameName("health.png"); sprite->setVisible(false); sprite->setAnchorPoint(Point(0.5f,0.8f)); _gameBatchNode->addChild(sprite,kMiddleground,kSpriteHealth); _healthPool.pushBack(sprite); } } void GameLayer::createActions() { FiniteTimeAction * easeSwing = Sequence::create(EaseInOut::create(RotateTo::create(1.2f,-10),2), EaseInOut::create(RotateTo::create(1.2f, 10),2),NULL); _swingHealth = RepeatForever::create((ActionInterval*)easeSwing); _swingHealth->retain(); _growBomb = ScaleTo::create(6.0f,1.0); _growBomb->retain(); ActionInterval* rotate = RotateTo::create(0.5f,-90); _rotateSprite = RepeatForever::create(rotate); _rotateSprite->retain(); } void GameLayer::shockwaveDone() { _shockWave->setVisible(false); } void GameLayer::removeEx(Ref* sender) { auto spr = (Sprite*) sender; this->removeChild(spr); } void GameLayer::animationDone(Ref* pSender) { auto spr = (Sprite*)pSender; spr->setVisible(false); _meteorPool.pushBack(spr); } void GameLayer::onTouchesBegan(const std::vector<Touch*>&touches, Event *unused_event) { if (!_running) { if (_introMessage->isVisible()) { _introMessage->setVisible(false); }else if (_gameOverMessage->isVisible()){ SimpleAudioEngine::getInstance()->stopAllEffects(); _gameOverMessage->setVisible(false); } this->resetGame(); return; } std::vector<Touch*>::const_iterator it = touches.begin(); Touch *touch; for(int i=0;i<touches.size();i++){ touch=(Touch*)(*it); if (touch) { if (_bomb->isVisible()) { _bomb->stopAllActions(); auto child=Sprite::create(); child=(Sprite*)_bomb->getChildByTag(kSpriteHalo); child->stopAllActions(); child=(Sprite*)_bomb->getChildByTag(kSpriteSparkle); child->stopAllActions(); if (_bomb->getScale()>0.3f) { _shockWave->setOpacity(255); _shockWave->setScale(0.1f); _shockWave->setPosition(_bomb->getPosition()); _shockWave->setVisible(true); _shockWave->runAction(ScaleTo::create(0.5f, _bomb->getScale()*2.0f)); auto action = Sequence::create(FadeOut::create(1.0f), CallFunc::create(CC_CALLBACK_0(GameLayer::shockwaveDone, this)),NULL); _shockWave->runAction(action); SimpleAudioEngine::getInstance()->playEffect("bombRelease.wav"); }else{ SimpleAudioEngine::getInstance()->playEffect("bombFail.wav"); } _bomb->setVisible(false); _shockwaveHits = 0; }else{ Point tap = touch->getLocation(); _bomb->stopAllActions(); _bomb->setScale(0.1f); _bomb->setPosition(tap); _bomb->setVisible(true); _bomb->setOpacity(50); _bomb->runAction((Action*)_growBomb); auto child=Sprite::create(); child = (Sprite*) _bomb->getChildByTag(kSpriteHalo); child->runAction(_rotateSprite); child = (Sprite*) _bomb->getChildByTag(kSpriteSparkle); child->runAction((Action*)_rotateSprite); } } it++; } } void GameLayer::resetGame(){ _score =0; _energy=100; _meteorInterval = 2.5; _meteorTimer = _meteorInterval *0.99f; _meteorSpeed =10; _healthInterval=20; _healthTimer = 0; _healthSpeed=15; _difficultyInterval =60; _difficultyTimer = 0; _running = true; std::string value = StringUtils::format("%i%s",_energy,"%"); _energyDisplay->setString(value); value = StringUtils::format("%i",_score); _scoreDisplay->setString(value); } void GameLayer::stopGame(){ _running = false; for(Sprite*spr:_fallingObjects) { spr->stopAllActions(); spr->setVisible(false); _fallingObjects.eraseObject(spr); } if(_bomb->isVisible()){ _bomb->stopAllActions(); _bomb->setVisible(false); auto child= (Sprite*)_bomb->getChildByTag(kSpriteHalo); child->stopAllActions(); child=(Sprite*)_bomb->getChildByTag(kSpriteSparkle); child->stopAllActions(); } if (_shockWave->isVisible()) { _shockWave->stopAllActions(); _shockWave->setVisible(false); } } void GameLayer::fallingObjectDone (Ref* pSender) { //remove it from array auto sSprite = (Sprite*)pSender; for(Sprite*spr:_fallingObjects) { if (spr == pSender) { _fallingObjects.eraseObject(spr); //_meteorPool.pushBack(spr); } } sSprite->stopAllActions(); sSprite->setRotation(0); //if object is a meteor... if (sSprite->getTag() == kSpriteMeteor) { _energy -= 15; //show explosion animation auto animation = Animation::create(); animation->setDelayPerUnit(0.1); for (int i=1; i<=10; i++) { auto frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(StringUtils::format("boom%i.png",i)); animation->addSpriteFrame(frame); } animation->setRestoreOriginalFrame(true); _groundHit =Sequence::create(MoveBy::create(0, Point(0,winSize.height*0.12f)), Animate::create(animation), CallFuncN::create(CC_CALLBACK_1(GameLayer::animationDone, this)), NULL); sSprite->runAction((Action*)_groundHit); //play explosion sound SimpleAudioEngine::getInstance()->playEffect("boom.wav"); //if object is a health drop... } else { sSprite->setVisible(false); //if energy is full, score points from falling drop if (_energy == 100) { _score += 25; char score[100] = {0}; sprintf(score, "%i", _score); _scoreDisplay->setString(score); } else { _energy+= 10; if (_energy > 100) _energy = 100; } //play health bonus sound SimpleAudioEngine::getInstance()->playEffect("health.wav"); } //if energy is less or equal 0, game over if (_energy <= 0) { _energy = 0; this->stopGame(); SimpleAudioEngine::getInstance()->playEffect("fire_truck.wav"); //show GameOver this->stopGame(); _gameOverMessage->setVisible(true); } std::string value = StringUtils::format("%i%s",_energy,"%"); _energyDisplay->setString(value); } void GameLayer::update(float dt) { if (!_running) return; int count; //update timers _meteorTimer += dt; if (_meteorTimer > _meteorInterval) { _meteorTimer = 0; this->resetMeteor(); } _healthTimer += dt; if (_healthTimer > _healthInterval) { _healthTimer = 0; this->resetHealth(); } _difficultyTimer += dt; if (_difficultyTimer > _difficultyInterval) { _difficultyTimer = 0; this->increaseDifficulty(); } if (_bomb->isVisible()) { if (_bomb->getScale() > 0.3f) { if (_bomb->getOpacity() != 255) _bomb->setOpacity(255); } } //check collision with shockwave if (_shockWave->isVisible()) { count = _fallingObjects.size(); float diffx; float diffy; for (Sprite*spr : _fallingObjects) { diffx = _shockWave->getPositionX() - spr->getPositionX(); diffy = _shockWave->getPositionY() - spr->getPositionY(); if (pow(diffx, 2) + pow(diffy, 2) <= pow(_shockWave->boundingBox().size.width * 0.5f, 2)) { auto animation = Animation::create(); for (int i=1; i<=7; i++) { auto frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(StringUtils::format("explosion_small%i.png",i)); animation->addSpriteFrame(frame); } animation->setDelayPerUnit(0.14); animation->setRestoreOriginalFrame(true); auto explosion = Sequence::create(Animate::create(animation),CallFuncN::create(CC_CALLBACK_1(GameLayer::animationDone, this)),NULL); spr->stopAllActions(); spr->runAction( explosion); SimpleAudioEngine::getInstance()->playEffect("boom.wav"); if (spr->getTag() == kSpriteMeteor) { _shockwaveHits++; _score += _shockwaveHits * 13 + _shockwaveHits * 2; } _fallingObjects.eraseObject(spr); } } } std::string value = StringUtils::format("%i",_score); _scoreDisplay->setString(value); //move clouds count = _clouds.size(); for (Sprite*spr:_clouds) { spr->setPositionX(spr->getPositionX() + dt * 20); if (spr->getPositionX() > _screenSize.width + spr->getContentSize().width * 0.5f) spr->setPositionX(-spr->getContentSize().width * 0.5f); } if (_bomb->isVisible()) { if (_bomb->getScale()>0.3f) { if (_bomb->getOpacity()!=255) { _bomb->setOpacity(255); } } } } void GameLayer::resetSpr(Ref* sender) { auto spr= (Sprite*)sender; _fallingObjects.eraseObject(spr); _gameBatchNode->removeChild(spr, true); } void GameLayer::resetHealth() { if (_fallingObjects.size() > 30) return; auto health = _healthPool.front(); _healthPool.eraseObject(health); int health_x = rand() % (int) (winSize.width * 0.8f) + winSize.width * 0.1f; int health_target_x = rand() % (int) (winSize.width * 0.8f) + winSize.width * 0.1f; health->stopAllActions(); health->setPosition(Point(health_x, winSize.height + health->getContentSize().height * 0.5)); //create action (swing, move to target, and call function when done) FiniteTimeAction* sequence = Sequence::create( MoveTo::create(_healthSpeed, Point(health_target_x, winSize.height * 0.15f)), CallFuncN::create(CC_CALLBACK_1(GameLayer::fallingObjectDone, this)), NULL); health->setVisible ( true ); health->runAction((Action *)_swingHealth); health->runAction(sequence); _fallingObjects.pushBack(health); } void GameLayer::pushMeteor(Ref* sender) { auto sprite = (Sprite*)sender; _gameBatchNode->removeChild(sprite, true); _meteorPool.pushBack(sprite); } void GameLayer::resetMeteor() { if(_fallingObjects.size()>30)return; auto meteor = _meteorPool.front(); _meteorPool.eraseObject(meteor); int meteor_x = rand()%(int)(winSize.width*0.8f)+winSize.width*0.1f; int meteor_target_x = rand()%(int)(winSize.width*0.8f)+winSize.width*0.1f; meteor->stopAllActions(); meteor->setPosition(Point(meteor_x,winSize.height+meteor->getContentSize().height *0.5)); ActionInterval* rotate = RotateBy::create(0.5f, -90); Action * repeatRotate = RepeatForever::create(rotate); FiniteTimeAction* sequence = Sequence::create(MoveTo::create(_meteorSpeed,Point(meteor_target_x,winSize.height*0.15f)),CallFuncN::create(CC_CALLBACK_1(GameLayer::fallingObjectDone, this)),NULL); meteor->setVisible(true); meteor->runAction(repeatRotate); meteor->runAction(sequence); _fallingObjects.pushBack(meteor); } void GameLayer::increaseDifficulty() { _meteorInterval -= 0.2f; if (_meteorInterval < 0.25f) _meteorInterval = 0.25f; _meteorSpeed -= 1; if (_meteorSpeed < 4) _meteorSpeed = 4; _healthSpeed -= 1; if (_healthSpeed < 8) _healthSpeed = 8; } |
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 | #ifndef __GAMELAYER_H__ #define __GAMELAYER_H__ #include "cocos2d.h" USING_NS_CC; #define BATCH_TAG 111 class GameLayer : public cocos2d::Layer { public: // there's no 'id' in cpp, so we recommend returning the class instance pointer static cocos2d::Scene* createScene(); // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone virtual bool init(); // a selector callback void menuCloseCallback(cocos2d::Ref* pSender); // implement the "static create()" method manually CREATE_FUNC(GameLayer); Size winSize = Director::getInstance()->getVisibleSize(); enum{ kBackground, kMiddleground, kForeground }; enum { kSpriteBomb, kSpriteShockwave, kSpriteMeteor, kSpriteHealth, kSpriteHalo, kSpriteSparkle }; Vector<Sprite*> _meteorPool; int _meteorPoolIndex; Vector<Sprite*> _healthPool; int _healthPoolIndex; Vector<Sprite*> _fallingObjects; Vector<Sprite*> _clouds; SpriteBatchNode * _gameBatchNode; Sprite * _bomb; Sprite * _shockWave; Sprite * _introMessage; Sprite * _gameOverMessage; LabelBMFont * _energyDisplay; LabelBMFont * _scoreDisplay; Action * _growBomb; Action * _rotateSprite; //Action * _shockwaveSequence; Action * _swingHealth; Action * _groundHit; Action * _explosion; Action * _explosion1; Size _screenSize; float _meteorInterval; float _meteorTimer; float _meteorSpeed; float _healthInterval; float _healthTimer; float _healthSpeed; float _difficultyInterval; float _difficultyTimer; int _energy; int _score; int _shockwaveHits; bool _running; void resetMeteor(void); void resetHealth(void); void resetGame(void); void stopGame(void); void increaseDifficulty(void); void initBS(); void createGameScreen (void); void createPools(void); void createActions(void); void fallingObjectDone(Ref* pSender); void animationDone(Ref* pSender); void shockwaveDone(); void pushMeteor(Ref* sender); void resetSpr(Ref* sender); void removeEx(Ref* sender); virtual void onTouchesBegan(const std::vector<Touch*>&touches, Event *unused_event); virtual void update (float dt); }; #endif // __HELLOWORLD_SCENE_H__ |
헤더파일과 씨쁠쁠파일입니다.
멀티터치가 구연되있고 가로모드이기 때문에 AppController.mm과 RootViewController.mm에서 설정을 해주셔야 합니다.
코드를 보시면 책에있는 코드와 비슷한 부분도 있고 완전 다른 부분도 있습니다.
일단 Array를 쓰지않고 전부 Vector를 사용했습니다.
일단 떨어지는 유성 코드를 분석해 보면서 벡터가 어떻게 사용되었는지 알아보도록 합니다.
1. 벡터의 사용 |
2.x 에서 Array를 사용했다면, 3.x에서는 벡터의 사용을 권고하고 있습니다.
이 게임에서 벡터는 유성과 헬스, 그리고 떨어지는 중인 물체에 대해 3가지 벡터를 가지고 있습니다.
벡터의 선언은 헤더파일에서 다음과 같이 선언합니다.
Vector<Sprite*> _meteorPool;
유성이나 헬스 등이 스프라이트이기 때문에 스프라이트형 벡터로 선언합니다. 벡터를 사용할때는 항상 초기화를 해주어야 합니다. init() 메소드에 보면 clear메소드가 보일겁니다.
_meteorPool.clear();
또 벡터에서 입력하는 것은 pushback()메소드를 사용하고 지울때는 eraseObject(Object)를 사용합니다.
for(i=0;i<50;i++){
sprite = Sprite::createWithSpriteFrameName("meteor.png");
sprite->setVisible(false);
_gameBatchNode->addChild(sprite,kMiddleground,kSpriteMeteor);
_meteorPool.pushBack(sprite);
}
createPool메소드 안에 위와같은 코드가 있습니다. for문을 사용해서 50개의 유성을 유성벡터안에 집어넣는 과정입니다. 보시면 스프라이트를 만들고 pushBack을 이용해 벡터에 넣는 것을 알 수 있습니다.
이렇게 무작정 pushBack을 했는데 어떻게 각가 유성들을 관리할지 걱정이 됬었는데 아주 간단히 해결됬습니다. 사스가 객체지향..
일단 벡터안에서 객체를 꺼낼때는 front를 사용합니다. 그럼 벡터 제일 앞에있는 객체가 튀어나오죠.
1 2 | auto meteor = _meteorPool.front(); _meteorPool.eraseObject(meteor); |
그리고 나온 객체를 벡터에서 제거합니다. 이렇게하면 벡터안에있는 객체들이 겹치지 않고 하나씩 꺼낼 수 있습니다. 이건 제가 생각한 방법이라 더 좋은 방법이 있을지도 모릅니다 ^^;;
이렇게 꺼낸 객체를 폭탄이 폭파시키거나 땅에 떨어지면 다시 본래의 백터에 pushBack을 통해 집어넣으면 됩니다.
2. 애니메이션에 관해. |
하... 이거 때문에 정말 4시간정도 코드를 고쳤습니다.
문제가 뭐냐면 책에 있는대로 애니메이션을 구현했더니 폭탄이 동시에 두개의 혜성을 터트릴때 하나의 혜성이 폭팔하는 그림으로 멈추고, 다른 혜성들이 폭팔하는 모양으로 떨어지는 문제가 발생했습니다.
어디가 문제인지 찾으려고 모든 코드를 건드려보다가 애니메이션 부분을 수정했더니 해결됬습니다.
문제인 부분은 createAction메소드 안에서 여러가지 애니메이션과 액션을 정의하고, 애니메이션이 필요할 때 그 메소드를 불러서 사용하는 방식입니다. 하지만 동시에 하나의 애니메이션을 호출할 경우 먼저 실행되었던 애니메이션이 멈추기 때문에 애니메이션을 아에 필요할때마다 생성하도록 만드는 방식으로 수정했습니다.
즉 createAction에 선언되었던 애니메이션 액션들을 사용되는 시점에서 선언하는 것입니다.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | auto animation = Animation::create(); animation->setDelayPerUnit(0.1); for (int i=1; i<=10; i++) { auto frame = SpriteFrameCache::getInstance()->getSpriteFrameByName(StringUtils::format("boom%i.png",i)); animation->addSpriteFrame(frame); } animation->setRestoreOriginalFrame(true); _groundHit =Sequence::create(MoveBy::create(0, Point(0,winSize.height*0.12f)), Animate::create(animation), CallFuncN::create(CC_CALLBACK_1(GameLayer::animationDone, this)), NULL); sSprite->runAction((Action*)_groundHit); //play explosion sound SimpleAudioEngine::getInstance()->playEffect("boom.wav"); |
위 코드는 유성이 땅바닥에 도착했을때 터지는 애니메이션을 구현한 코드입니다. 본래 책에는 _groundHit가 createAction에서 만든 것을 사용했지만, 여기서는 바로 만들어서 바로 사용합니다.
저는 프레임 만드는 것과 액션 설정까지 전부 할 필요는 없고 프레임 설정하는 건 따른 메소드에서 하고 액션 만들때만 불러오면 될 것 같은데.. 귀찮아서 그냥 한번에 넣었습니다. 이렇게 되면 프로그램상 부하가 좀 있지 않을까 생각되지만요 ^^....
아무튼 이렇게 해서 문제를 해결했습니다.
하.. 게임이 돌아가니까 뭔가 기분좋긴한데 2.x버전을 3.x버전으로 바꾸기가 엄청 힘드네요.
3가지 예제가 남았지만... 그냥 제가 만들고자 하는 게임을 만드는게 나을 것 같다고 판단해서...
이 책에 예제는 여기까지 하겠습니다 ^^....
'Study > Cocos2d-x 3.x' 카테고리의 다른 글
[cocos2d-x 3.6] 포코팡류 게임 만들기~! (2) | 2015.05.31 |
---|---|
cocos2d-x 3.2 가상패드 만들기( 가상조이스틱, dpad, sneakyinput, virtual pad) (9) | 2014.09.02 |
5가지 실전 게임으로 배우는 코코스2d-x(cocos2d-x) 모바일 2D 게임 개발 두번째 예제(3) (0) | 2014.08.28 |
5가지 실전 게임으로 배우는 코코스2d-x(cocos2d-x) 모바일 2D 게임 개발 두번째 예제(2) (2) | 2014.08.26 |
5가지 실전 게임으로 배우는 코코스2d-x(cocos2d-x) 모바일 2D 게임 개발 두번째 예제(1) (0) | 2014.08.22 |