1. 程式人生 > >Cocos2d-x 3.x學習筆記:猩先生帶你打飛機(四)遊戲場景:背景與我機的建立、敵機的建立、物理世界構建

Cocos2d-x 3.x學習筆記:猩先生帶你打飛機(四)遊戲場景:背景與我機的建立、敵機的建立、物理世界構建

一、背景與我機的建立
現在我們要建立新的一個場景了。選擇開始遊戲即從選單場景跳到遊戲場景。現在先完善HelloWorldScene的程式碼
找到我們開始遊戲的回撥方法,新增程式碼:

//開始遊戲
void HelloWorld::menuStartCallback(Ref* pSender)
{
     auto scene = GameScene::createScene();                //這個場景類理應先建立好的。為了線性介紹只能這樣了。
     auto gameScene = TransitionSlideInR::create(1.0f,scene);
     Director::getInstance
()->replaceScene(gameScene); }

然後建立新的一個場景GameScene相關的GameScene.h和GameScene.cpp,裡面的程式碼參照HelloWorldScene的格式。注意:建立的程式碼檔案一定要放到classes下面,否則會出錯。
然後在GameScene的建立場景的方法中,新增如下程式碼

Scene* GameScene::createScene()
{
 auto scene = Scene::createWithPhysics();         //建立物理世界的場景
 //PhysicsWorld* phyWorld = scene->getPhysicsWorld();            //測試專用,如果釋出就註釋掉就好了。
//phyWorld->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL); auto layer = GameScene::create(); scene->addChild(layer); return scene; }

這樣我們的物理世界場景就建立好了。下面就新增各種精靈。
上一節也講過怎麼設定滾動背景和飛機的建立了就不多說,只是這次新增的飛機的物理世界的實體。
在GameScene的Init方法中新增如下程式碼。

auto plane = Sprite::create("hero1.png");
 plane->
setPosition(visibleSize.width/2+origin.x,200); plane->setTag(103); //設定物理世界實體 //這裡只有我機、敵機、子彈,子彈和敵機可以碰撞,敵機和我機可以碰撞,我機和子彈不可以碰撞 auto planeBody = PhysicsBody::createBox(plane->getContentSize()); planeBody->setContactTestBitmask(0x0003); //碰撞測試掩碼 planeBody->setCategoryBitmask(0x0001); //類別掩碼 planeBody->setCollisionBitmask(0x0007); //碰撞掩碼 planeBody->setGravityEnable(false); //設定重力無效,飛機是在天空中的,別讓他掉下來。 plane->setPhysicsBody(planeBody); this->addChild(plane); //啟動飛機動畫 Animation * animation = Animation::create(); SpriteFrame * spriteFrame1 = SpriteFrame::create("hero1.png",Rect(0,0,102,126)); //優化可以用 SpriteFrameCache用法查Api SpriteFrame * spriteFrame2 = SpriteFrame::create("hero2.png",Rect(0,0,102,126)); animation->addSpriteFrame(spriteFrame1); animation->addSpriteFrame(spriteFrame2); animation->setDelayPerUnit(0.15f); Animate * animate = Animate::create(animation); plane->runAction(RepeatForever::create(animate)); //執行動畫

現在飛機還是靜止的,那麼根據我們的遊戲邏輯,飛機應該是隨著我們的手上下動而動(我聽起來怎麼這麼黃這麼暴力呢)。
那麼我們給他新增一個觸屏監聽事件來控制飛機的移動。
首先在GameScene.h檔案中的public下新增如下程式碼:

int status;         //遊戲狀態  1為正常、2為暫停、3為結束
float fx,fy;        //用來記錄手指點選的開始位置
//觸屏事件 ,由系統監聽
 virtual bool onTouchBegan(cocos2d::Touch * touch, cocos2d::Event * event);             //手指首次點選
 virtual void onTouchMoved(cocos2d::Touch * touch, cocos2d::Event * event);             //手指移動
然後註冊監聽器,在GameScene的init方法中新增
//觸控事件註冊,要通過回撥函式來控制飛機的座標
 setTouchEnabled(true);
 //設定為單點觸碰
 setTouchMode(Touch::DispatchMode::ONE_BY_ONE);
然後實現觸屏反應函式
//手指點選下時,記錄該點的位置,該點為起點
bool GameScene::onTouchBegan(Touch * touch, Event * event)
{
 if(status == 1)
 {
  fx=touch->getLocation().x;
  fy=touch->getLocation().y;
 }
 return true;
}

//每次移動把移動的位置(終點)記錄下來,並與之前記錄下的位置相減,得到飛機該位移的相對量(x、y軸移動多少),並重新整理起點位置

void GameScene::onTouchMoved(Touch * touch, Event * event)
{
 if(status == 1)
 {
  int mx=(touch->getLocation().x-fx);
  int my=(touch->getLocation().y-fy);
  auto spPlane=this->getChildByTag(103);
  spPlane->runAction(MoveBy::create(0,Point(mx,my)));
  fx=touch->getLocation().x;
  fy=touch->getLocation().y;
 }
}

現在你可以編譯執行下,看看效果了。
這裡寫圖片描述
看到飛機飛來飛去,好想射點什麼。好,下面新增飛機發射子彈的相關程式碼,激動的地方。
實現發射子彈,只需要使用一個定時器,讓他每隔一段時間,就呼叫一個函式,在飛機的位置建立一個子彈精靈,並且宣告個Vector儲存所有的子彈,然後再建立一個定時器讓所有的子彈每隔一段時間向上移動,所有的子彈都儲存在Vector中,形成飛機發射子彈的現象。怎麼做的,看程式碼。
先在GameScene.h中宣告
//儲存所有的子彈

cocos2d::Vector<cocos2d::Sprite *> bulletList;
//子彈建立的定時器回撥函式
 void bulletCreate(float f);
 //讓子彈飛和讓敵機飛  因為敵機和子彈移動的速度一樣,不用建立多個定時器
 void objectMove(float f); 
然後在GameScene的init方法中設定兩個定時器。
//我機發射子彈
 this->schedule(schedule_selector(GameScene::bulletCreate),0.3);            //裡面的引數就是為什麼要建立多個定時器的原因。
 //讓子彈飛
 this->schedule(schedule_selector(GameScene::objectMove),0.01);            
最後實現定時器的回撥方法,看程式碼
//建立子彈
void GameScene::bulletCreate(float f)
{
 SimpleAudioEngine::getInstance()->playEffect("sounds/bullet.wav");
 auto plane=this->getChildByTag(103);
 Sprite * bullet=Sprite::create("bullet.png");
 bullet->setPosition(plane->getPosition().x,plane->getPosition().y+60);
 bullet->setTag(106);
 auto bulletBody = PhysicsBody::createBox(bullet->getContentSize());
 bulletBody->setContactTestBitmask(0x0002);
 bulletBody->setCategoryBitmask(0x0005);
 bulletBody->setCollisionBitmask(0x0002);
 bulletBody->setGravityEnable(false);
 bullet->setPhysicsBody(bulletBody);
 this->addChild(bullet);
 this->bulletList.pushBack(bullet);
}
//讓子彈飛
void GameScene::objectMove(float f)
{
 //遍歷vector取出所有的子彈,讓子彈的位置往上移,水往低處流,子彈向上飛嘛
 for(int i = 0; i < bulletList.size() ; i++)
 {
  auto bullet = bulletList.at(i);
  bullet->setPositionY(bullet->getPositionY()+3);
  //如果該子彈已經超出螢幕範圍,則移除它
  if(bullet->getPositionY()>Director::getInstance()->getWinSize().height)
  {
   bullet->removeFromParent(); //從層中移除
   bulletList.eraseObject(bullet);//從記錄所有子彈的vector中移除
   //移除後上一個物件會移到當前這個物件的位置,實際還是當前這個i,所以要i--才能訪問到下一個物件
   i--;
  }
 }
 //取出所有的敵機,讓敵機往下移動
 for(int i = 0; i < enemyList.size() ; i++)
 {
  auto enemy = enemyList.at(i);
  enemy->setPositionY(enemy->getPositionY()-5);
  //如果該子彈已經超出螢幕範圍,則移除它
  if(enemy->getPositionY() < -enemy->getContentSize().height)
  {
   enemy->removeFromParent(); //從層中移除
   enemyList.eraseObject(enemy);//從記錄所有子彈的vector中移除
   //移除後上一個物件會移到當前這個物件的位置,實際還是當前這個i,所以要i--才能訪問到下一個物件
   i--;
  }
 }
}

我們的飛機就可以可以發射子彈了。
這裡寫圖片描述

二、敵機的建立
敵機的建立也很簡單,類似子彈的做法,但是區別就在於敵機的位置是隨機在螢幕最上方隨機生成。看程式碼。
先在GameScene.h宣告。函式和變數的宣告都在標頭檔案中,後面就不講那麼具體。

//用來儲存所有的敵機
cocos2d::Vector<cocos2d::Sprite *> enemyList;
//建立敵機
 void enemyCreate(float f);  
在建立一個定時器
//敵機建立
 this->schedule(schedule_selector(GameScene::enemyCreate),0.5);
實現我們的建立函式
//敵機建立
void GameScene::enemyCreate(float f)
{
 //隨機出現敵機1或敵機2
 int ranDom = rand()%2+1;
 auto string = cocos2d::__String::createWithFormat("enemy%d.png",ranDom);
 auto enemy = Sprite::create(string->getCString());
 if(ranDom == 1)
 {
  enemy->setTag(104);    //敵機的型別,由這個來判斷,用於分數計算
 }
 else
 {
  enemy->setTag(105);
 }

 enemy->setPosition(Vec2(rand()%(int)(Director::getInstance()->getVisibleSize().width),Director::getInstance()->getVisibleSize().height+enemy->getContentSize().height));    //隨機在螢幕最上方的出現敵機
 auto enemyBody = PhysicsBody::createBox(enemy->getContentSize());        //建立物理實體
 enemyBody->setContactTestBitmask(0x0003);
 enemyBody->setCategoryBitmask(0x0002);
 enemyBody->setCollisionBitmask(0x0001);
 enemyBody->setGravityEnable(false);
 enemy->setPhysicsBody(enemyBody);
 this->addChild(enemy);
 this->enemyList.pushBack(enemy);
}
建立好敵機後就是,嗨,敵機,走你。
因為敵機的飛行速度跟子彈的飛行速度是一樣的,所以只要在void GameScene::objectMove(float f)方法中新增以下程式碼就行了。 
//取出所有的敵機,讓敵機往下移動
 for(int i = 0; i < enemyList.size() ; i++)
 {
  auto enemy = enemyList.at(i);
  enemy->setPositionY(enemy->getPositionY()-5);
  //如果該子彈已經超出螢幕範圍,則移除它
  if(enemy->getPositionY() < -enemy->getContentSize().height)
  {
   enemy->removeFromParent();    //從層中移除
   enemyList.eraseObject(enemy);    //從記錄所有子彈的vector中移除
   //移除後上一個物件會移到當前這個物件的位置,實際還是當前這個i,所以要i--才能訪問到下一個物件
   i--;
  }
 }

然後,然後就沒然後了,這一節已經大功告成了。
看看執行效果,因為敵機我機是可以碰撞的,子彈和敵機是可以碰撞的,所以~~~所以就是你看的效果了。
這裡寫圖片描述
下一節我們將來充當爆破人員,爆爆爆,引爆一切碰撞。
原始碼下載:原始碼2