基于cocos2d-x对俯视角游戏碰撞检测及碰撞处理的探究
来源:互联网 发布:淘宝友臣肉松饼是假的 编辑:程序博客网 时间:2024/04/28 14:30
作者:i_dovelemon
来源:CSDN
日期:2015/2/10
主题:俯视角游戏,碰撞检测,碰撞处理
引言
对于任何游戏来说,碰撞检测和碰撞处理都是非常重要的内容。最近自己在编写一个俯视角的类rouge-like的游戏。游戏基于网格来设计地图,在游戏设计过程中,尤其是在设计游戏的碰撞系统的时候遇到了麻烦。经过多方面的努力,终于解决了问题,现在就此问题,记录下我的心得和体会。
碰撞检测
在我的游戏中,大部分的时候都是使用AABB-AABB这种碰撞盒来进行碰撞。对于此种的碰撞体,在前面的文章中也讲述过了,有很多的描述方式。我选用的是Max-Min的描述方式,即使用一个最大点Max和一个最小点Min。这样对于两个AABB盒,我们只要简单的使用下面的代码就能够判断是否发生碰撞了:
bool AABB::intersectWithAABB(AABB aabb){ if(aabb.vMax.x < m_vMin.x) return false ; if(aabb.vMax.y < m_vMin.y) return false ; if(aabb.vMin.x > m_vMax.x) return false ; if(aabb.vMin.y > m_vMax.y) return false ; return true ;}// end for intersectWithAABB
对于AABB碰撞盒来说,这种检测方式最简单,也最实用。
碰撞处理
思路由来
正如大家看到的一样,这样的游戏碰撞检测是非常容易的,我在编写的时候,也是如上所示那样编写的。但是,我在进行碰撞处理的时候,即发生玩家与障碍物发生碰撞之后,该如何反应上面遇到了问题。我原先的方案在实际运行之后,发现玩家会在地图上乱窜,完全没有碰到障碍物的那种感觉。所以为了更好的研究这个问题的解决方案,我另外开辟了一个应用程序来专门对这个问题进行了研究。
那么,该使用什么样的处理方法才能够很合适的碰撞了?在考虑这个问题的时候,我发现在我以前写的游戏Demo中,我总会给游戏加上一个世界的边界,大多时候是一个矩形来完成的。我控制一个矩形在这个大的矩形世界里面到处移动。当移动到边缘的时候,我会检测它是否超出了大的矩形世界的边缘,然后强制的将玩家的位置设置到刚好和矩形世界边缘触碰的位置处。而在使用这样的方法之后,发现我们控制的小矩形能够很好的与矩形世界进行碰撞反应。
实际测试
在明白了上面的那个处理方法能够带来比较好的效果之后,我就想:能不能使用同样的思路,在我的游戏中,当我们检测到碰撞的时候,只要强制的将玩家放在一个刚好触碰的障碍物的位置就可以了。为此,我马上在新开辟的应用程序中编写了如下的代码:
#ifndef __HELLOWORLD_SCENE_H__#define __HELLOWORLD_SCENE_H__#include "cocos2d.h"class HelloWorld : public cocos2d::CCLayer{public: // Here's a difference. Method 'init' in cocos2d-x returns bool, instead of returning 'id' in cocos2d-iphone virtual bool init(); // there's no 'id' in cpp, so we recommand to return the exactly class pointer static cocos2d::CCScene* scene(); // a selector callback void menuCloseCallback(CCObject* pSender); // implement the "static node()" method manually CREATE_FUNC(HelloWorld); // void update(float dt) ; void collisionTest1(); void collision();private: cocos2d::CCSprite* m_pWalls[10] ; cocos2d::CCSprite* m_pRole ;};#endif // __HELLOWORLD_SCENE_H__#include "HelloWorldScene.h"using namespace cocos2d;CCScene* HelloWorld::scene(){ CCScene * scene = NULL; do { // 'scene' is an autorelease object scene = CCScene::create(); CC_BREAK_IF(! scene); // 'layer' is an autorelease object HelloWorld *layer = HelloWorld::create(); CC_BREAK_IF(! layer); // add layer as a child to scene scene->addChild(layer); } while (0); // return the scene return scene;}// on "init" you need to initialize your instancebool HelloWorld::init(){ bool bRet = false; do { ////////////////////////////////////////////////////////////////////////// // super init first ////////////////////////////////////////////////////////////////////////// CC_BREAK_IF(! CCLayer::init()); ////////////////////////////////////////////////////////////////////////// // add your codes below... ////////////////////////////////////////////////////////////////////////// m_pRole = CCSprite::create("Wood.png"); addChild(m_pRole); m_pRole->setPosition(ccp(100,100)); memset(m_pWalls,0,sizeof(CCSprite*) * 6); m_pWalls[0] = CCSprite::create("Wall.png"); m_pWalls[0]->setPosition(ccp(160,120)); addChild(m_pWalls[0]); m_pWalls[1] = CCSprite::create("Wall.png"); m_pWalls[1]->setPosition(ccp(160,120+32)); addChild(m_pWalls[1]); m_pWalls[2] = CCSprite::create("Wall.png"); m_pWalls[2]->setPosition(ccp(160+32,120+62)); addChild(m_pWalls[2]); m_pWalls[3] = CCSprite::create("Wall.png"); m_pWalls[3]->setPosition(ccp(160+64,120-32)); addChild(m_pWalls[3]); scheduleUpdate(); bRet = true; } while (0); return bRet;}void HelloWorld::menuCloseCallback(CCObject* pSender){ // "close" menu item clicked CCDirector::sharedDirector()->end();}void HelloWorld::update(float dt){ CCPoint pos = m_pRole->getPosition(); if(GetKeyState(VK_UP) & 0x8000) { pos.y += 3 ; } else if(GetKeyState(VK_DOWN) & 0x8000) { pos.y -= 3 ; } if(GetKeyState(VK_LEFT) & 0x8000) { pos.x -= 3 ; } else if(GetKeyState(VK_RIGHT) & 0x8000) { pos.x += 3 ; } m_pRole->setPosition(pos); collision();}// end for updatevoid HelloWorld::collision(){ for(int i = 0 ; i < 10 ; i ++) { if(0 == m_pWalls[i]) break ; //check if they collided if(m_pRole->boundingBox().intersectsRect(m_pWalls[i]->boundingBox())) { CCPoint rolePos = m_pRole->getPosition(); CCPoint wallPos = m_pWalls[i]->getPosition(); CCPoint temp = ::ccpSub(rolePos, wallPos); if(abs(temp.x) > abs(temp.y)) { if(rolePos.x >= wallPos.x && wallPos.x + 16 + 16 >= rolePos.x) { rolePos.x = wallPos.x + 16 + 16 ; } else if(rolePos.x <= wallPos.x && rolePos.x + 16 + 16 >= wallPos.x) { rolePos.x = wallPos.x - 16 - 16 ; } } else { if(rolePos.y >= wallPos.y && rolePos.y - 16 - 16 <= wallPos.y) { rolePos.y = wallPos.y + 16 + 16 ; } else if(rolePos.y <= wallPos.y && rolePos.y + 16 + 16 >=wallPos.y) { rolePos.y = wallPos.y - 16 - 16 ; } } m_pRole->setPosition(rolePos); } }//end for}// end for collision
上面的代码就是经过考虑之后,编写出来的代码,运行检测之后发现的确能够很好的工作,如图所示:
上图中红色的代表玩家,另外一个代表障碍物
碰撞处理要点
在实现这种方案的过程中,我也经过了多次尝试才成功。接下来向大家讲述下这种方案的处理要点。
第一点:
首先我们要确定玩家到底在哪个方向上与障碍物发生了碰撞。这个检测方案十分的简单,我们只要获取玩家和障碍物之间的位置的向量差,即上面代码中的:
CCPoint rolePos = m_pRole->getPosition();CCPoint wallPos = m_pWalls[i]->getPosition();CCPoint temp = ::ccpSub(rolePos, wallPos);
这个temp就是玩家位置与障碍物位置之间的向量差。在获取了这个向量差之后,我们只要比较下这个向量差的X和Y轴的分量的绝对值的大小,就能够知道,玩家是在哪个方向上与障碍物碰撞在一起的。比如,当X轴的分量绝对值大于Y轴的值的时候,就表示玩家是与障碍物在X轴向上碰撞的,反之则是在Y轴向上发生了碰撞。如果对这个描述不是很理解,看下下图:
第二点:
在知道了是哪个方向上发生了碰撞之后,我们就需要判断玩家是从左向右撞击,还是从右向左撞击,亦或者从上往下撞击,还是从下往上撞击。这就下面的判断代码的由来:
if(rolePos.x >= wallPos.x &&wallPos.x + 16 + 16 >= rolePos.x){ rolePos.x = wallPos.x + 16 + 16 ;}else if(rolePos.x <= wallPos.x && rolePos.x + 16 + 16 >= wallPos.x){ rolePos.x = wallPos.x - 16 - 16 ;}andif(rolePos.y >= wallPos.y &&rolePos.y - 16 - 16 <= wallPos.y){ rolePos.y = wallPos.y + 16 + 16 ;}else if(rolePos.y <= wallPos.y && rolePos.y + 16 + 16 >=wallPos.y){ rolePos.y = wallPos.y - 16 - 16 ;}
第三点:
在你实现了前面描述的两点之后,基本上已经能够完成功能了,但是要注意的是,上面第二点中判断的“==”条件一定不能省略,否则会出现意想不到的情况。
好了,这个问题就讲解这么多。关于如果游戏中使用了其他的诸如Sphere和OBB碰撞体,又该如何解决的问题,等到我以后遇到,并且找到解决方案之后在分享给大家!!!
- 基于cocos2d-x对俯视角游戏碰撞检测及碰撞处理的探究
- cocos2d-x的碰撞检测
- cocos2d-x游戏开发系列教程-坦克大战游戏之子弹的碰撞检测处理
- Cocos2d-X 游戏之碰撞检测的方法
- 【cocos2d-x游戏开发】物体的碰撞检测
- cocos2d-x 碰撞检测
- cocos2d-x 碰撞检测
- cocos2d-x 检测碰撞
- Cocos2d-x碰撞检测
- <cocos2d-x for wp7>使用cocos2d-x制作基于Tile地图的游戏:碰撞检测和收集物品(二)
- cocos2d-x中矩形的碰撞检测
- Cocos2d-X 碰撞检测的使用方法
- 基于cocos2d-x的跑酷游戏,不同高度地面的碰撞检测demo,有兴趣可以看一看
- cocos2d-x如何检测碰撞
- cocos2d-x 矩形碰撞检测
- Cocos2d-x如何检测碰撞
- cocos2d-x 检测矩形碰撞
- cocos2d-x中的碰撞检测
- TCP/IP协议中分包与重组原理介绍
- Android应用程序资源的编译和打包过程分析
- Android ADB server didn't ACK * failed to start daemon * 简单有效的解决方案
- 主机无法ping通虚拟机
- Mysql中的 的 Cascade ,NO ACTION ,Restrict ,SET NULL
- 基于cocos2d-x对俯视角游戏碰撞检测及碰撞处理的探究
- nginx-简介
- 面试
- 云计算浪潮汹涌,成IT业转型利器
- android系统触摸屏虚拟按键
- sum()over()和count()over()分析函数
- 新兴短距离无线通信技术ZigBee入门到进阶
- 关于U盘安装Fedora Server 21时Failed to load ldlinux.c32的解决方案
- 【iOS代码块】项目中常用的动画效果