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