)知易遊戲開發教程cocos2d-x移植版004

來源:互聯網
上載者:User
文章目錄
  • CCStandardTouchDelegate
  • CCTargetedTouchDelegate

我們知道cocos2d-x是cocos2d-iphone項目的C++移植版本,它擁有跨平台的特性。同時cocos2d-x與cocos2d-iphone保持著高度地同步,這也就從根本上限制住它是一個為手機、平板等裝置量身定做的遊戲引擎。而對Win32等平台的支援,僅僅是為了方便開發與調試。
如果你正準備開發PC版的遊戲,使用那種專為PC設計的引擎才是你正確的選擇。雖然在一篇介紹cocos2d-x的文章裡出現這樣的句子有些紮眼,但我想有些事情還是講明白的好,任何人的時間都不應該被浪費。

如果你也像我一樣是從PC端開發加入到cocos2d-x中的,那麼有很多概念是需要注意的。
比如,在PC上我們經常使用的滑鼠在手機和平板上變成了手指頭。這當然不單單是介質的轉變,發生變化的還包括使用習慣。

消失的滑鼠經過狀態
大家都知道,在PC上,一個按鈕通常包含4種狀態——普通、滑鼠經過、滑鼠按下、禁用,而在手機和平板上,一個按鈕通常只有3種狀態——普通、按下、禁用。
這是很容易理解的。
第一,不管滑鼠放在什麼地方,它終究是脫離不了顯示器螢幕的,而讓一個人時刻把手指按在觸控螢幕上,要困難得多。
第二,滑鼠是有按鍵的,而人手沒有按鍵,想實現移動而脫離點擊是有難度的。
所以在手機和平板上,傳統意義的滑鼠經過狀態幾乎不存在。

神奇的多點觸摸
對於手機和平板使用者來說,多點觸屏稀鬆平常。雖然PC也有支援多點輸入的外設,但支援這一特性的軟體卻不常見。對於用慣了PC的人來說,還是滑鼠的單點輸入更容易接受。

所謂習慣嘛,就是習以為常,時間久了,也就是那麼回事兒了。今天我們就來認識認識這個Touch(觸摸)。

cocos2d-x的觸摸事件處理

在cocos2d-x中,觸摸是一種重要的互動手段。雖然我們之前沒有明確指出這個觸摸事件,但是我們一刻也沒有離開它。每一個Menu的觸發,其實就是一次觸摸。

CCStandardTouchDelegate

準確來說,我們與Touch有過一面之緣。在第2篇中,我們實現了一個點擊螢幕後,飛船移動過去的功能。

1 void GameLayer::ccTouchesEnded(CCSet *pTouches, CCEvent *pEvent) 2 { 3 CCTouch *touch = (CCTouch *)pTouches->anyObject(); 4 // 獲得觸摸點座標5 CCPoint location = touch->locationInView(touch->view()); 6 CCPoint convertedLocation = CCDirector::sharedDirector()->convertToGL(location); 7 // 讓飛船在1秒鐘內移動過去8 flight->runAction(CCMoveTo::actionWithDuration(1.0f, ccp(convertedLocation.x, convertedLocation.y))); 9 }

但是,想要上面的代碼生效,還必須在初始化中開啟觸摸事件。

1 bool GameLayer::init(void) 2 { 3 ... 4 // accept touch now!5 setIsTouchEnabled(true); 6 ... 7 }

跟進去看看開啟觸摸事件的實現。

 1 void CCLayer::setIsTouchEnabled(bool enabled) 2 { 3 if (m_bIsTouchEnabled != enabled) 4 { 5 m_bIsTouchEnabled = enabled; 6 if (m_bIsRunning) 7 { 8 if (enabled) 9 { 10 this->registerWithTouchDispatcher(); 11 } 12 else 13 { 14 // have problems?15 CCTouchDispatcher::sharedDispatcher()->removeDelegate(this); 16 } 17 } 18 } 19 } 20  21 void CCLayer::registerWithTouchDispatcher() 22 { 23 CCTouchDispatcher::sharedDispatcher()->addStandardDelegate(this,0); 24 }

上面的代碼通過CCTouchDispatcher添加標準代理實現開啟觸摸的功能。

所謂標準代理就是指你可以接收到所有的訊息——開始(Began)、移動(Moved)、結束(Ended)、取消(Cancelled)。觸摸點的資訊是由CCSet表示一個集合。

與高許可權相隨的是高靈活性,而要獲得高靈活性的代價就是你必須自己來編寫額外的代碼。

靈活性太高,反而不知從何開始,乾脆就不講了,以後有實際需要的時候再說。不過有一點必須提一下,標準代理類型與蘋果的CocoaTouch架構基本一致,所以CocoaTouch的大部分方案在cocos2d-x中也是可行的。

CCTargetedTouchDelegate

相較標準代理來說,目標代理的功能自然是弱一些,但使用起來要簡便得多。

使用目標代理有兩個顯著的好處:
1.你不用跟CCSet打交道,發送器會替你做好拆分,每次使用時你會得到單一的Touch事件。
2.你可以通過讓ccTouchBegan返回true來“認領”一個觸摸事件。被“認領”的觸摸事件只會被分發給“認領”它的代理對象。這樣你就可以從多點觸摸的檢測苦海中解脫出來。

我們來實戰演練一下。假設我們接到一個任務,要求在螢幕上顯示一個精靈,這個精靈是一個迴圈播放的序列幀動畫。當我們按在精靈上的時候可以拖動它,如果點在精靈外面,那就不能拖動。

首先分析下我們接到的任務。顯示一個迴圈播放的序列幀動畫精靈,這個沒有痛點,我們之前已經做過多次了。按在精靈上的時候可以拖動它,按在外面就不能拖動,這一條如果使用標準代理對象實現,必然要添加大量的判斷和狀態,顯然目標代理是我們應該優先考慮的。

因此,我們需要的是一個符合目標代理的精靈,所以這是一個多重繼承的類,它有2個父類——CCSprite和CCTargetedTouchDelegate。

1 class KillingLight : public CCSprite, public CCTargetedTouchDelegate 2 { 3 public: 4 KillingLight(void); 5 virtual ~KillingLight(void); 6 }

要接收觸摸事件必須先進行註冊,當不再需要的時候要進行反註冊。我們重寫CCNode的onEnter和onExit函數來完成觸摸事件的註冊與反註冊。

 1 void KillingLight::onEnter(void) 2 { 3 CCSprite::onEnter(); 4 // 我們希望獨佔被“認領”的觸摸事件,所以第3個參數傳入true5 CCTouchDispatcher::sharedDispatcher()->addTargetedDelegate(this, 0, true); 6 } 7  8 void KillingLight::onExit(void) 9 { 10 CCTouchDispatcher::sharedDispatcher()->removeDelegate(this); 11 CCSprite::onExit(); 12 }

在目標代理對象中,只有先“認領”觸摸事件,才能使用。所以我們要重寫CCTargetedTouchDelegate的ccTouchBegan函數。

因為任務要求只有點在精靈上面時才能拖動,所以我們需要增加判斷觸摸點是否在精靈上的判斷。

 1 CCRect KillingLight::rect(void) 2 { 3 // 後面的比較是以錨點為標準的4 const CCSize& s = getTextureRect().size; 5 const CCPoint& p = this->getAnchorPointInPixels(); 6 return CCRectMake(-p.x, -p.y, s.width, s.height); 7 } 8  9 bool KillingLight::containsTouchLocation(CCTouch *touch) 10 { 11 return CCRect::CCRectContainsPoint(rect(), convertTouchToNodeSpaceAR(touch)); 12 } 13  14 bool KillingLight::ccTouchBegan(CCTouch *pTouch, CCEvent *pEvent) 15 { 16 if (! containsTouchLocation(pTouch)) 17 return false; 18  19 return true; 20 }

接著,我們重寫CCTargetedTouchDelegate的ccTouchMoved函數,來實現拖動功能。

1 void KillingLight::ccTouchMoved(CCTouch *pTouch, CCEvent *pEvent) 2 { 3 CCPoint touchPoint = pTouch->locationInView(pTouch->view()); 4 touchPoint = CCDirector::sharedDirector()->convertToGL(touchPoint); 5 setPosition(touchPoint); 6 }

為了便於使用,我們再添加一個靜態成員函數KillingLightWithBatchNode來建立KillingLight對象。

 1 KillingLight* KillingLight::KillingLightWithBatchNode(cocos2d::CCSpriteBatchNode *batchNode, const cocos2d::CCRect& rect) 2 { 3 KillingLight *pobSprite = new KillingLight(); 4 if (pobSprite && pobSprite->initWithBatchNode(batchNode, rect)) 5 { 6 pobSprite->autorelease(); 7 return pobSprite; 8 } 9 CC_SAFE_DELETE(pobSprite); 10 return NULL; 11 }

這樣,一個支援點擊拖動的精靈類就完成了,你可以像使用CCSprite那樣使用它。

如果你希望讓這個類再完美一些,比如只響應第一個按上的觸摸事件以免多點搶一個精靈等等,你可以參考TouchesTest中的Paddle類。

代碼下載:
http://files.cnblogs.com/cocos2d-x/ZYG004.rar

在處理觸摸事件的時候,最需要注意的是座標轉換。這包括很多層面,是螢幕座標系還是GL座標系,是全局座標還是局部座標,還有座標是相對哪個點計算的等等。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.