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。

GameScene
 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对象碰撞。

Gold
 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对象碰撞。

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 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跑动动画。

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 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的碰撞情况。

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 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 原创,欢迎转载分享。请尊重作者劳动,转载时保留该声明和作者博客链接,谢谢!

posted @ 2013-03-04 09:40  Ghost Soar  阅读(2024)  评论(6编辑  收藏  举报