接《基於Cocos2d-x-1.0.1的飛機大戰游戲開發實例(上)》
三、代碼分析
1.界面初始化
1 bool PlaneWarGame::init()
2 {
3 bool bRet = false;
4 do
5 {
6 CC_BREAK_IF(! CCLayer::init());
7
8 _size = CCDirector::sharedDirector()->getWinSize();
9
10 // 設置觸摸可用
11 this->setIsTouchEnabled(true);
12 // 從窗口中取消息
13 CCDirector::sharedDirector()->getOpenGLView()->SetWin32KeyLayer( this );
14
15 // 初始化游戲背景
16 CC_BREAK_IF(!initBackground());
17 // 菜單1(暫停/聲音/炸彈)
18 CC_BREAK_IF(!initMenu1());
19 // 菜單2(繼續/重新開始/返回)
20 CC_BREAK_IF(!initMenu2());
21 // 菜單3(重新開始/返回)
22 CC_BREAK_IF(!initMenu3());
23
24 // 創建玩家飛機
25 _player = new PlaySprite;
26 _player->setPosition(CCPointZero);
27 addChild(_player);
28
29 // 調度器:定時調用自定義的回掃函數
30 this->schedule( schedule_selector(PlaneWarGame::gameLoop));
31 this->schedule( schedule_selector(PlaneWarGame::shoot), 0.1 );
32 this->schedule( schedule_selector(PlaneWarGame::addEnemy), 0.3 );
33 this->schedule( schedule_selector(PlaneWarGame::addProp), 5 );
34
35 // 初始化兩個數組
36 _enemys = CCArray::array();
37 _enemys->retain();
38 _bullets = CCArray::array();
39 _bullets->retain();
40
41 // 背景音樂
42 CocosDenshion::SimpleAudioEngine::sharedEngine()->playBackgroundMusic(
43 "planewar/game_music.wav", true);
44
45 bRet = true;
46 } while (0);
47
48 return bRet;
49 }
初始化的工作包括:
2.初始化游戲背景
1 bool PlaneWarGame::initBackground()
2 {
3 // 顯示分數
4 _label = CCLabelBMFont::labelWithString("0123456789","planewar/font.fnt");
5 _label->setPosition(ccp(220,_size.height-20));
6 _label->setColor(ccc3(0,0,0));
7 this->addChild(_label, 1);
8
9 // 顯示炸彈數量
10 CCLabelBMFont* bombcount = CCLabelBMFont::labelWithString("X09","planewar/font.fnt");
11 bombcount->setAnchorPoint(ccp(0,0));
12 bombcount->setPosition(ccp(73,10));
13 bombcount->setColor(ccc3(0,0,0));
14 addChild(bombcount, 10,111);
15
16 // 添加背景
17 CCSprite* bg1 = CCSprite::spriteWithFile("planewar/bg1.png");
18 if (!bg1)return false;
19 bg1->setAnchorPoint(ccp(0,1));
20 bg1->setPosition( ccp(0, _size.height) );
21 this->addChild(bg1, 0, 11);
22
23 bg1->runAction(
24 CCSequence::actions(
25 CCMoveBy::actionWithDuration(10,ccp(0,-720)),
26 CCCallFunc::actionWithTarget(this, callfunc_selector(PlaneWarGame::bg1roll)),NULL));
27
28 CCSprite* bg2 = CCSprite::spriteWithFile("planewar/bg2.png");
29 if (!bg1)return false;
30 bg2->setAnchorPoint(ccp(0,1));
31 bg2->setPosition( ccp(0, _size.height*2) );
32 this->addChild(bg2, 0, 12);
33
34 bg2->runAction(
35 CCSequence::actions(
36 CCMoveBy::actionWithDuration(20,ccp(0,-1440)),
37 CCCallFunc::actionWithTarget(this, callfunc_selector(PlaneWarGame::bg2roll)),NULL));
38 return true;
39 }
40
41 void PlaneWarGame::bg1roll(){
42 //運動出屏幕重設位置,運動
43 CCSprite * bg = (CCSprite *)getChildByTag(11);
44 bg->setPosition(ccp(0,1440));
45 CCAction* seq = CCSequence::actions(
46 CCMoveBy::actionWithDuration(20,ccp(0,-1440)),
47 CCCallFunc::actionWithTarget(this, callfunc_selector(PlaneWarGame::bg1roll)),NULL);
48 bg->runAction(seq);
49 }
50
51 void PlaneWarGame::bg2roll(){
52 //運動出屏幕重設位置,運動
53 CCSprite * bg = (CCSprite *)getChildByTag(12);
54 bg->setPosition(ccp(0,1440));
55 CCAction* seq = CCSequence::actions(
56 CCMoveBy::actionWithDuration(20,ccp(0,-1440)),
57 CCCallFunc::actionWithTarget(this, callfunc_selector(PlaneWarGame::bg2roll)),NULL);
58 bg->runAction(seq);
59 }
初始化游戲背景時,需要注意的是:要做出飛機向上走的視覺效果,就要把背景向下滾動,這裡使用兩個背景bg1和bg2,大小分別為屏幕大小。初始bg1在屏幕內,bg2在屏幕上方,兩個同事向下運動;當bg1剛剛運動到屏幕外,bg2剛好蓋住屏幕,bg1挪到屏幕上方向下運動...循環操作,就能做出循環滾動的背景效果了。
3.子彈的處理
1 // 確定子彈類型
2 void PlaneWarGame::shoot(float dt)
3 {
4 if (_isOver)return;
5 if(_player==NULL) return;
6
7 if(_player->_bulletKind == BK_SINGLE)
8 {
9 CCSprite *bullet = CCSprite::spriteWithFile(
10 "planewar/plane.png", CCRectMake(112,2,9,17));
11 addBullet(bullet,_player->getPlayerPt());
12 }else if (_player->_bulletKind == BK_DOUBLE)
13 {
14 CCSprite *bullet = CCSprite::spriteWithFile(
15 "planewar/plane.png", CCRectMake(66,238,8,15));
16 addBullet(bullet,ccp(_player->getPlayerPt().x-20,_player->getPlayerPt().y));
17 CCSprite *bullet1 = CCSprite::spriteWithFile(
18 "planewar/plane.png", CCRectMake(66,238,8,15));
19 addBullet(bullet1,ccp(_player->getPlayerPt().x+20,_player->getPlayerPt().y));
20 }
21 }
22 // 添加子彈
23 void PlaneWarGame::addBullet(CCSprite* bullet, CCPoint pt)
24 {
25 bullet->setPosition(pt);
26 this->addChild(bullet);
27
28 bullet->runAction( CCSequence::actions(
29 CCMoveTo::actionWithDuration(0.5, ccp(pt.x,_size.height+bullet->getContentSize().height/2)),
30 CCCallFuncN::actionWithTarget(this,callfuncN_selector(PlaneWarGame::spriteMoveFinished)),
31 NULL) );
32
33 bullet->setTag(1);
34 _bullets->addObject(bullet);
35 }
36 // 回收
37 void PlaneWarGame::spriteMoveFinished(CCNode* sender)
38 {
39 CCSprite *sprite = (CCSprite *)sender;
40 this->removeChild(sprite, true);
41 if (sprite->getTag()==1)//子彈
42 _bullets->removeObject(sprite);
43 }
吃道具可改變子彈類型。子彈的回收方式:從飛機坐標處出發,運動到屏幕外被回收。道具的處理類似。
4.設置觸摸/鼠標點擊控制玩家角色的移動
1 bool PlaneWarGame::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent)
2 {
3 if(_player==NULL) return false;
4
5 CCPoint pt = CCDirector::sharedDirector()->convertToGL(
6 pTouch->locationInView(pTouch->view()));
7
8 CCRect rt = _player->getRect();
9 if (CCRect::CCRectContainsPoint(rt,pt))
10 _player->_isDragEnabled = true;
11 return true;
12 }
13
14 void PlaneWarGame::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent)
15 {
16 if(_player==NULL) return;
17
18 CCSize size = CCDirector::sharedDirector()->getWinSize();
19 CCPoint pt = CCDirector::sharedDirector()->convertToGL(
20 pTouch->locationInView(pTouch->view()));
21
22 CCRect rt = CCRect(0,0,size.width,size.height);
23
24 if (_player->_isDragEnabled && CCRect::CCRectContainsPoint(rt,pt))
25 _player->setPlayerPt(pt);
26 }
27
28 void PlaneWarGame::ccTouchEnded(CCTouch *pTouch, CCEvent *pEvent)
29 {
30 _player->_isDragEnabled = false;
31 }
這裡重寫3個虛函數。移動角色的方式:觸摸/鼠標按下時,如果點擊位置在角色上,將角色可被拖拽狀態置為true;觸摸/鼠標移動時,根據角色的可被拖拽狀態和屏幕范圍確定是否移動;觸摸/鼠標彈起時,將角色的可被拖拽狀態恢復為false。
5.碰撞檢測
1 void PlaneWarGame::updateGame(float dt)
2 {
3 CCArray *bulletsToDelete = CCArray::array();
4 CCObject* it = NULL;
5 CCObject* jt = NULL;
6
7 if(_player==NULL) return;
8
9 CCRect playerRect = _player->getRect();
10 // 己方飛機和敵方飛機的碰撞
11 CCARRAY_FOREACH(_enemys, jt)
12 {
13 EnemySprite *enemy = dynamic_cast<EnemySprite*>(jt);
14 if (!enemy->isNull() && CCRect::CCRectIntersectsRect(playerRect, enemy->getRect()))
15 {
16 _player->die();
17 gameover(false);
18 return;
19 }
20 }
21
22 //////////////////////////////////////////////////////////////////////////
23 // 道具和角色的碰撞檢測
24 CCSprite* prop = (CCSprite*)getChildByTag(8);//子彈
25 if (NULL != prop)
26 {
27 CCRect propRect = CCRectMake(
28 prop->getPosition().x - (prop->getContentSize().width/2),
29 prop->getPosition().y - (prop->getContentSize().height/2),
30 prop->getContentSize().width,
31 prop->getContentSize().height);
32 if (CCRect::CCRectIntersectsRect(playerRect, propRect))
33 {
34 _player->_bulletKind = BK_DOUBLE;
35 removeChild(prop,true);
36 CocosDenshion::SimpleAudioEngine::sharedEngine()->
37 playEffect("planewar/get_double_laser.wav",false);
38 }
39 }
40 CCSprite* prop1 = (CCSprite*)getChildByTag(9);//炸彈
41 if (NULL != prop1)
42 {
43 CCRect prop1Rect = CCRectMake(
44 prop1->getPosition().x - (prop1->getContentSize().width/2),
45 prop1->getPosition().y - (prop1->getContentSize().height/2),
46 prop1->getContentSize().width,
47 prop1->getContentSize().height);
48 if (CCRect::CCRectIntersectsRect(playerRect, prop1Rect))
49 {
50 _player->_bombCount++;
51 removeChild(prop1,true);
52 CocosDenshion::SimpleAudioEngine::sharedEngine()->
53 playEffect("planewar/get_bomb.wav",false);
54 }
55 }
56
57 //////////////////////////////////////////////////////////////////////////
58 // 子彈和敵機的碰撞檢測
59 CCARRAY_FOREACH(_bullets, it)
60 for (int i=0; i<_bullets->count(); i++)
61 {
62 CCSprite *bullet = dynamic_cast<CCSprite*>(_bullets->objectAtIndex(i));
63 CCRect bulletRect = CCRectMake(
64 bullet->getPosition().x - (bullet->getContentSize().width/2),
65 bullet->getPosition().y - (bullet->getContentSize().height/2),
66 bullet->getContentSize().width,
67 bullet->getContentSize().height);
68
69 CCArray* enemysToDelete =CCArray::array();
70
71 CCARRAY_FOREACH(_enemys, jt)
72 {
73 EnemySprite *enemy = dynamic_cast<EnemySprite*>(jt);
74 if (!enemy->_die && CCRect::CCRectIntersectsRect(bulletRect, enemy->getRect()))
75 {
76 if (enemy->_hp>0)
77 {
78 enemy->_hp--;
79 //bulletsToDelete->addObject(bullet);
80 _bullets->removeObject(bullet);
81 removeChild(bullet,true);
82 }
83 else if (enemy->_hp<=0)
84 {
85 //bulletsToDelete->addObject(bullet);
86 _bullets->removeObject(bullet);
87 removeChild(bullet,true);
88 enemysToDelete->addObject(enemy);
89 }
90 }
91 }
92
93 CCARRAY_FOREACH(enemysToDelete, jt)
94 {
95 EnemySprite *enemy = dynamic_cast<EnemySprite*>(jt);
96 enemy->_die = true;
97 enemy->die();
98 _bulletsDestroyed++;
99 }
100
101 enemysToDelete->release();
102 }
103
104 // 釋放已死亡的子彈
105 CCARRAY_FOREACH(bulletsToDelete, it)
106 {
107 CCSprite* projectile = dynamic_cast<CCSprite*>(it);
108 _bullets->removeObject(projectile);
109 this->removeChild(projectile, true);
110 }
111 bulletsToDelete->release();
112 }
碰撞檢測使用最簡單的矩形檢測。
6.玩家角色的添加和操作
1 void PlaySprite::onEnter()
2 {
3 CCNode::onEnter();
4
5 CCSize size = CCDirector::sharedDirector()->getWinSize();
6 _sprite = CCSprite::spriteWithFile("planewar/hero1.png");
7 _sprite->setContentSize(CCSize(62,68));
8 _sprite->setPosition( ccp(size.width/2,_sprite->getContentSize().height/2) );
9 addChild(_sprite,10);
10
11 CCAnimation * animation = CCAnimation::animation();
12 animation->addFrameWithFileName("planewar/hero1.png");
13 animation->addFrameWithFileName("planewar/hero2.png");
14 CCAction* action = CCRepeatForever::actionWithAction(
15 CCAnimate::actionWithDuration(0.1f, animation, false));
16 action->setTag(11);
17 _sprite->runAction(action);
18
19 // 調度器
20 schedule( schedule_selector(PlaySprite::move), 0.002 );
21 }
22
23 CCRect PlaySprite::getRect()
24 {
25 if (_sprite!=NULL)
26 return CCRect(
27 _sprite->getPosition().x - (_sprite->getContentSize().width/2),
28 _sprite->getPosition().y - (_sprite->getContentSize().height/2),
29 _sprite->getContentSize().width,
30 _sprite->getContentSize().height);
31 }
32
33 CCPoint PlaySprite::getPlayerPt()
34 {
35 if (_sprite!=NULL)
36 return _sprite->getPosition();
37 }
38
39 void PlaySprite::setPlayerPt(CCPoint pt)
40 {
41 if (_sprite!=NULL)
42 return _sprite->setPosition(pt);
43 }
44
45 void PlaySprite::setMoveMode( UINT message, WPARAM wParam)
46 {
47 if (message == WM_KEYDOWN)
48 {// 控制飛機移動
49 if (wParam == VK_UP)
50 _mode = MM_UP;
51 else if (wParam == VK_DOWN)
52 _mode = MM_DOWN;
53 else if (wParam == VK_LEFT)
54 _mode = MM_LEFT;
55 else if (wParam == VK_RIGHT)
56 _mode = MM_RIGHT;
57 }else if (message == WM_KEYUP)
58 {
59 if (wParam == VK_UP || wParam == VK_DOWN ||wParam == VK_LEFT||wParam == VK_RIGHT)
60 _mode = MM_NONE;
61 }
62 }
63
64 void PlaySprite::move(float dt)
65 {
66 CCSize winSize = CCDirector::sharedDirector()->getWinSize();
67
68 switch(_mode)
69 {
70 case MM_NONE:
71 break;
72 case MM_UP:
73 if (getPlayerPt().y<winSize.height)
74 setPlayerPt(ccp(getPlayerPt().x,getPlayerPt().y+1));
75 break;
76 case MM_DOWN:
77 if (getPlayerPt().y>0)
78 setPlayerPt(ccp(getPlayerPt().x,getPlayerPt().y-1));
79 break;
80 case MM_LEFT:
81 if (getPlayerPt().x>0)
82 setPlayerPt(ccp(getPlayerPt().x-1,getPlayerPt().y));
83 break;
84 case MM_RIGHT:
85 if (getPlayerPt().x<winSize.width)
86 setPlayerPt(ccp(getPlayerPt().x+1,getPlayerPt().y));
87 break;
88 }
89 }
90
91 void PlaySprite::die()
92 {
93 if (_sprite==NULL)return;
94
95 _sprite->stopActionByTag(11);
96 CCAnimation * animation = CCAnimation::animation();
97 animation->addFrameWithFileName("planewar/hero_blowup_n1.png");
98 animation->addFrameWithFileName("planewar/hero_blowup_n2.png");
99 animation->addFrameWithFileName("planewar/hero_blowup_n3.png");
100 animation->addFrameWithFileName("planewar/hero_blowup_n4.png");
101 _sprite->runAction(CCSequence::actions(
102 CCAnimate::actionWithDuration(0.1f, animation, false),
103 CCCallFunc::actionWithTarget(this, callfunc_selector(PlaySprite::destroy)),NULL));
104 }
105
106 void PlaySprite::destroy()
107 {
108 if (_sprite==NULL)return;
109
110 removeChild(_sprite,true);
111 _sprite = NULL;
112 }
四、完成效果圖
經過不到一周的時間,從什麼都沒有,到游戲正常運行、功能完整,體會了cocos2dx的調用機制。
下面是運行效果圖:





如果實現中有什麼問題,歡迎大家在評論中指教!