Cocos2d-x初學(xué)者教程

本文翻譯自https://www.raywenderlich.com/網(wǎng)站上Guanghui Qu寫(xiě)的2015年4月30號(hào)的一篇博文Cocos2d-x Tutorial for Beginners,他使用的Cocos2d-x的版本是 version 3.5。另外,關(guān)于在Windows10下使用Cocos2d-x 3.17.2構(gòu)建項(xiàng)目的,可以參考我之前寫(xiě)的博客:Win10+Python2.7.14+cocos2d-x-3.17.2+VS2017環(huán)境搭建

Cocos2d-x初學(xué)者教程

在此Cocos2d-x教程中揣苏,學(xué)習(xí)如何使用C ++為iOS健芭,Android等創(chuàng)建基本的跨平臺(tái)游戲废睦!
Guanghui Qu
2015年4月30日·文章(30分鐘)·初學(xué)者


Cocos2d-x

Cocos2d-x是一種快速坷虑,強(qiáng)大且易于使用的開(kāi)源2D游戲引擎。

它與Apple的Sprite Kit非常相似埂奈,但具有一個(gè)關(guān)鍵優(yōu)勢(shì)– Cocos2d-x是跨平臺(tái)的迄损。

這意味著您可以使用一組代碼來(lái)制作適用于iOS,Android账磺,Windows Phone芹敌,Mac OS X,Windows桌面和Linux的游戲垮抗。 對(duì)于獨(dú)立游戲開(kāi)發(fā)者來(lái)說(shuō)氏捞,這是意義巨大的!

在本教程中冒版,您將學(xué)習(xí)如何使用C ++在Cocos2d-x中創(chuàng)建一個(gè)簡(jiǎn)單的2D游戲液茎。 是的-會(huì)有忍者! :]

**注意:本教程假定您了解C ++開(kāi)發(fā)的基礎(chǔ)知識(shí)。 如果您不熟悉C ++捆等,請(qǐng)務(wù)必先閱讀有關(guān)該主題的書(shū)滞造。**

入門(mén)

www.cocos2d-x.org/download下載最新版本的Cocos2d-x; 本教程使用3.5版栋烤。

將下載的文件放在您要存儲(chǔ)Cocos2d-x安裝的位置谒养,例如在主目錄中,然后將其解壓縮明郭。

打開(kāi)終端cd到剛解壓縮的文件夾中买窟。 例如,如果將項(xiàng)目放置在主目錄中薯定,請(qǐng)運(yùn)行以下命令:

cd ~/cocos2d-x-3.5/

現(xiàn)在運(yùn)行以下命令:

python setup.py

這將設(shè)置必要的Shell環(huán)境變量始绍。 當(dāng)它提示您配置特定于Android的變量NDK_ROOTANDROID_SDK_ROOTANT_ROOT時(shí)沉唠,只需按3次Enter回車(chē)鍵即可完成配置疆虚。

注意:Cocos2D需要在您的機(jī)器上安裝Python 2.7+。 如果不確定所用的Python版本满葛,請(qǐng)?jiān)诿钚猩湘I入python径簿,它將顯示該版本(然后按Ctrl-D退出)。 如果您使用的是Python的舊版本嘀韧,請(qǐng)?jiān)?a target="_blank">python.org上安裝最新版本的Python篇亭。

如下面的屏幕截圖所示,該腳本指示您執(zhí)行另一個(gè)命令以完成設(shè)置:

cocos2d-x-3.5

注意:根據(jù)您使用的shell锄贷,您可能會(huì)看到一些不同的輸出译蒂。 在上面的屏幕截圖中,安裝程序包提示輸入“ source / Users / rwenderlich / bash_profile”命令谊却,因?yàn)槲沂褂玫氖荁ash柔昼,但例如如果我一直使用Zsh,它會(huì)提示我運(yùn)行“ source /Users/rwenderlich/.zshrc”炎辨。

按照腳本的輸出說(shuō)明輸入命令捕透。 節(jié)省時(shí)間的秘訣:您可以使用代字號(hào)(?)代替/ Users / your_user_name,因此要保存擊鍵碴萧,可以鍵入以下內(nèi)容:

source ~/.zshrc  (or source ~/.bash_profile)

您輸入的命令只是重新處理您的shell配置乙嘀,并使其可以訪問(wèn)新變量。 現(xiàn)在破喻,您可以從任何目錄在終端中調(diào)用cocos命令虎谢。

運(yùn)行以下命令以創(chuàng)建一個(gè)名為SimpleGame的C ++游戲模板:

cocos new -l cpp -d ~/Cocos2d-x-Tutorial SimpleGame

這將在您的主目錄中創(chuàng)建一個(gè)名為Cocos2d-x-Tutorial的目錄,并在其中創(chuàng)建一個(gè)名為SimpleGame的子目錄曹质,其中包含您項(xiàng)目的文件婴噩。

注意:要了解可用的cocos子命令擎场,請(qǐng)鍵入cocos --helpcocos -h。 您還可以通過(guò)添加“ --help”或“ -h”(例如cocos new -h)來(lái)了解任何子命令的選項(xiàng)讳推,以查看new命令的選項(xiàng)顶籽。
Finder中雙擊?/ Cocos2d-x-Tutorial / SimpleGame / proj.ios_mac / SimpleGame.xcodeproj以在Xcode中打開(kāi)項(xiàng)目。

一旦進(jìn)入Xcode银觅,請(qǐng)確保SimpleGame Mac是活動(dòng)方案礼饱,如下所示:

SimpleGame Mac

盡管Cocos2d-x能夠?yàn)樵S多平臺(tái)構(gòu)建游戲,但在本教程中究驴,您將重點(diǎn)關(guān)注制作OS X應(yīng)用程序镊绪。 將這個(gè)項(xiàng)目移植到其他平臺(tái)上是一件很簡(jiǎn)單的事情(是的,很簡(jiǎn)單H饔恰)蝴韭,這在本教程的結(jié)尾進(jìn)行了簡(jiǎn)要討論。

生成并運(yùn)行您的應(yīng)用熙侍,以全面了解模板項(xiàng)目:


HelloWorld

分辨率設(shè)置

默認(rèn)情況下榄鉴,Cocos2d-x游戲的名稱(chēng)為“ MyGame”,分辨率為960×640蛉抓,但是這些細(xì)節(jié)很容易更改庆尘。
打開(kāi)AppDelegate.cpp并在其中找到以下行
AppDelegate::applicationDidFinishLaunching:

glview = GLViewImpl::create("My Game");

用以下代碼替換該行:

glview = GLViewImpl::createWithRect("SimpleGame", Rect(0,0, 480, 320), 1.0);

這會(huì)將應(yīng)用程序的名稱(chēng)更改為“ SimpleGame”,并將其分辨率設(shè)置為480×320巷送,以匹配模板隨附的背景圖片驶忌。

再次構(gòu)建并運(yùn)行您的應(yīng)用,以查看新的較小的游戲:

SimpleGame

請(qǐng)注意笑跛,您傳遞給createWithRect的第三個(gè)參數(shù)-1.0付魔。 此參數(shù)縮放幀,通常用于測(cè)試分辨率大于顯示器的幀飞蹂。 例如几苍,要在小于1920×1080的監(jiān)視器上測(cè)試1920×1080的分辨率,您可以傳遞0.5以將窗口縮放到960×540陈哑。

雖然對(duì)createWithRect的調(diào)用更改了臺(tái)式機(jī)上的游戲框架擦剑,但在iOS設(shè)備上這種方式無(wú)法正常工作; 而是游戲的分辨率與屏幕尺寸匹配芥颈。 這是在iPhone 6上的外觀:

Big SimpleGame

那么,您如何處理多種分辨率呢赚抡? 在本教程中爬坑,您將基于960×640分辨率創(chuàng)建一組游戲資源,然后在運(yùn)行時(shí)根據(jù)需要簡(jiǎn)單地按比例放大或縮小資產(chǎn)涂臣。
要實(shí)現(xiàn)這一點(diǎn)盾计,請(qǐng)?jiān)趦?nèi)部添加以下代碼:
AppDelegate::applicationDidFinishLaunching售担,位于在Director上調(diào)用setDisplayStats的行的上方:

// 1
Size designSize = Size(480,320);
Size resourceSize = Size(960,640);
// 2
director->setContentScaleFactor(resourceSize.height / designSize.height);
director->getOpenGLView()->setDesignResolutionSize(
  designSize.width, designSize.height, ResolutionPolicy::FIXED_HEIGHT);

上面的代碼是這樣的:

  • .在這里,您可以定義designSize(創(chuàng)建游戲邏輯時(shí)要使用的尺寸)和resourceSize(您所有藝術(shù)資產(chǎn)所基于的尺寸)署辉。
  • 2.這些行告訴您游戲的Driector根據(jù)您提供的設(shè)計(jì)和資源大小在必要時(shí)擴(kuò)展資產(chǎn)族铆。
    有關(guān)Cocos2d-x如何處理分辨率的詳細(xì)說(shuō)明,請(qǐng)參閱Cocos2d-x Wiki關(guān)于多分辨率適配的條目哭尝。

添加精靈

接下來(lái)哥攘,下載該項(xiàng)目的資源文件并將其解壓縮到方便的位置。

在剛剛提取的SimpleGameResources文件夾中選擇所有文件材鹦,并將它們拖到``Xcode項(xiàng)目的Resources組中逝淹。 在出現(xiàn)的對(duì)話框中,請(qǐng)確保在單擊“完成”之前選中“復(fù)制項(xiàng)目”桶唐,SimpleGame iOSSimpleGame Mac栅葡。

Choose options for adding these files

接下來(lái)打開(kāi)HelloWorldScene.h,在包含cocos2d.h的行之后添加以下行:

using namespace cocos2d;

這指定您將使用cocos2d命名空間尤泽; 這使您可以執(zhí)行諸如寫(xiě)Sprite *而不是cocos2d :: Sprite *的操作欣簇。 這不是絕對(duì)必要的,但肯定會(huì)使開(kāi)發(fā)更加愉快坯约。 :]

現(xiàn)在熊咽,您需要一個(gè)私有成員變量來(lái)指向您的player精靈。 將以下代碼添加到HelloWorld類(lèi)的聲明中:

private:
  Sprite* _player;

接下來(lái)鬼店,打開(kāi)HelloWorldScene.cpp并將HelloWorld::init方法的內(nèi)容替換為以下內(nèi)容:

// 1
if ( !Layer::init() ) {
  return false;
}
// 2
auto origin = Director::getInstance()->getVisibleOrigin();
auto winSize = Director::getInstance()->getVisibleSize();
// 3
auto background = DrawNode::create();
background->drawSolidRect(origin, winSize, Color4F(0.6,0.6,0.6,1.0));
this->addChild(background);
// 4
_player = Sprite::create("player.png");
_player->setPosition(Vec2(winSize.width * 0.1, winSize.height * 0.5));
this->addChild(_player);
    
return true;

這是此方法的逐步播放:

  • 1.首先网棍,您調(diào)用父類(lèi)的init方法。 只有成功后妇智,您才能繼續(xù)進(jìn)行HelloWorldScene的設(shè)置滥玷。
  • 2.然后,您可以使用游戲的Director單例來(lái)獲取窗口的邊界巍棱。
  • 3.然后惑畴,您創(chuàng)建一個(gè)DrawNode來(lái)繪制一個(gè)灰色矩形,該矩形將填充屏幕并將其添加到場(chǎng)景中航徙。 這是您游戲的背景如贷。
  • 4.最后,您通過(guò)傳入圖片名稱(chēng)來(lái)創(chuàng)建player精靈到踏。 您將其從屏幕的左邊緣垂直居中放置10%杠袱,并將其添加到場(chǎng)景中。
    生成并運(yùn)行您的應(yīng)用窝稿; 瞧楣富,女士們,先生們伴榔,忍者進(jìn)入了大樓纹蝴! :]


    添加忍者精靈

移動(dòng)怪物

忍者需要生活中的目標(biāo)庄萎,因此您需要在場(chǎng)景中添加一些怪物,忍者才能戰(zhàn)斗塘安。 為了讓事情變得更加有趣糠涛,您希望怪物們四處走動(dòng)-否則,這并不會(huì)帶來(lái)太大的挑戰(zhàn)兼犯! 您將在屏幕右側(cè)的右邊創(chuàng)建怪物忍捡,并為它們?cè)O(shè)置一個(gè)動(dòng)作,告訴它們向左移動(dòng)免都。

首先锉罐,打開(kāi)HelloWorldScene.h并添加以下方法聲明:

void addMonster(float dt);

然后在HelloWorldScene.cpp中添加以下方法實(shí)現(xiàn):

void HelloWorld::addMonster(float dt) {
  auto monster = Sprite::create("monster.png");
    
  // 1
  auto monsterContentSize = monster->getContentSize();
  auto selfContentSize = this->getContentSize();
  int minY = monsterContentSize.height/2;
  int maxY = selfContentSize.height - monsterContentSize.height/2;
  int rangeY = maxY - minY;
  int randomY = (rand() % rangeY) + minY;
    
  monster->setPosition(Vec2(selfContentSize.width + monsterContentSize.width/2, randomY));
  this->addChild(monster);
    
  // 2
  int minDuration = 2.0;
  int maxDuration = 4.0;
  int rangeDuration = maxDuration - minDuration;
  int randomDuration = (rand() % rangeDuration) + minDuration;
    
  // 3
  auto actionMove = MoveTo::create(randomDuration, Vec2(-monsterContentSize.width/2, randomY));
  auto actionRemove = RemoveSelf::create();
  monster->runAction(Sequence::create(actionMove,actionRemove, nullptr));
}

它相對(duì)簡(jiǎn)單,但是上面的代碼是這樣的:

  • 1.該方法的第一部分與您之前對(duì)player進(jìn)行的操作類(lèi)似:它會(huì)創(chuàng)建一個(gè)怪物(monster)精靈并將其放置在屏幕外的右側(cè)绕娘。 它將y位置設(shè)置為隨機(jī)值脓规,以保持有趣的狀態(tài)。
  • 2.接下來(lái)险领,該方法會(huì)計(jì)算要添加到個(gè)怪物(monster)身上的動(dòng)作的隨機(jī)持續(xù)時(shí)間侨舆,介于2到4秒之間。 每個(gè)怪物(monster)都會(huì)在屏幕上移動(dòng)相同的距離绢陌,因此改變持續(xù)時(shí)間會(huì)導(dǎo)致怪物(monster)的速度隨機(jī)挨下。
  • 3.最后,該方法創(chuàng)建一個(gè)動(dòng)作脐湾,該動(dòng)作使怪物(monster)從右到左在屏幕上移動(dòng)臭笆,并指示怪物(monster)運(yùn)行它。 下面將對(duì)此進(jìn)行詳細(xì)說(shuō)明秤掌。

Cocos2d-x提供了許多非常方便的內(nèi)置動(dòng)作愁铺,可幫助您隨時(shí)間輕松地更改精靈的狀態(tài),包括移動(dòng)動(dòng)作闻鉴,旋轉(zhuǎn)動(dòng)作茵乱,淡入淡出動(dòng)作,動(dòng)畫(huà)動(dòng)作等孟岛。 在這里瓶竭,您對(duì)怪物使用三個(gè)動(dòng)作:

  • MoveTo:在特定的時(shí)間內(nèi)將對(duì)象從一個(gè)點(diǎn)移動(dòng)到另一點(diǎn)。
  • RemoveSelf:從其父節(jié)點(diǎn)刪除節(jié)點(diǎn)渠羞,從而有效地將其從場(chǎng)景中“刪除”斤贰。 在這種情況下,您可以使用該操作將不再可見(jiàn)的怪物從場(chǎng)景中移除次询。 這很重要腋舌,因?yàn)榉駝t您將有無(wú)窮無(wú)盡的怪物供不應(yīng)求,并最終會(huì)消耗掉設(shè)備的所有資源渗蟹。
  • Sequence:讓您一次執(zhí)行一系列其他操作块饺。 這意味著您可以讓怪物在場(chǎng)景中移動(dòng),并在到達(dá)目的地時(shí)將其從屏幕上移開(kāi)雌芽。

在讓忍者進(jìn)城之前授艰,還有最后一件事要做-您需要實(shí)際調(diào)用創(chuàng)建怪物的方法! 為了使事情變得有趣世落,您將創(chuàng)建不斷產(chǎn)生的怪物淮腾。

只需在return語(yǔ)句之前,將以下代碼添加到HelloWorld:: init的末尾:

srand((unsigned int)time(nullptr));
this->schedule(schedule_selector(HelloWorld::addMonster), 1.5); 

srand((unsigned int)time(nullptr));播種隨機(jī)數(shù)生成器屉佳。 如果您不這樣做谷朝,那么每次您運(yùn)行該應(yīng)用程序時(shí),您的隨機(jī)數(shù)都會(huì)相同武花。 感覺(jué)不會(huì)很隨意圆凰,是嗎? :]

然后体箕,將HelloWorld::addMonster傳遞到schedule方法中专钉,該方法每1.5秒調(diào)用一次addMonster()
在這里累铅,Cocos2d-x利用了C ++指向成員函數(shù)的指針跃须。 如果您不了解其工作原理,請(qǐng)參閱ioscpp以獲取更多信息娃兽。

而已菇民! 建立并運(yùn)行您的項(xiàng)目; 您現(xiàn)在應(yīng)該可以看到妖怪在屏幕上快樂(lè)地(或憤怒地(視情況而定M洞ⅰ))移動(dòng):


添加怪物 2

射擊彈丸

您勇敢的小忍者需要一種保護(hù)自己的方法第练。 在游戲中實(shí)現(xiàn)火力的方法有很多,但是在此項(xiàng)目中轻要,您將讓用戶(hù)單擊或輕擊屏幕以沿單擊或輕擊的方向發(fā)射彈丸复旬。 ew! :]

為簡(jiǎn)化起見(jiàn)冲泥,您將通過(guò)MoveTo操作實(shí)現(xiàn)這一點(diǎn)-但這意味著您需要做一些數(shù)學(xué)運(yùn)算驹碍。

MoveTo操作需要射彈的目標(biāo)位置,但是您不能直接使用輸入位置凡恍,因?yàn)樵擖c(diǎn)僅代表相對(duì)于玩家的射擊方向志秃。 您想讓子彈一直移動(dòng)到該點(diǎn),直到子彈到達(dá)屏幕外的最終目的地嚼酝。

這是說(shuō)明問(wèn)題的圖片:


射擊彈丸的物理圖

從原點(diǎn)到觸摸位置的x和y偏移會(huì)創(chuàng)建一個(gè)小三角形浮还; 您只需要制作一個(gè)具有相同比率的大三角形即可,并且您知道要使其中一個(gè)端點(diǎn)不在屏幕上闽巩。

利用Cocos2d-x隨附的矢量數(shù)學(xué)例程钧舌,可以輕松執(zhí)行這些計(jì)算担汤。 但是,在計(jì)算移動(dòng)位置之前洼冻,您需要啟用輸入事件處理功能才能弄清楚用戶(hù)觸摸的位置崭歧!
將以下代碼添加到HelloWorld:: init的末尾,就在return語(yǔ)句的上方:

auto eventListener = EventListenerTouchOneByOne::create();
eventListener->onTouchBegan = CC_CALLBACK_2(HelloWorld::onTouchBegan, this);
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(eventListener, _player);

Cocos2d-x版本3及更高版本使用EventDispatcher來(lái)調(diào)度各種事件撞牢,例如觸摸率碾,加速計(jì)和鍵盤(pán)事件。

注意:在整個(gè)討論中屋彪,術(shù)語(yǔ)“觸摸”是指觸摸設(shè)備上的點(diǎn)擊以及桌面上的點(diǎn)擊所宰。 Cocos2d-x使用相同的方法來(lái)處理兩種類(lèi)型的事件。

為了從EventDispatcher接收事件畜挥,您需要注冊(cè)一個(gè)EventListener仔粥。 觸摸事件偵聽(tīng)器有兩種類(lèi)型:

  • EventListenerTouchOneByOne:此類(lèi)型為每個(gè)觸摸事件調(diào)用一次您的回調(diào)方法。
  • EventListenerTouchAllAtOnce:此類(lèi)型對(duì)所有觸摸事件調(diào)用一次您的回調(diào)方法砰嘁。

觸摸事件偵聽(tīng)器支持四個(gè)回調(diào)件炉,但是您只需要為您關(guān)心的事件綁定方法。

  • onTouchBegan:在手指首次觸摸屏幕時(shí)調(diào)用矮湘。 如果使用的是EventListenerTouchOneByOne斟冕,則必須返回true才能接收其他三個(gè)觸摸事件中的任何一個(gè)。
  • onTouchMoved:當(dāng)您的手指已經(jīng)觸摸屏幕而沒(méi)有離開(kāi)屏幕而移動(dòng)時(shí)調(diào)用缅阳。
  • onTouchEnded:當(dāng)手指離開(kāi)屏幕時(shí)調(diào)用磕蛇。
  • onTouchCancelled:在某些情況下被調(diào)用以停止事件處理,例如當(dāng)您觸摸屏幕時(shí)十办,然后像電話之類(lèi)的中斷應(yīng)用程序秀撇。
    在這個(gè)游戲中,您實(shí)際上只在乎何時(shí)發(fā)生觸摸向族。 聲明您的回調(diào)以在HelloWorldScene.h中接收觸摸通知呵燕,如下所示:
bool onTouchBegan(Touch *touch, Event *unused_event);

然后在HelloWorldScene.cpp中實(shí)現(xiàn)您的回調(diào):

bool HelloWorld::onTouchBegan(Touch *touch, Event *unused_event) {
  // 1  - Just an example for how to get the  _player object
  //auto node = unused_event->getCurrentTarget();
    
  // 2
  Vec2 touchLocation = touch->getLocation();
  Vec2 offset = touchLocation - _player->getPosition();
    
  // 3
  if (offset.x < 0) {
    return true;
  }

  // 4
  auto projectile = Sprite::create("projectile.png");
  projectile->setPosition(_player->getPosition());
  this->addChild(projectile);

  // 5
  offset.normalize();
  auto shootAmount = offset * 1000;

  // 6
  auto realDest = shootAmount + projectile->getPosition();

  // 7
  auto actionMove = MoveTo::create(2.0f, realDest);
  auto actionRemove = RemoveSelf::create();
  projectile->runAction(Sequence::create(actionMove,actionRemove, nullptr));
    
  return true;
}

上面的方法正在進(jìn)行很多工作,因此請(qǐng)花點(diǎn)時(shí)間逐步檢查一下件相。

  • 1.第一行已被注釋掉再扭,但是它在那里向您展示了如何訪問(wèn)作為第二個(gè)參數(shù)傳遞給addEventListenerWithSceneGraphPriority(eventListener, _player)_player對(duì)象。
  • 2.您可以在此處獲得場(chǎng)景坐標(biāo)系內(nèi)觸摸的坐標(biāo)夜矗,然后計(jì)算該點(diǎn)與播放器當(dāng)前位置的偏移量泛范。這是Cocos2d-x中向量數(shù)學(xué)的一個(gè)示例。
  • 3.如果offsetx值為負(fù)紊撕,則表示玩家正在嘗試向后射擊罢荡。在此游戲中不允許這樣做(真正的忍者永不回頭!),因此只需返回而無(wú)需發(fā)射彈丸区赵。
  • 4.在玩家的位置上創(chuàng)建一個(gè)彈丸惭缰,并將其添加到場(chǎng)景中。
  • 5.然后笼才,您調(diào)用normalize()將偏移量轉(zhuǎn)換為單位向量从媚,該向量是長(zhǎng)度為1的向量。將其乘以1000可得到長(zhǎng)度為1000的向量患整,該向量指向用戶(hù)點(diǎn)擊的方向。為什么是1000喷众?該長(zhǎng)度應(yīng)足以以該分辨率延伸超出屏幕邊緣:]
  • 6.將向量添加到彈丸的位置即可得到目標(biāo)位置各谚。
  • 7.最后,創(chuàng)建一個(gè)動(dòng)作到千,將彈丸移至目標(biāo)位置超過(guò)兩秒鐘昌渤,然后將其從場(chǎng)景中移除。
    生成并運(yùn)行您的應(yīng)用憔四;觸摸屏幕膀息,使您的忍者向即將來(lái)臨的部落射擊!


    添加飛鏢

碰撞檢測(cè)與物理

現(xiàn)在您已經(jīng)擁有飛鏢飛來(lái)飛去的地方-但您的忍者真正想要做的就是放下一些零頭了赵。 因此潜支,您需要一些代碼來(lái)檢測(cè)彈丸何時(shí)與目標(biāo)相交。

關(guān)于Cocos2d-x的一件好事是它內(nèi)置了一個(gè)物理引擎柿汛! 物理引擎不僅對(duì)于模擬逼真的運(yùn)動(dòng)非常有用冗酿,而且對(duì)于檢測(cè)碰撞也非常有用。 您將使用Cocos2d-x的物理引擎來(lái)確定怪物和投射物何時(shí)發(fā)生碰撞络断。

首先在HelloWorld::createScene的實(shí)現(xiàn)上方裁替,向HelloWorldScene.cpp添加以下代碼:

enum class PhysicsCategory {
  None = 0,
  Monster = (1 << 0),    // 1
  Projectile = (1 << 1), // 2
  All = PhysicsCategory::Monster | PhysicsCategory::Projectile // 3
};

些位掩碼定義了您需要的物理類(lèi)別-并非雙關(guān)語(yǔ)! :]在這里貌笨,您已經(jīng)創(chuàng)建了兩種類(lèi)型弱判,MonsterProjectile,以及兩個(gè)特殊值锥惋,用于指定沒(méi)有類(lèi)型或所有類(lèi)型昌腰。 您將使用這些類(lèi)別為對(duì)象分配類(lèi)型,從而允許您指定允許哪些對(duì)象類(lèi)型相互碰撞净刮。

注意:您可能想知道這種奇特的語(yǔ)法是什么剥哑。 Cocos2d-x上的類(lèi)別只是一個(gè)32位整數(shù)。 此語(yǔ)法將整數(shù)中的特定位設(shè)置為代表不同的類(lèi)別淹父,最多給您32種可能的類(lèi)別株婴。 在這里,您將第一位設(shè)置為指示怪物,將下一位設(shè)置為代表彈丸困介,依此類(lèi)推大审。

接下來(lái),用以下代碼替換HelloWorld::createScene的第一行:

auto scene = Scene::createWithPhysics();
scene->getPhysicsWorld()->setGravity(Vec2(0,0));
scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);

這將創(chuàng)建一個(gè)啟用了物理的場(chǎng)景座哩。 Cocos2d-x使用PhysicsWorld來(lái)控制其物理模擬徒扶。 在這里,您可以在兩個(gè)方向上將世界的重力設(shè)置為零根穷,這實(shí)際上會(huì)禁用重力姜骡,并且可以啟用調(diào)試?yán)L圖以查看物理物體。 在對(duì)物理相互作用進(jìn)行原型設(shè)計(jì)時(shí)屿良,啟用調(diào)試?yán)L圖很有幫助圈澈,這樣可以確保事情正常進(jìn)行。

HelloWorld::addMonster中尘惧,在創(chuàng)建怪物精靈的第一行之后添加以下代碼:

// 1
auto monsterSize = monster->getContentSize();
auto physicsBody = PhysicsBody::createBox(Size(monsterSize.width , monsterSize.height),
                                          PhysicsMaterial(0.1f, 1.0f, 0.0f));
// 2
physicsBody->setDynamic(true);
// 3
physicsBody->setCategoryBitmask((int)PhysicsCategory::Monster);
physicsBody->setCollisionBitmask((int)PhysicsCategory::None);
physicsBody->setContactTestBitmask((int)PhysicsCategory::Projectile);
    
monster->setPhysicsBody(physicsBody);

這是上面的代碼的作用:

  • 1.為精靈創(chuàng)建一個(gè)PhysicsBody康栈。物理實(shí)體代表Cocos2d-x物理仿真中的對(duì)象,您可以使用任何形狀來(lái)定義它們喷橙。在這種情況下啥么,可以使用與精靈大小相同的矩形作為怪獸的近似值。您可以使用更精確的形狀贰逾,但是更簡(jiǎn)單的形狀足以滿(mǎn)足大多數(shù)游戲和更高的性能要求悬荣。
  • 2.將精靈設(shè)置為動(dòng)態(tài)。這意味著物理引擎不會(huì)向怪物施加力似踱。相反隅熙,您將直接通過(guò)之前創(chuàng)建的MoveTo操作對(duì)其進(jìn)行控制。
  • 3.在這里核芽,您可以設(shè)置類(lèi)別囚戚,碰撞和接觸測(cè)試位掩碼:
    • 類(lèi)別:定義對(duì)象的類(lèi)型–Monster
    • 碰撞:定義在碰撞期間應(yīng)以何種類(lèi)型的對(duì)象物理影響該對(duì)象-在這種情況下為None轧简。因?yàn)榇藢?duì)象也是動(dòng)態(tài)的驰坊,所以此字段無(wú)效,但出于完整性考慮哮独,在此將其包括在內(nèi)拳芙。
    • 接觸測(cè)試:定義碰撞應(yīng)通過(guò)其生成通知的對(duì)象類(lèi)型-Projectile。您將在本教程的稍后部分注冊(cè)并處理這些通知皮璧。
    • 最后舟扎,將物理物體分配給怪物。
      接下來(lái)悴务,將以下代碼添加到HelloWorld::onTouchBegan中睹限,緊接設(shè)置彈丸位置的行之后:
auto projectileSize = projectile->getContentSize();
auto physicsBody = PhysicsBody::createCircle(projectileSize.width/2 );
physicsBody->setDynamic(true); 
physicsBody->setCategoryBitmask((int)PhysicsCategory::Projectile);
physicsBody->setCollisionBitmask((int)PhysicsCategory::None);
physicsBody->setContactTestBitmask((int)PhysicsCategory::Monster);
projectile->setPhysicsBody(physicsBody);

這與您為怪物執(zhí)行的物理設(shè)置非常相似譬猫,不同的是它使用圓形而不是矩形來(lái)定義物理物體。 請(qǐng)注意羡疗,并不是絕對(duì)必要設(shè)置接觸測(cè)試位掩碼染服,因?yàn)楣治镆呀?jīng)在檢查與射彈的碰撞,但這有助于使代碼的意圖更加清晰叨恨。

立即構(gòu)建并運(yùn)行您的項(xiàng)目柳刮; 您會(huì)看到紅色形狀疊加在物理物體上,如下所示:


SimpleGame final

射彈被設(shè)置為可以擊中怪物痒钝,因此當(dāng)它們碰撞時(shí)秉颗,您需要將它們都移除岂昭。

還記得早先的物理學(xué)世界嗎蝎亚? 好吧,您可以在其上設(shè)置一個(gè)聯(lián)系人代表霎奢,以在兩個(gè)物理物體碰撞時(shí)得到通知益愈。 在那里,您將編寫(xiě)一些代碼來(lái)檢查對(duì)象的類(lèi)別夷家,如果它們是怪物和彈丸蒸其,則可以使其蓬勃發(fā)展!

首先库快,將以下方法聲明添加到HelloWorldScene.h中:

bool onContactBegan(PhysicsContact &contact);

這是您注冊(cè)以接收聯(lián)系事件的方法摸袁。

接下來(lái),在HelloWorldScene.cpp中實(shí)現(xiàn)以下方法:

bool HelloWorld::onContactBegan(PhysicsContact &contact) {
  auto nodeA = contact.getShapeA()->getBody()->getNode();
  auto nodeB = contact.getShapeB()->getBody()->getNode();
    
  nodeA->removeFromParent();
  nodeB->removeFromParent();
  return true;
}

傳遞給此方法的PhysicsContact包含有關(guān)碰撞的信息义屏。 在這個(gè)游戲中靠汁,您知道唯一會(huì)碰撞的對(duì)象是怪物和射彈。 因此闽铐,您將使節(jié)點(diǎn)參與碰撞并將其從場(chǎng)景中移除蝶怔。

最后,您需要注冊(cè)以接收聯(lián)系人通知兄墅。 在return語(yǔ)句之前踢星,將以下行添加到HelloWorld ::init的末尾:

auto contactListener = EventListenerPhysicsContact::create();
contactListener->onContactBegin = CC_CALLBACK_1(HelloWorld::onContactBegan, this);
this->getEventDispatcher()->addEventListenerWithSceneGraphPriority(contactListener, this);

這將創(chuàng)建一個(gè)聯(lián)系人偵聽(tīng)器,注冊(cè)HelloWorld::onContactBegan以接收事件并將偵聽(tīng)器添加到EventDispatcher隙咸。 現(xiàn)在沐悦,只要兩個(gè)物理物體發(fā)生碰撞并且它們的類(lèi)別位掩碼與它們的接觸測(cè)試位掩碼匹配,EventDispatcher就會(huì)調(diào)用onContactBegan五督。

生成并運(yùn)行您的應(yīng)用藏否; 現(xiàn)在,當(dāng)您的彈丸與目標(biāo)相交時(shí)充包,它們應(yīng)該消失:


Simple 碰撞檢測(cè)

畫(huà)龍點(diǎn)睛

您現(xiàn)在已經(jīng)快要制作出一款可行(但非常簡(jiǎn)單)的游戲了副签。 您只需要添加一些聲音效果和音樂(lè)(因?yàn)槟姆N游戲都沒(méi)有聲音!)和一些簡(jiǎn)單的游戲邏輯即可。

Cocos2d-x帶有一個(gè)稱(chēng)為CocosDenshion的簡(jiǎn)單音頻引擎继薛,您將使用它來(lái)播放聲音修壕。

注意:Cocos2d-x還包括第二個(gè)音頻引擎,旨在代替簡(jiǎn)單的音頻引擎模塊遏考。 但是慈鸠,它仍處于試驗(yàn)階段,并且不適用于所有受支持的平臺(tái)灌具,因此您將不在此處使用它青团。

該項(xiàng)目已經(jīng)包含了一些很酷的背景音樂(lè)以及您之前導(dǎo)入的超贊的“ pew-pew”音效。 您只需要玩它們咖楣!

為此督笆,在其他#include語(yǔ)句之后,將以下代碼添加到HelloWorldScene.cpp的頂部:

using namespace CocosDenshion;

這將導(dǎo)入SimpleAudioEngine模塊诱贿,并指定您將在此文件中使用CocosDenshion命名空間娃肿。

接下來(lái),將以下定義添加到PhysicsCategory枚舉上方的HelloWorldScene.cpp

#define PEW_PEW_SFX           "pew-pew-lei.mp3"

在這里珠十,您定義了兩個(gè)字符串常量:BACKGROUND_MUSIC_SFXPEW_PEW_SFX料扰。 這只是將文件名放在一個(gè)位置,這使得以后更容易更改它們焙蹭。 像這樣組織代碼(甚至使用完全獨(dú)立的文件甚至更好)晒杈,可以更輕松地支持特定于平臺(tái)的更改,例如在iPhone上使用.mp3文件孔厉,在Windows Phone上使用.wav文件拯钻。

現(xiàn)在,在return語(yǔ)句之前撰豺,將以下行添加到HelloWorld::init的末尾:

SimpleAudioEngine::getInstance()->playBackgroundMusic(BACKGROUND_MUSIC_SFX, true);

場(chǎng)景建立后粪般,即會(huì)開(kāi)始播放背景音樂(lè)。

至于聲音效果污桦,請(qǐng)將以下行添加到HelloWorld::onTouchBeganreturn語(yǔ)句上方:

SimpleAudioEngine::getInstance()->playEffect(PEW_PEW_SFX);

每當(dāng)忍者發(fā)動(dòng)攻擊時(shí)刊驴,這都會(huì)起到很好的“ pew-pew”聲音效果。 很方便寡润,是嗎捆憎? 您僅需一行代碼即可播放聲音效果。

生成并運(yùn)行梭纹,并享受您的時(shí)髦音樂(lè)躲惰!

然后去哪兒?
這是上面教程中完成的示例游戲变抽。

希望您喜歡Cocos2d-x础拨,并從中獲得靈感來(lái)制作自己的游戲氮块! 要了解有關(guān)Cocos2d-x的更多信息,請(qǐng)訪問(wèn)Cocos2d-x網(wǎng)站以獲取大量學(xué)習(xí)資源诡宗。

如果對(duì)本教程有任何疑問(wèn)或意見(jiàn)滔蝉,請(qǐng)加入下面的討論!

關(guān)于本項(xiàng)目在其他系統(tǒng)如Windows上的移植

我使用的是Window7系統(tǒng)塔沃,Cocos2d-x的版本是3.17.2蝠引,Python是2.7.18
使用VS2017打開(kāi)項(xiàng)目下的SimpleGame\proj.win32\文件夾下的SimpleGame.sln,然后編譯運(yùn)行蛀柴,前提是需要配置好Cocos2d-x 3.17.2的開(kāi)發(fā)環(huán)境螃概,關(guān)于環(huán)境搭建可以參考我之前寫(xiě)的一篇博客:Win10+Python2.7.14+cocos2d-x-3.17.2+VS2017環(huán)境搭建,下面是我在VS2017中運(yùn)行本項(xiàng)目的截圖:

VS2017中的運(yùn)行結(jié)果截圖

最終的項(xiàng)目源代碼我已經(jīng)托管到GithubGitee上,需要的話執(zhí)行如下命令自雀爰病:

從github上獲取cocos2d-x-tutorial源代碼

git clone https://github.com/ccf19881030/Cocos2d-x-Tutorial.git

從gitee碼云上獲取cocos2d-x-tutorial源代碼

git clone https://gitee.com/havealex/cocos2d-x-tutorial.git

參考資料

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末吊洼,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子冒窍,更是在濱河造成了極大的恐慌,老刑警劉巖超燃,帶你破解...
    沈念sama閱讀 210,914評(píng)論 6 490
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件拘领,死亡現(xiàn)場(chǎng)離奇詭異樱调,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)圣猎,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 89,935評(píng)論 2 383
  • 文/潘曉璐 我一進(jìn)店門(mén)乞而,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)送悔,“玉大人,你說(shuō)我怎么就攤上這事爪模∏菲。” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 156,531評(píng)論 0 345
  • 文/不壞的土叔 我叫張陵屋灌,是天一觀的道長(zhǎng)洁段。 經(jīng)常有香客問(wèn)我,道長(zhǎng)共郭,這世上最難降的妖魔是什么祠丝? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 56,309評(píng)論 1 282
  • 正文 為了忘掉前任疾呻,我火速辦了婚禮,結(jié)果婚禮上写半,老公的妹妹穿的比我還像新娘岸蜗。我一直安慰自己,他們只是感情好叠蝇,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,381評(píng)論 5 384
  • 文/花漫 我一把揭開(kāi)白布璃岳。 她就那樣靜靜地躺著,像睡著了一般蟆肆。 火紅的嫁衣襯著肌膚如雪矾睦。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,730評(píng)論 1 289
  • 那天炎功,我揣著相機(jī)與錄音枚冗,去河邊找鬼。 笑死蛇损,一個(gè)胖子當(dāng)著我的面吹牛赁温,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播淤齐,決...
    沈念sama閱讀 38,882評(píng)論 3 404
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼股囊,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了更啄?” 一聲冷哼從身側(cè)響起稚疹,我...
    開(kāi)封第一講書(shū)人閱讀 37,643評(píng)論 0 266
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤内狗,失蹤者是張志新(化名)和其女友劉穎柳沙,沒(méi)想到半個(gè)月后赂鲤,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體数初,經(jīng)...
    沈念sama閱讀 44,095評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡妙真,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,448評(píng)論 2 325
  • 正文 我和宋清朗相戀三年练般,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了锈候。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片泵琳。...
    茶點(diǎn)故事閱讀 38,566評(píng)論 1 339
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡获列,死狀恐怖击孩,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情创泄,我是刑警寧澤鞠抑,帶...
    沈念sama閱讀 34,253評(píng)論 4 328
  • 正文 年R本政府宣布搁拙,位于F島的核電站法绵,受9級(jí)特大地震影響礼烈,放射性物質(zhì)發(fā)生泄漏此熬。R本人自食惡果不足惜犀忱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,829評(píng)論 3 312
  • 文/蒙蒙 一阴汇、第九天 我趴在偏房一處隱蔽的房頂上張望节槐。 院中可真熱鬧,春花似錦哥倔、人聲如沸咆蒿。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,715評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至田巴,卻和暖如春壹哺,著一層夾襖步出監(jiān)牢的瞬間管宵,已是汗流浹背攀甚。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,945評(píng)論 1 264
  • 我被黑心中介騙來(lái)泰國(guó)打工秋度, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留荚斯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,248評(píng)論 2 360
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像兽泣,于是被迫代替她去往敵國(guó)和親唠倦。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,440評(píng)論 2 348