Cocos2d-x 3.0 开发(九)使用Physicals代替Box2D和chipmunk

标签: cocos2d-x 3.0 物理引擎 Physicals Cocos2d-x box2d
42748人阅读 评论(41) 收藏 举报
分类:

1、   概述

    游戏中模拟真实的世界是个比较麻烦的事情,通常这种事情都是交给物理引擎来做。首屈一指的是Box2D了,它几乎能模拟所有的物理效果。而chipmunk则是个更轻量的引擎,能够满足简单的物理需求,比如最常用的的碰撞检测等。这些引擎在使用的过程中有个令人讨厌的地方,它们参数太多了。通常为了初始化一个简单的场景要写很多代码。在cocos2d-x 3.0版本中,出现了一个新类族——physicals。它将Box2D或者chipmunk做了一层封装,使我们的上层调用有更友好的接口。它通过宏来切换使用哪种物理引擎,目前的版本只有chipmunk的实现,Box2D的实现没有写,所以手动将宏切换的话是不行的。另外,当前版本还是有bug的,下面会提到,先看效果图吧:




2、 原理分析


    相信大家都对物理引擎的使用有所了解,篇幅有限,一些基本概念就不复述了。如果你曾经用过Box2D或者chipmunk,再使用这套封装,你只会有一种爽到爆的感觉。

    在这个版本中,物理世界的概念被加入到Scene中,即当创建一个场景时,就可以指定这个场景是否使用物理引擎。相对应的,每一个Sprite中也有body的概念。可以直接将body关联到Sprite上。Listener当然也不需要再弄一套东西来监听,只要注册到场景中就可以了。

    不知你听到这个改动有和感想,反正我是震惊了。

    接下来我们动手做一个吧。


3、创建场景


    首先,运行脚本创建一个新工程:testNewPhy,编译运行确保一切正常。 

    找到 CreateScene函数,更改scene的初始化。

Scene* HelloWorld::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::createWithPhysics();
    scene->getPhysicsWorld()->setDebugDraw(true); //此句仅3.0 alpha0 有效
    scene->getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);

    
    // 'layer' is an autorelease object
    auto layer = HelloWorld::create();

    // add layer as a child to scene
    scene->addChild(layer);

    // return the scene
    return scene;
}

    更改create,创建一个支持物理的世界,打开debugDraw。两行就可以搞定了。

    打开debugDrawMask,两行就可以搞定了。DrawMask参数可以选择打开绘制哪些部分比如,Joint、Shape等等。    

    接下来,我们要将这个World传到Layer中。所以我们在HelloWorld类中加入一个函数。将这个world存起来。 

//……
	 void setPhyWorld(PhysicsWorld* world){m_world = world;}
private:
	PhysicsWorld* m_world;
}

    同时在creatScene创建layer完成后,将这个值设定上。

 // ……
    auto layer = HelloWorld::create();
    layer->setPhyWorld(scene->getPhysicsWorld());
// ……


    另外,我们更改一下menuItem的响应,来控制debugDraw的绘制:


  此函数已在3.0 alpha1中失效

void HelloWorld::menuCloseCallback(Object* pSender)
{
	if(m_world->isDebugDraw())
	{
		 m_world->setDebugDraw(false);
	}
	else
	{
		m_world->setDebugDraw(true);
	}
}

    使用如下函数

void HelloWorld::menuCloseCallback(Object* pSender)
{
	if(m_world->getDebugDrawMask() != PhysicsWorld::DEBUGDRAW_NONE)
	{
		 m_world->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_NONE);
	}
	else
	{
		m_world->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL);
	}

}

    

4、创建边界

    创建了物理世界,还要有东西才行。接下来,我们着手创建一个边界。我们可以方便的使用PhysicalsBody的create方法创建自己想要的物体。 

    在init中进行更改: 

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //////////////////////////////
    // 1. super init first
    if ( !Layer::init() )
    {
        return false;
    }
    
    Size visibleSize = Director::getInstance()->getVisibleSize();
    Point origin = Director::getInstance()->getVisibleOrigin();

    /////////////////////////////
   
	auto edgeSp = Sprite::create();
	auto body = PhysicsBody::createEdgeBox(visibleSize,3); //此句仅3.0 alpha0 有效
        auto body = PhysicsBody::createEdgeBox(visibleSize,PHYSICSBODY_MATERIAL_DEFAULT,3);
        edgeSp->setPosition(Point(visibleSize.width/2,visibleSize.height/2));
        edgeSp->setPhysicsBody(body);this->addChild(edgeSp);edgeSp->setTag(0);
        return true;
}

    其中,PHYSICSBODY_MATERIAL_DEFAULT宏表示的是创建的Body的默认材质,3是边线宽度。编译运行我们会看到场景边上有红色的边界。




5、添加元素

    我们先将点击响应搭建起来,在init中将touchEnable设置为true,重新onTouchesEnd方法:

void HelloWorld::onTouchesEnded(const std::vector<Touch*>& touches, Event *event)
{
	for(auto touch:touches)
	{
		auto location = touch->getLocation();
		addNewSpriteAtPosition(location);
	}
}

    然后我们来实现addNewSpriteAtPosition函数。关联body与sprite从未如此简单,我们只需创建一个body,创建一个sprite然后将body设置为sprite的body即可。 

void HelloWorld::addNewSpriteAtPosition(Point p)
{    
    auto sp = Sprite::create("1.png");
    sp->setTag(1);
    auto body = PhysicsBody::createBox(Size(80, 40));
    sp->setPhysicsBody(body);	
    sp->setPosition(p);
    this->addChild(sp);
}

    在这其中,当前版本的cocos2d-x 3.0有一个小问题。关联的时候,并未将body相应的owner设置为对应的sprite,我们需要修改sprite.cpp中的setPhysicsBody这个函数。增加最后一行。此bug已修复

void Sprite::setPhysicsBody(PhysicsBody* body)
{
    _physicsBody = body;
    _physicsBody->retain();
    _physicsBody->setPosition(getPosition());
    _physicsBody->setRotation(getRotation());
    _physicsBody->_owner = this;
}

     编译运行,我们点击屏幕即可动态创建元素了。




6、碰撞检测

    碰撞检测的回调是在world中注册函数来实现的。首先我们在HelloWorld中声明一个变量。并重写OnEnter方法。

    碰撞检测的回调是在Scene中注册Listener来实现的。当有碰撞发生时,就会调用对应的Listener。所有的碰撞都使用EventListenerPhysicsContact类。我们可以通过重写它的onContactBegin、onContactPreSolve、onContactPostSolve、onContactSeperate方法来更改它的行为。

    下面函数已失效

//声明
PhysicsContactListener m_listener;

//实现

void HelloWorld::onEnter()
{
	Layer::onEnter();

	m_listener.onContactBegin = [=](const PhysicsContact& contact)
	{
		auto cnt = const_cast<PhysicsContact*>(&contact);

		auto sp = cnt->getShapeA()->getBody()->getOwner();
		int tag = sp->getTag();
		if(tag == 1)
		{
			Texture2D *texture = TextureCache::getInstance()->addImage("2.png");
			sp->setTexture(texture);
		}

		sp = cnt->getShapeB()->getBody()->getOwner();
		tag = sp->getTag();
		if(tag == 1)
		{
			Texture2D *texture = TextureCache::getInstance()->addImage("1.png");
			sp->setTexture(texture);
		}
		return true;
	};
	m_world->registerContactListener(&m_listener);
}

    应使用:

void HelloWorld::onEnter()
{
	Layer::onEnter();
	auto listener = EventListenerPhysicsContact::create();
	listener->onContactBegin = [=](EventCustom* event, const PhysicsContact& contact)
	{
		auto sp = (Sprite*)contact.getShapeA()->getBody()->getNode();
		int tag = sp->getTag();
		if(tag == 1)
		{
			Texture2D *texture = TextureCache::getInstance()->addImage("2.png");
			sp->setTexture(texture);
		}

		sp = (Sprite*)contact.getShapeB()->getBody()->getNode();
		tag = sp->getTag();
		if(tag == 1)
		{
			Texture2D *texture = TextureCache::getInstance()->addImage("1.png");
			sp->setTexture(texture);
		}
		return true;
	};	
	Director::getInstance()->getEventDispatcher()->addEventListenerWithFixedPriority(listener,10); //第二个参数是优先级,10是随意写的
}


    其中,我们将listener的onContactBegin方法重写。并通过shape->body->owner的方式来取到sprite。更改它的显示。最后将listener注册到m_world中。

    编译运行,然后点击menuItem,将debugDrow关闭,即可。


7、总结

    通过创建一个支持Physicals的场景,来创建物理系统。将body创建出来,并调用sprite的setPhysicsBody来为一个sprite设定body。通过PhysicsContactListener来创建一个Listener并通过registerContactListener将其注册,来处理碰撞。

 

    Demo下载:http://download.csdn.net/detail/fansongy/6502401

    Demo 下载(3.0 alpha1版本):http://download.csdn.net/detail/fansongy/6652089


    本篇博客出自阿修罗道,转载请注明出处,禁止用于商业用途http://blog.csdn.net/fansongy/article/details/14142323  




查看评论

box2d 在lua中的运用(Box2D物理引擎)

* 全局的对象的构造函数作了三件事情: * 1、一个在b2AABB类中的实例构建的坐标系统 * 2、一个定义重力的向量,这是一个b2Vec2类构建的实例。 * 3、一个布尔变量来定义...
  • fuwenyihao
  • fuwenyihao
  • 2014-05-06 17:11:54
  • 793

我在Cocos2d-x luabinding box2d时挖到过的坑

我在Cocos2d-x luabinding box2d时挖到过的坑
  • jiaohougenyang
  • jiaohougenyang
  • 2015-12-02 20:58:48
  • 853

物理引擎比较:Box2D 对比 Chipmunk

Cocos2d 自带了两套物理引擎:Box2D 和 Chipmunk。那么我们应该选择哪一个呢? 很多情况下,这个选择取决于个人口味。很多游戏开发者对这两个物理引擎的 争论集中于它们所用的编程语言:...
  • benbenxiongyuan
  • benbenxiongyuan
  • 2014-08-29 22:03:59
  • 3346

Cocos-js 之 使用Chipmunk实现碰撞 和 碰撞的监听

这两天在用cocos-js  开发一个一堆小球碰来碰去的游戏,就打算选择一款物理引擎来简化代码。第一开始打算用box2d(网上一片好评),但是看看之后发现box2d适用于js-HTML版本,对js打包...
  • u013647453
  • u013647453
  • 2015-07-17 18:54:35
  • 1769

cocos2dx-3.0 中的物理引擎Box2D使用(四)

~~~~我的生活,我的点点滴滴!!
  • AC_huang
  • AC_huang
  • 2014-09-03 00:30:44
  • 1604

【COCOS2DX-BOX2D游戏开发之一】Box2d概念

1.cocos2d 自带了两套物理引擎:Box2D 和Chipmunk。  两套引擎都是为2D游戏设计的,可以和cocos2d 完美整合。  Box2D 是用 C++写的,而 Chipmunk 用...
  • teng_ontheway
  • teng_ontheway
  • 2014-03-18 14:39:27
  • 12847

cocos2d-x节点(CCPhysicsBody.h)API

本文来自http://blog.csdn.net/runaying ,引用必须注明出处! cocos2d-x节点(CCPhysicsBody.h)API 温馨提醒:为了大家能更好学习,强烈推荐大...
  • runaying
  • runaying
  • 2013-12-02 15:58:44
  • 2211

Box2D和Chipmunk

物理的表现力对游戏的影响越来越重要,几乎已经是现在游戏中不可获取的要素之一,如果进入游戏开发的物理世界中,你会发现这是一个深不可测的领域,没个十几年的功力怕是难说出个头道来的,不过再难总要去面对和挑战...
  • tspangle
  • tspangle
  • 2014-04-15 08:57:17
  • 4646

Lua_物理引擎

require "Cocos2d" require "Cocos2dConstants" -- for CCLuaEngine traceback function __G__TRACKBACK__...
  • c201038795050
  • c201038795050
  • 2015-04-28 00:50:33
  • 1181

cocos2dx 3.x使用Box2d

众所周知cocs2dx 3.x中有个Physics的封装,本意可能是想同时封装chipmunk和box2d,但为什么只实现了chipmunk就不管box2d了呢。。 最近尝试了一下,chipmunk...
  • zhanhuai1
  • zhanhuai1
  • 2017-04-09 16:23:12
  • 802
    个人资料
    专栏达人 持之以恒 微软MVP
    等级:
    访问量: 227万+
    积分: 1万+
    排名: 639
    关于

    左手代码右手艺术 追求新浪潮。


    个人网站:blog.songyang.net


    开源项目:


    UIAP : Unity3D内购插件

    UExtend : Unity3D常用功能合集


    微信公众号:松阳论道



    微博:

    我写的书:


    实例妙解Cocos2d-x游戏开发
    博客专栏
    最新评论