游戲中碰撞的檢測相當重要,任何兩個sprite間都避免不了有交集,碰撞檢測也體現了游戲的真實性。
矩形檢測
矩形檢測是一種實現方式比較簡單的檢測方式,簡單就意味着不那么真實。原理就是將sprite紋理抽象出一個Rect,然后通過判斷Rect間是否相交,以此作為sprite的碰撞檢測。這種碰撞檢測是不精確的,當然,如果游戲要求不高,還是可以的。
可見,構建矩形框Rect(黑色)后,判斷Rect相交即可實現碰撞檢測,但無論矩形如何設置,難免會有“盲點”使得檢測不那么精確(第3種情況)。
CCRect.CCRectIntersetsRect
Cocos2d-x提供了方法判斷Rect是否相交的方法。
游戲規則
為了講解碰撞檢測,簡單地設計一個游戲,游戲的規則是:玩家通過觸碰屏幕操作Wolf的移動,Gold與Bomb隨機從屏幕上端往下移動。Wolf與Gold碰撞得分,Wolf與Bomb碰撞扣分。很簡單檢測碰撞的游戲。
前提
還是老樣子,添加游戲關鍵兩層(Scene和Layer)GameScene、GameLayer。

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using cocos2d; 6 7 namespace LearningCocos2d_xForXNA.Classes 8 { 9 class GameScene:CCScene 10 { 11 public GameScene() 12 { 13 CCLayer gameLayer = new GameLayer(); 14 this.addChild(gameLayer); 15 } 16 } 17 }
Sprite
Gold:繼承CCSprite,構造方法中,添加各類的紋理圖片,通過隨機函數設置Gold的起始位置和運動,同時通過方法collideWithWolf檢測是否與Wolf對象碰撞。

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using cocos2d; 6 7 namespace LearningCocos2d_xForXNA.Classes 8 { 9 class Gold:CCSprite 10 { 11 public Gold(CCLayer layer) 12 { 13 Random rnd = new Random(); 14 float posionX = 100 * (float)rnd.Next(1, 4);//Gold起始位置X坐標值 15 this.initWithFile("img/Wolf/Others/gold"); 16 this.position = new CCPoint(posionX, 850);//Gold起始位置 17 layer.addChild(this); 18 this.runAction(CCMoveTo.actionWithDuration(5.0f, new CCPoint(posionX, -50)));//運動,垂直向下運動 19 } 20 21 /// <summary> 22 /// 創建檢測碰撞Rect 23 /// </summary> 24 /// <returns>返回用於檢測碰撞的Rect</returns> 25 public CCRect rect() 26 { 27 CCSize s = Texture.getContentSize();//Gold紋理的大小 28 return new CCRect(this.position.x, this.position.y, this.contentSize.width/2, this.contentSize.height/2);//設置Rect 29 } 30 31 /// <summary> 32 /// 檢測是否與Wolf對象碰撞 33 /// </summary> 34 /// <param name="wolf"></param> 35 /// <returns>碰撞返回true,否則返回false</returns> 36 public bool collideWithWolf(Wolf wolf) 37 { 38 CCRect wolfRect = wolf.rect(); 39 if(CCRect.CCRectIntersetsRect(wolfRect,rect()))//通過Rect是否相交判斷是否碰撞 40 { 41 return true; 42 } 43 return false; 44 } 45 } 46 }
Bomb:繼承CCSprite,構造方法中,添加各類的紋理圖片,通過隨機函數設置Bomb的起始位置和運動,同時通過方法collideWithWolf檢測是否與Wolf對象碰撞。

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using cocos2d; 6 7 namespace LearningCocos2d_xForXNA.Classes 8 { 9 class Bomb:CCSprite 10 { 11 public Bomb(CCLayer layer) 12 { 13 Random rnd = new Random(); 14 float posionX = 100 * (float)rnd.Next(1, 4);//Gold起始位置X坐標值 15 this.initWithFile("img/Wolf/Others/bomb"); 16 this.position = new CCPoint(posionX, 850);//Gold起始位置 17 layer.addChild(this); 18 this.runAction(CCMoveTo.actionWithDuration(5.0f, new CCPoint(posionX, -50)));//運動,垂直向下運動 19 } 20 21 /// <summary> 22 /// 創建檢測碰撞Rect 23 /// </summary> 24 /// <returns>返回用於檢測碰撞的Rect</returns> 25 public CCRect rect() 26 { 27 CCSize s = Texture.getContentSize();//Bomb紋理的大小 28 return new CCRect(this.position.x, this.position.y, this.contentSize.width/2, this.contentSize.height/2);//設置Rect 29 } 30 31 /// <summary> 32 /// 檢測是否與Wolf對象碰撞 33 /// </summary> 34 /// <param name="wolf"></param> 35 /// <returns>碰撞返回true,否則返回false</returns> 36 public bool collideWithWolf(Wolf wolf) 37 { 38 CCRect wolfRect = wolf.rect(); 39 if(CCRect.CCRectIntersetsRect(wolfRect,rect()))//通過Rect是否相交判斷是否碰撞 40 { 41 return true; 42 } 43 return false; 44 } 45 } 46 }
Wolf:繼承CCSprite和ICCTargetedTouchDelegate接口,構造方法中,返回對象的用於檢測碰撞的Rect。ICCTargetedTouchDelegate接口是為了實現觸摸屏使得Wolf移動(上講有講解)。在runing方法中實現Sprite跑動動畫。

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using cocos2d; 6 7 namespace LearningCocos2d_xForXNA.Classes 8 { 9 class Wolf:CCSprite, ICCTargetedTouchDelegate 10 { 11 /// <summary> 12 /// 創建檢測碰撞Rect 13 /// </summary> 14 /// <returns>返回用於檢測碰撞的Rect</returns> 15 public CCRect rect() 16 { 17 CCSize s = Texture.getContentSize();//Wolf紋理的大小 18 return new CCRect(this.position.x, this.position.y, this.contentSize.width / 2, this.contentSize.height / 2);//設置Rect 19 } 20 21 public override void onEnter() 22 { 23 CCTouchDispatcher.sharedDispatcher().addTargetedDelegate(this, 0, true); 24 base.onEnter(); 25 } 26 27 public override void onExit() 28 { 29 CCTouchDispatcher.sharedDispatcher().removeDelegate(this); 30 base.onExit(); 31 } 32 33 public virtual bool ccTouchBegan(CCTouch touch, CCEvent eventer) 34 { 35 return true; 36 } 37 38 public virtual void ccTouchMoved(CCTouch touch, CCEvent eventer) 39 { } 40 41 /// <summary> 42 /// 觸摸屏Ended事件 43 /// </summary> 44 /// <param name="touch"></param> 45 /// <param name="eventer"></param> 46 public virtual void ccTouchEnded(CCTouch touch, CCEvent eventer) 47 { 48 CCPoint touchPoint = touch.locationInView(touch.view()); 49 CCPoint convertedLocation = CCDirector.sharedDirector().convertToGL(touchPoint); 50 51 //執行運動 52 CCActionInterval move = CCMoveTo.actionWithDuration(2, convertedLocation); 53 CCActionInterval move_ease_inout = CCEaseInOut.actionWithAction(move);//ease緩沖 54 base.runAction(move_ease_inout); 55 } 56 57 public void ccTouchCancelled(CCTouch pTouch, CCEvent pEvent) 58 { 59 throw new NotImplementedException(); 60 } 61 62 public void runing(CCLayer cclayer) 63 { 64 #region Sprite跑動動畫 65 CCSize s = CCDirector.sharedDirector().getWinSize(); 66 // 創建批處理節點,讀取plist文件 67 CCSpriteBatchNode batch = CCSpriteBatchNode.batchNodeWithFile("plist/images/wolf_move");//批處理節點貼圖 68 cclayer.addChild(batch, 0, 1); 69 CCSpriteFrameCache.sharedSpriteFrameCache().addSpriteFramesWithFile("plist/wolf_move");//讀取plsit文件 70 //起始精靈 71 72 this.initWithSpriteFrameName("wolf_move1.png"); 73 this.position = (new CCPoint(s.width / 3, s.height / 2)); 74 batch.addChild(this); 75 // 創建逐幀數組 76 List<CCSpriteFrame> animFrames = new List<CCSpriteFrame>(); 77 string str = ""; 78 for (int i = 2; i < 8; i++) 79 { 80 string temp = ""; 81 temp = i.ToString(); 82 str = string.Format("wolf_move{0}.png", temp); 83 CCSpriteFrame frame = CCSpriteFrameCache.sharedSpriteFrameCache().spriteFrameByName(str); 84 animFrames.Add(frame); 85 } 86 //動畫Animate 87 CCAnimation animation = CCAnimation.animationWithFrames(animFrames, 0.2f);//Animation動畫信息 88 this.runAction(CCRepeatForever.actionWithAction(CCAnimate.actionWithAnimation(animation, false)));//執行動畫 89 #endregion 90 } 91 } 92 }
Layer層
在GameLayer中,構造方法中,實例化得分面板(記錄分數),初始化Wolf,然后通過調用schedule方法不斷地產生Gold和Bomb,在方法collide中不斷地檢測Wolf與Gold、Bomb的碰撞情況。

1 using System; 2 using System.Collections.Generic; 3 using System.Linq; 4 using System.Text; 5 using cocos2d; 6 7 namespace LearningCocos2d_xForXNA.Classes 8 { 9 class GameLayer:CCLayer 10 { 11 Random rnd=new Random();//隨機變量 12 const int likelihoodGold = 70;//產生Gold的比例 13 const int likelihoodBomb = 30;//產生Bomb的比例 14 CCLabelTTF lblScore;//文本,記錄游戲得分 15 int score;//得分 16 Wolf wolf;//主角 17 List<Gold> golds = new List<Gold>();//用於存儲Gold對象 18 List<Bomb> bombs = new List<Bomb>();//用於存儲Bomb對象 19 public GameLayer() 20 { 21 base.isTouchEnabled = true;//開啟觸屏事件 22 CCDirector.sharedDirector().deviceOrientation = ccDeviceOrientation.kCCDeviceOrientationPortraitUpsideDown;//設置朝向,豎屏 23 24 //得分 25 score = 0; 26 lblScore = CCLabelTTF.labelWithString(string.Format("得分:{0}",score), "Yahei", 30); 27 lblScore.position = new CCPoint(100, 100); 28 this.addChild(lblScore); 29 30 wolf = new Wolf(); 31 wolf.runing(this);//Sprite跑動動畫 32 33 this.schedule(CreateGoldOrBomb, 3.0f);//每隔3.0秒調用函數,類似線程 34 this.schedule(collide);//默認下1.0/60s執行 35 36 } 37 38 /// <summary> 39 /// 創建Gold對象 40 /// </summary> 41 /// <param name="dt">時間間隔</param> 42 public void CreateGoldOrBomb(float dt) 43 { 44 int random = rnd.Next(1, 100);//產生1-100間隨機數 45 if (random < 30)//產生Bomb 46 { 47 Bomb bomb = new Bomb(this); 48 bombs.Add(bomb); 49 } 50 else//產生Gold 51 { 52 Gold gold = new Gold(this); 53 golds.Add(gold); 54 } 55 } 56 57 /// <summary> 58 /// 碰撞檢測 59 /// </summary> 60 /// <param name="dt"></param> 61 public void collide(float dt) 62 { 63 for (int i = 0; i < golds.Count; i++)//遍歷golds 64 { 65 if (golds[i].collideWithWolf(wolf))//調用Gold判斷碰撞的方法,如果碰撞返回true,否則返回false 66 { 67 removeChild(golds[i], true);//將碰撞的Gold節點移除 68 golds.RemoveAt(i);//移除泛型golds中節點 69 lblScore.setString(string.Format("得分:{0}", (++score).ToString().Trim()));//得分 70 } 71 } 72 for (int i = 0; i < bombs.Count; i++)//遍歷bombs 73 { 74 if (bombs[i].collideWithWolf(wolf))//調用Bomb判斷碰撞的方法,如果碰撞返回true,否則返回false 75 { 76 removeChild(bombs[i], true);//將碰撞的Bomb節點移除 77 bombs.RemoveAt(i);//移除泛型bombs中節點 78 lblScore.setString(string.Format("得分:{0}", (--score).ToString().Trim()));//扣分 79 } 80 } 81 } 82 } 83 }
進行游戲
游戲中,觸摸屏幕操作Wolf的移動,去吃Gold得分,避開Bomb。
著作權聲明:本文由http://www.cnblogs.com/suguoqiang 原創,歡迎轉載分享。請尊重作者勞動,轉載時保留該聲明和作者博客鏈接,謝謝!