Learning Cocos2d-x for XNA(9)——碰撞检测
游戏中碰撞的检测相当重要,任何两个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 原创,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!