第十二章物理引擎

Cocos2d-x学习笔记


使用物理引擎

物理引擎能够模仿真实世界物理运动规律,使得精灵做出自由落体、抛物线运动、互相碰撞、反弹等效果,使用物理引擎还可以进行准确的碰撞检测。

物理引擎核心概念

物理引擎核心概念

  • 世界(World):游戏中的物理世界。
  • 物体(Body):构成物理世界的基础,具有位置、旋转角度等的特性,它上面的任何两点之间的距离都是完全不变的,也可以称为刚体(rigid body)。
  • 形状(Shape):物体的形状。一个依附于物体的二维碰撞几何结构,具有摩擦和弹性等材料属性。由于物体被抽象成刚体,忽略了形状。但是物体间的摩擦和碰撞时与形状有关的,这时候需要将形状依附于物体上。
  • 接触点(Contact):管理检测碰撞。
  • 关节(Joint):把两个或多个物体固定到一起的约束。

物理引擎与精灵关系

物理引擎本身不包括精灵,它与精灵关系之间是相互独立的,精灵不会自动跟着物理引擎中的物体做物理运动,通常需要编写代码将物体与精灵连接起来,同步它们的状态。

Cocos2d-x 3.x中物理引擎封装

Cocos2d-x 3.x 物理引擎API

在Cocos2d-x 3.x 中物理世界被融入游戏引擎的场景中,我们可以指定这个场景是否使用物理引擎,为此创建类Scene增加如下函数:

  • static Scene * createWithPhysics():创建场景对象。
  • bool initWithPhysics():初始化具有物理引擎场景对象。
  • void addChlidToPhysicsWorld(Node * child):增加节点对象到物理世界。
  • PhysicsWorld * getPhysicsWorld():获得物理世界对象。

Cocos2d-x 3.x 在节点类Node中增加了physicsBody属性,我们可以将物理引擎中的物体添加到Node对象中。
此外,Cocos2d-x 3.x为物理引擎增加了很多类,其中主要的类如下:

  • PhysicsWorld类:封装物理引擎世界(World)。
  • PhysicsBody类:封装物理引擎物体(Body)。
  • PhysicsShape类:封装物理疫情形状(Shape)。
  • PhysicsContact类:封装物理引擎碰撞类(Contact)。
  • EventListenerPhysicsContact类:碰撞检测监听类。
  • PhysicsJoint类:封装物理引擎关节(Joint)。

PhysicsShape类

形状类PhysicsShape是一个抽象类,它有很多子类:

  • PhysicsShapeCircle:圆圈。
  • PhysicsShapeBox:矩形盒子。
  • PhysicsShapePolygon:多边形。
  • PhysicsShapeEdgeSegment:有边的线段。
  • PhysicsShapeEdgeBox:有边的矩形盒子。
  • PhysicsShapeEdgePolygon:有边的多边形。
  • PhysicsShapeEdgeChain:有边的链形。

EventListenerPhysicsContact类

碰撞检测监听类EventListenerPhysicsShapeContact,子类如下:

EventListenerPhysicsContact中碰撞检测事件响应属性:

  • std::function<bool(PhysicsContact & contact)>onContactBegin:两个物体开始接触时会响应,但只调用一次。返回false情况下后面的两个属性(onContactPreSolve 和 onContactPostSolve)所指定的函数,不调用。
  • std::function<bool(PhysicsContact & contact, PhysicsContactPreSolve & solve)>onContactPreSolve:持续接触时响应,它会被多次调用。返回false情况下后面的onContactPostSolve属性所指定的函数,不调用。
  • std::function<void(PhysicsContact & contact, const PhysicsContactPostSolve & solve)>onContactPostSolve:持续接触时响应,调用完PreSolve后调用。
  • std::function<void(PhysicsContact & contact)>onContactSeparate:分离时响应,但只调用一次。

PhysicsJoint类

关节类PhysicsJoint是一个抽象类,其子类如下:

PhysicsJointDistance类是距离关节类,两个物体上面各自有一点,两点之间的距离必须固定不变。创建PhysicsJointDistace的静态函数定义如下:

static PhysicsJointDistance * construct (
    PhysicsBody * a,
    PhysicsBody * b,
    const Vec2 & anchr1,
    const Vec2 & anchr2
)

其中参数a和b是两个互相约束的物体,anchr1是连接a物体的锚点,anchr2是b物体的锚点。

实例

小球

HelloWorld.h文件

#ifndef __HELLOWORLD_SCENE_H__
#define __HELLOWORLD_SCENE_H__

#include "cocos2d.h"

USING_NS_CC;

class HelloWorld : public cocos2d::Layer
{
public:
    static cocos2d::Scene* createScene();

    virtual bool init();  
    virtual bool onTouchBegan(cocos2d::Touch * touch, cocos2d::Event * event);

    void addNewSpriteAtPosition(Vec2 p);

    // implement the "static create()" method manually
    CREATE_FUNC(HelloWorld);
};

#endif // __HELLOWORLD_SCENE_H__

HelloWorld.cpp文件

#include "HelloWorldScene.h"

USING_NS_CC;

Scene* HelloWorld::createScene()
{
    // 'scene' is an autorelease object
    auto scene = Scene::createWithPhysics();//创建带物理引擎的场景
    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;
}

// on "init" you need to initialize your instance
bool HelloWorld::init()
{
    //
    // 1. super init first
    if ( !Layer::init() )
    {
    return false;
    }

    log("HelloWorld init");

    Size visibleSize = Director::getInstance()->getVisibleSize();
    Vec2 origin = Director::getInstance()->getVisibleOrigin();

    //定义世界的边界
    //创建物体对象,静态函数createEdgeBox指定世界边界是矩形盒子,第一个参数指定矩形的大小,第二个参数是设置材质,第三个参数是设置边的宽度
    auto body = PhysicsBody::createEdgeBox(visibleSize, PHYSICSBODY_MATERIAL_DEFAULT, 5.0f);
    auto edgeNode = Node::create();//创建边界节点对象,这个节点对象作为世界边界的对象
    edgeNode->setPosition(Vec2(visibleSize.width / 2, visibleSize.height / 2));
    edgeNode->setPhysicsBody(body);//设置与节点相关的物体对象
    this->addChild(edgeNode);

    setTouchEnabled(true);
    //设置为单点触摸
    setTouchMode(Touch::DispatchMode::ONE_BY_ONE);

    return true;
}

bool HelloWorld::onTouchBegan(Touch * touch, Event * event)
{
    Vec2 location = touch->getLocation();
    addNewSpriteAtPosition(location);
    return false;
}

void HelloWorld::addNewSpriteAtPosition(Vec2 p)
{
    auto sp = Sprite::create("Ball.png");
    sp->setTag(1);

    auto body = PhysicsBody::createCircle(sp->getContentSize().width / 2);//创建圆圈形状物体
    sp->setPhysicsBody(body);
    sp->setPosition(p);
    this->addChild(sp);
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值