首页 > 其他 > 详细

cocos基础教程(13)使用Physicals代替Box2D和chipmunk

时间:2015-09-24 19:08:32      阅读:266      评论:0      收藏:0      [点我收藏+]

1、   概述

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

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,创建一个支持物理的世界,打开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的绘制:

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);  
}  

6、碰撞检测

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

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将其注册,来处理碰撞。

原文博客地址:http://blog.csdn.net/fansongy/article/details/14142323

cocos基础教程(13)使用Physicals代替Box2D和chipmunk

原文:http://www.cnblogs.com/damowang/p/4836237.html

(0)
(0)
   
举报
评论 一句话评论(0
关于我们 - 联系我们 - 留言反馈 - 联系我们:wmxa8@hotmail.com
© 2014 bubuko.com 版权所有
打开技术之扣,分享程序人生!