微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

Cocos2dx 学习笔记 -TMX和物理引擎的结合

Cocos2dx 学习笔记 -TMX和物理引擎的结合

我使用的 cocos2dx 引擎的版本是3.3.4
尽管Cocos2dx提供了两套物理引擎,但是用的更多的是Box2的,在IOS平台上多使用chipmunk。
这次我的目标是将TMX地图文件加载到内存中,然后为每个TMX地图中的小方块生成物理形状从而为自己编写的跑酷游戏加上物理引擎。
引擎中现在Scene类提供了静态方法可以生成带有物理的场景。
Scene::initWithPhysics()
这个方法可以让场景具有创建物理世界的基本条件,在跑酷游戏中需要重力的影响,所以应该把场景的重力设置出来。

PhysicsWorld* world=getPhysicsWorld();
world->setGravity(Vec2(0,-10));

然后我们要给物理世界创造一个边界,同时把游戏逻辑和物理场景分开,新建一个Layer的子类来写游戏逻辑。
文件如下:

#pragma once
#include <string>
#include "cocos2d.h"
#include "Box2D\Box2D.h"
USING_NS_CC;

class PhyLayer :
    public Layer
{
public :
    Sprite * ball;
    Sprite * edgeSp;
    //sprite * prop;
    PhysicsBody* ballBody;
    TMXTiledMaP* map;
    Sprite* batS;
    int mapdx;
    CREATE_FUNC(PhyLayer);
    bool init();//初始化函数
    void loadPhyBody();//加载物理元素
    void loadTileMap();//加载地图
    void update(float tt);
    void contact();
public:
    PhyLayer();
    ~PhyLayer();
};

这是CPP文件

#include "PhyLayer.h"


PhyLayer::PhyLayer()
{
}


PhyLayer::~PhyLayer()
{
}
bool PhyLayer::init()
{
    if (!Layer::init())
        return false;
    loadTileMap();
    loadPhyBody();
    mapdx = 5;
    return true;
}
void PhyLayer::loadPhyBody()
{
    auto visibleSize = Director::getInstance()->getVisibleSize();
    auto origin = Director::getInstance()->getVisibleOrigin();
    edgeSp = Sprite::create();
    auto boundBody = PhysicsBody::createEdgeBox(visibleSize,PhysicsMaterial(0.0f,1.0f,0.0f),3);
    edgeSp->setPosition(visibleSize.width / 2,visibleSize.height / 2);
    edgeSp->setPhysicsBody(boundBody);
    addChild(edgeSp);

    ball = Sprite::create("ball.png");
    ball->setPosition(100,100);
    ballBody = PhysicsBody::createCircle(ball->getContentSize().width / 2,0.0f));
    ballBody->setContactTestBitmask(0xFFFFFFFF);
    Vect force = Vect(100.0f,100.0f);
    ballBody->applyImpulse(force);
    ballBody->setVeLocity(Vec2(150,150));
    ball->setPhysicsBody(ballBody);
    addChild(ball);

    batS = Sprite::create("block.png");
    PhysicsBody* batBody = PhysicsBody::createEdgeBox(batS->getContentSize(),0.0f));
    batS->setPosition(visibleSize.width / 2,50);
    batS->setZOrder(0);
    addChild(batS);
    batBody->setContactTestBitmask(0xFFFFFFFF);
    EventListenerTouchOneByOne * ev1 = EventListenerTouchOneByOne::create();
    ev1->onTouchBegan = [](Touch* touch,Event* ev){return true; };
    ev1->onTouchMoved = [&](Touch* touch,Event* ev)
    {
        float x = touch->getDelta().x;
        batS->setPositionX(batS->getPositionX() + x);
    };
    Director::getInstance()->getEventdispatcher()->addEventListenerWithSceneGraPHPriority(ev1,this);
    contact();
    schedule(schedule_selector(PhyLayer::update));
}
void PhyLayer::loadTileMap()
{
    map = TMXTiledMap::create("map.tmx");
    map->setPositionX(getPositionX() + 20);
    TMXLayer *layer = map->getLayer("map1");
    addChild(map);
    for (int i = 0; i < 80; i++)
    {
        for (int j = 0; j < 20; j++)
        {
            int gid = layer->getTileGIDAt(Vec2(i,j));
            if (gid == 0)
            {
                Sprite* sprite = layer->getTileAt(Vec2(i,j));
                if (!sprite)
                {
                    return;
                }
                PhysicsBody* body = PhysicsBody::createEdgeBox(sprite->getContentSize(),0.0f));
                sprite->setTag(3);
                body->setContactTestBitmask(0xFFFFFFFF);
                sprite->setPhysicsBody(body);
            }
        }
    }
}

void PhyLayer::update(float tt)
{
    int const spd = 50;
    float x = ballBody->getVeLocity().x;
    float y = ballBody->getVeLocity().y;
    if (x != spd && x != -spd)
    {
        if (x < 0)
            x = -spd;
        else
            x = spd;
    }
    if (y != spd && y != -spd)
    {
        if (y < 0)
            y = -spd;
        else
            y = spd;
    }
    ballBody->setVeLocity(Vec2(x,y));

    map->setPositionX(map->getPositionX() - 2);

}
void PhyLayer::contact()
{
    EventListenerPhysicsContact *evContact = EventListenerPhysicsContact::create();
    evContact->onContactBegin = [](PhysicsContact& contact)    -> bool
    {
        auto bodyA = (Sprite*)(contact.getShapeA()->getBody()->getNode());
        auto bodyB = (Sprite*)(contact.getShapeB()->getBody()->getNode());
        if (bodyA->getTag() == 3)
        {

        }
        if (bodyB->getTag() == 3)
        {

        }
        return true;
    };
    _eventdispatcher->addEventListenerWithSceneGraPHPriority(evContact,this);


}

其中我要说明的其中的lamda表达式,在C++中的lambda表达式可以看下面的图示

1.lambda-introducer (捕获字段)
2.lambda-parameter-declaration-list(变量列表)
3.mutable-specification(变量是否可以修改,这部分可以省略不写)
4.exception-specification(抛出的异常声明,可以省略不写)
5.lambda-return-type-clause(返回值类型,可以省略不写)
6.compound-statement(函数体部分)
其中捕获字段是[]时,表达式函数体部分是不能访问外部变量的。如果要使得函数体部分可以访问外部变量,可以使用&或者=,其中&表示按引用访问,=表示按值访问,可以指明具体要访问的变量也可不写访问当前所有作用域下的变量。

参数列表

lambda表达式的参数列表基本和函数的一致,不过有如下限制:

参数列表不能有认参数
不能是可变参数列表
所有的参数必须有个变量名
能否修改捕获的变量

如果在参数列表后加上了 mutable,则表示表达式可以修改按值捕获的外部变量的拷贝。

异常设置

函数一样,可以用 throw 来限定表达式能够抛出哪些异常。

返回类型

如果设置返回类型,你需要在类型名前面加上 ->。如果你只有一个返回语句的话,返回类型可以省略,编译器将会为你做出判断。

函数

lambda表达式的函数体和普通函数大致相同。

原文地址:https://www.jb51.cc/cocos2dx/343719.html

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。

相关推荐