2013-09-09 10:29:02 +08:00
|
|
|
/****************************************************************************
|
|
|
|
Copyright (c) 2013 cocos2d-x.org
|
|
|
|
|
|
|
|
http://www.cocos2d-x.org
|
|
|
|
|
|
|
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
|
|
of this software and associated documentation files (the "Software"), to deal
|
|
|
|
in the Software without restriction, including without limitation the rights
|
|
|
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
|
|
copies of the Software, and to permit persons to whom the Software is
|
|
|
|
furnished to do so, subject to the following conditions:
|
|
|
|
|
|
|
|
The above copyright notice and this permission notice shall be included in
|
|
|
|
all copies or substantial portions of the Software.
|
|
|
|
|
|
|
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
|
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
|
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
|
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
|
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
|
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
|
|
THE SOFTWARE.
|
|
|
|
****************************************************************************/
|
2013-09-09 10:40:31 +08:00
|
|
|
#include "CCPhysicsBody.h"
|
2013-09-10 17:36:49 +08:00
|
|
|
#ifdef CC_USE_PHYSICS
|
|
|
|
|
2013-10-26 12:33:31 +08:00
|
|
|
#include <climits>
|
2013-09-17 14:31:43 +08:00
|
|
|
#include <algorithm>
|
2013-12-03 12:47:03 +08:00
|
|
|
#include <cmath>
|
2013-09-17 14:31:43 +08:00
|
|
|
|
2013-09-17 17:39:08 +08:00
|
|
|
#include "chipmunk.h"
|
|
|
|
|
2013-09-16 21:22:22 +08:00
|
|
|
#include "CCPhysicsShape.h"
|
|
|
|
#include "CCPhysicsJoint.h"
|
|
|
|
#include "CCPhysicsWorld.h"
|
|
|
|
|
2013-10-31 18:18:02 +08:00
|
|
|
#include "chipmunk/CCPhysicsBodyInfo_chipmunk.h"
|
|
|
|
#include "chipmunk/CCPhysicsJointInfo_chipmunk.h"
|
|
|
|
#include "chipmunk/CCPhysicsWorldInfo_chipmunk.h"
|
|
|
|
#include "chipmunk/CCPhysicsShapeInfo_chipmunk.h"
|
|
|
|
#include "chipmunk/CCPhysicsHelper_chipmunk.h"
|
2013-09-16 21:22:22 +08:00
|
|
|
|
2013-09-10 17:36:49 +08:00
|
|
|
NS_CC_BEGIN
|
2013-11-27 17:33:33 +08:00
|
|
|
extern const float PHYSICS_INFINITY;
|
2013-09-10 17:36:49 +08:00
|
|
|
|
2013-09-16 21:22:22 +08:00
|
|
|
namespace
|
|
|
|
{
|
|
|
|
static const float MASS_DEFAULT = 1.0;
|
2013-10-14 13:56:08 +08:00
|
|
|
static const float MOMENT_DEFAULT = 200;
|
2013-09-16 21:22:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
PhysicsBody::PhysicsBody()
|
2013-11-01 16:26:03 +08:00
|
|
|
: _node(nullptr)
|
2013-09-16 21:22:22 +08:00
|
|
|
, _world(nullptr)
|
|
|
|
, _info(nullptr)
|
2013-09-30 20:43:19 +08:00
|
|
|
, _dynamic(true)
|
2013-09-29 09:39:20 +08:00
|
|
|
, _enable(true)
|
2013-10-15 16:55:08 +08:00
|
|
|
, _rotationEnable(true)
|
|
|
|
, _gravityEnable(true)
|
2013-09-16 21:22:22 +08:00
|
|
|
, _massDefault(true)
|
2013-10-14 13:56:08 +08:00
|
|
|
, _momentDefault(true)
|
2013-09-16 21:22:22 +08:00
|
|
|
, _mass(MASS_DEFAULT)
|
2013-10-15 16:55:08 +08:00
|
|
|
, _area(0.0f)
|
|
|
|
, _density(0.0f)
|
2013-10-14 13:56:08 +08:00
|
|
|
, _moment(MOMENT_DEFAULT)
|
2013-10-15 16:55:08 +08:00
|
|
|
, _linearDamping(0.0f)
|
|
|
|
, _angularDamping(0.0f)
|
2013-09-29 09:39:20 +08:00
|
|
|
, _tag(0)
|
2013-10-21 23:16:21 +08:00
|
|
|
, _categoryBitmask(UINT_MAX)
|
|
|
|
, _collisionBitmask(UINT_MAX)
|
2013-11-04 14:36:38 +08:00
|
|
|
, _contactTestBitmask(UINT_MAX)
|
2013-10-29 17:31:35 +08:00
|
|
|
, _group(0)
|
2013-09-10 17:36:49 +08:00
|
|
|
{
|
2013-09-16 21:22:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
PhysicsBody::~PhysicsBody()
|
|
|
|
{
|
|
|
|
for (auto it = _joints.begin(); it != _joints.end(); ++it)
|
|
|
|
{
|
|
|
|
PhysicsJoint* joint = *it;
|
2013-10-28 11:08:41 +08:00
|
|
|
|
2013-11-07 14:17:57 +08:00
|
|
|
PhysicsBody* other = joint->getBodyA() == this ? joint->getBodyB() : joint->getBodyA();
|
|
|
|
other->removeJoint(joint);
|
2013-09-16 21:22:22 +08:00
|
|
|
delete joint;
|
|
|
|
}
|
2013-11-07 14:17:57 +08:00
|
|
|
|
2013-10-28 11:08:41 +08:00
|
|
|
CC_SAFE_DELETE(_info);
|
2013-09-16 21:22:22 +08:00
|
|
|
}
|
2013-09-10 17:36:49 +08:00
|
|
|
|
2013-10-10 18:31:43 +08:00
|
|
|
PhysicsBody* PhysicsBody::create()
|
|
|
|
{
|
|
|
|
PhysicsBody* body = new PhysicsBody();
|
|
|
|
if (body && body->init())
|
|
|
|
{
|
|
|
|
body->autorelease();
|
|
|
|
return body;
|
|
|
|
}
|
|
|
|
|
|
|
|
CC_SAFE_DELETE(body);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2013-10-28 11:08:41 +08:00
|
|
|
PhysicsBody* PhysicsBody::create(float mass)
|
|
|
|
{
|
|
|
|
PhysicsBody* body = new PhysicsBody();
|
|
|
|
if (body)
|
|
|
|
{
|
|
|
|
body->_mass = mass;
|
|
|
|
body->_massDefault = false;
|
|
|
|
if (body->init())
|
|
|
|
{
|
|
|
|
body->autorelease();
|
|
|
|
return body;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CC_SAFE_DELETE(body);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
PhysicsBody* PhysicsBody::create(float mass, float moment)
|
|
|
|
{
|
|
|
|
PhysicsBody* body = new PhysicsBody();
|
|
|
|
if (body)
|
|
|
|
{
|
|
|
|
body->_mass = mass;
|
|
|
|
body->_massDefault = false;
|
|
|
|
body->_moment = moment;
|
|
|
|
body->_momentDefault = false;
|
|
|
|
if (body->init())
|
|
|
|
{
|
|
|
|
body->autorelease();
|
|
|
|
return body;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
CC_SAFE_DELETE(body);
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
PhysicsBody* PhysicsBody::createCircle(float radius, const PhysicsMaterial& material, const Point& offset)
|
2013-09-10 17:36:49 +08:00
|
|
|
{
|
2013-09-16 21:22:22 +08:00
|
|
|
PhysicsBody* body = new PhysicsBody();
|
|
|
|
if (body && body->init())
|
|
|
|
{
|
2013-11-05 15:54:33 +08:00
|
|
|
body->addShape(PhysicsShapeCircle::create(radius, material, offset));
|
2013-09-16 21:22:22 +08:00
|
|
|
body->autorelease();
|
|
|
|
return body;
|
|
|
|
}
|
|
|
|
|
|
|
|
CC_SAFE_DELETE(body);
|
|
|
|
return nullptr;
|
2013-09-10 17:36:49 +08:00
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
PhysicsBody* PhysicsBody::createBox(const Size& size, const PhysicsMaterial& material, const Point& offset)
|
2013-09-10 17:36:49 +08:00
|
|
|
{
|
2013-09-16 21:22:22 +08:00
|
|
|
PhysicsBody* body = new PhysicsBody();
|
|
|
|
if (body && body->init())
|
|
|
|
{
|
2013-11-05 15:54:33 +08:00
|
|
|
body->addShape(PhysicsShapeBox::create(size, material, offset));
|
2013-09-16 21:22:22 +08:00
|
|
|
body->autorelease();
|
|
|
|
return body;
|
|
|
|
}
|
|
|
|
|
|
|
|
CC_SAFE_DELETE(body);
|
|
|
|
return nullptr;
|
2013-09-10 17:36:49 +08:00
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
PhysicsBody* PhysicsBody::createPolygon(const Point* points, int count, const PhysicsMaterial& material, const Point& offset)
|
2013-09-16 21:22:22 +08:00
|
|
|
{
|
|
|
|
PhysicsBody* body = new PhysicsBody();
|
|
|
|
if (body && body->init())
|
|
|
|
{
|
2013-11-05 15:54:33 +08:00
|
|
|
body->addShape(PhysicsShapePolygon::create(points, count, material, offset));
|
2013-09-16 21:22:22 +08:00
|
|
|
body->autorelease();
|
|
|
|
return body;
|
|
|
|
}
|
|
|
|
|
|
|
|
CC_SAFE_DELETE(body);
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
PhysicsBody* PhysicsBody::createEdgeSegment(const Point& a, const Point& b, const PhysicsMaterial& material, float border/* = 1*/)
|
2013-09-10 17:36:49 +08:00
|
|
|
{
|
2013-09-16 21:22:22 +08:00
|
|
|
PhysicsBody* body = new PhysicsBody();
|
2013-09-30 20:43:19 +08:00
|
|
|
if (body && body->init())
|
2013-09-16 21:22:22 +08:00
|
|
|
{
|
2013-10-09 17:53:12 +08:00
|
|
|
body->addShape(PhysicsShapeEdgeSegment::create(a, b, material, border));
|
2013-09-30 20:43:19 +08:00
|
|
|
body->_dynamic = false;
|
2013-09-16 21:22:22 +08:00
|
|
|
body->autorelease();
|
|
|
|
return body;
|
|
|
|
}
|
|
|
|
|
|
|
|
CC_SAFE_DELETE(body);
|
|
|
|
return nullptr;
|
2013-09-10 17:36:49 +08:00
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
PhysicsBody* PhysicsBody::createEdgeBox(const Size& size, const PhysicsMaterial& material, float border/* = 1*/, const Point& offset)
|
2013-09-10 17:36:49 +08:00
|
|
|
{
|
2013-09-16 21:22:22 +08:00
|
|
|
PhysicsBody* body = new PhysicsBody();
|
2013-09-30 20:43:19 +08:00
|
|
|
if (body && body->init())
|
2013-09-16 21:22:22 +08:00
|
|
|
{
|
2013-11-05 15:54:33 +08:00
|
|
|
body->addShape(PhysicsShapeEdgeBox::create(size, material, border, offset));
|
2013-09-30 20:43:19 +08:00
|
|
|
body->_dynamic = false;
|
2013-09-16 21:22:22 +08:00
|
|
|
body->autorelease();
|
|
|
|
return body;
|
|
|
|
}
|
|
|
|
|
|
|
|
CC_SAFE_DELETE(body);
|
|
|
|
|
|
|
|
return nullptr;
|
2013-09-10 17:36:49 +08:00
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
PhysicsBody* PhysicsBody::createEdgePolygon(const Point* points, int count, const PhysicsMaterial& material, float border/* = 1*/)
|
2013-09-10 17:36:49 +08:00
|
|
|
{
|
2013-09-16 21:22:22 +08:00
|
|
|
PhysicsBody* body = new PhysicsBody();
|
2013-09-30 20:43:19 +08:00
|
|
|
if (body && body->init())
|
2013-09-10 17:36:49 +08:00
|
|
|
{
|
2013-10-09 17:53:12 +08:00
|
|
|
body->addShape(PhysicsShapeEdgePolygon::create(points, count, material, border));
|
2013-09-30 20:43:19 +08:00
|
|
|
body->_dynamic = false;
|
2013-09-16 21:22:22 +08:00
|
|
|
body->autorelease();
|
2013-09-10 17:36:49 +08:00
|
|
|
return body;
|
|
|
|
}
|
|
|
|
|
|
|
|
CC_SAFE_DELETE(body);
|
2013-09-16 21:22:22 +08:00
|
|
|
|
2013-09-10 17:36:49 +08:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
PhysicsBody* PhysicsBody::createEdgeChain(const Point* points, int count, const PhysicsMaterial& material, float border/* = 1*/)
|
2013-09-16 21:22:22 +08:00
|
|
|
{
|
|
|
|
PhysicsBody* body = new PhysicsBody();
|
2013-09-30 20:43:19 +08:00
|
|
|
if (body && body->init())
|
2013-09-16 21:22:22 +08:00
|
|
|
{
|
2013-10-09 17:53:12 +08:00
|
|
|
body->addShape(PhysicsShapeEdgeChain::create(points, count, material, border));
|
2013-09-30 20:43:19 +08:00
|
|
|
body->_dynamic = false;
|
2013-09-16 21:22:22 +08:00
|
|
|
body->autorelease();
|
|
|
|
return body;
|
|
|
|
}
|
|
|
|
|
|
|
|
CC_SAFE_DELETE(body);
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2013-09-10 17:36:49 +08:00
|
|
|
bool PhysicsBody::init()
|
|
|
|
{
|
|
|
|
do
|
|
|
|
{
|
|
|
|
_info = new PhysicsBodyInfo();
|
|
|
|
CC_BREAK_IF(_info == nullptr);
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
_info->setBody(cpBodyNew(PhysicsHelper::float2cpfloat(_mass), PhysicsHelper::float2cpfloat(_moment)));
|
2013-10-17 10:57:48 +08:00
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
CC_BREAK_IF(_info->getBody() == nullptr);
|
2013-09-10 17:36:49 +08:00
|
|
|
|
|
|
|
return true;
|
|
|
|
} while (false);
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2013-11-07 14:17:57 +08:00
|
|
|
void PhysicsBody::removeJoint(PhysicsJoint* joint)
|
|
|
|
{
|
|
|
|
auto it = std::find(_joints.begin(), _joints.end(), joint);
|
|
|
|
|
|
|
|
if (it != _joints.end())
|
|
|
|
{
|
|
|
|
_joints.erase(it);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-09-16 21:22:22 +08:00
|
|
|
void PhysicsBody::setDynamic(bool dynamic)
|
2013-09-10 17:36:49 +08:00
|
|
|
{
|
2013-09-30 13:02:17 +08:00
|
|
|
if (dynamic != _dynamic)
|
2013-09-10 17:36:49 +08:00
|
|
|
{
|
2013-10-15 16:55:08 +08:00
|
|
|
_dynamic = dynamic;
|
2013-11-04 14:36:38 +08:00
|
|
|
if (dynamic)
|
2013-09-16 21:22:22 +08:00
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
cpBodySetMass(_info->getBody(), _mass);
|
2013-11-19 18:30:12 +08:00
|
|
|
cpBodySetMoment(_info->getBody(), _moment);
|
2013-11-04 14:36:38 +08:00
|
|
|
|
|
|
|
if (_world != nullptr)
|
2013-10-15 16:55:08 +08:00
|
|
|
{
|
2013-11-19 18:30:12 +08:00
|
|
|
// reset the gravity enable
|
|
|
|
if (isGravityEnabled())
|
|
|
|
{
|
|
|
|
_gravityEnable = false;
|
|
|
|
setGravityEnable(true);
|
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
cpSpaceAddBody(_world->_info->getSpace(), _info->getBody());
|
2013-11-04 14:36:38 +08:00
|
|
|
}
|
2013-11-19 18:30:12 +08:00
|
|
|
}
|
|
|
|
else
|
2013-11-04 14:36:38 +08:00
|
|
|
{
|
|
|
|
if (_world != nullptr)
|
2013-10-15 16:55:08 +08:00
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
cpSpaceRemoveBody(_world->_info->getSpace(), _info->getBody());
|
2013-10-15 16:55:08 +08:00
|
|
|
}
|
2013-11-19 18:30:12 +08:00
|
|
|
|
|
|
|
// avoid incorrect collion simulation.
|
2013-11-27 17:33:33 +08:00
|
|
|
cpBodySetMass(_info->getBody(), PHYSICS_INFINITY);
|
|
|
|
cpBodySetMoment(_info->getBody(), PHYSICS_INFINITY);
|
2013-11-19 18:30:12 +08:00
|
|
|
cpBodySetVel(_info->getBody(), cpvzero);
|
|
|
|
cpBodySetAngVel(_info->getBody(), 0.0f);
|
2013-09-16 21:22:22 +08:00
|
|
|
}
|
2013-09-30 13:02:17 +08:00
|
|
|
|
2013-10-15 16:55:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicsBody::setRotationEnable(bool enable)
|
|
|
|
{
|
|
|
|
if (_rotationEnable != enable)
|
|
|
|
{
|
2013-11-27 17:33:33 +08:00
|
|
|
cpBodySetMoment(_info->getBody(), enable ? _moment : PHYSICS_INFINITY);
|
2013-10-15 16:55:08 +08:00
|
|
|
_rotationEnable = enable;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicsBody::setGravityEnable(bool enable)
|
|
|
|
{
|
|
|
|
if (_gravityEnable != enable)
|
|
|
|
{
|
|
|
|
_gravityEnable = enable;
|
|
|
|
|
|
|
|
if (_world != nullptr)
|
|
|
|
{
|
|
|
|
if (enable)
|
|
|
|
{
|
2013-10-29 17:31:35 +08:00
|
|
|
applyForce(_world->getGravity() * _mass);
|
2013-10-15 16:55:08 +08:00
|
|
|
}else
|
|
|
|
{
|
2013-10-29 17:31:35 +08:00
|
|
|
applyForce(-_world->getGravity() * _mass);
|
2013-10-15 16:55:08 +08:00
|
|
|
}
|
|
|
|
}
|
2013-09-10 17:36:49 +08:00
|
|
|
}
|
2013-09-16 21:22:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicsBody::setPosition(Point position)
|
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
cpBodySetPos(_info->getBody(), PhysicsHelper::point2cpv(position));
|
2013-09-16 21:22:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicsBody::setRotation(float rotation)
|
|
|
|
{
|
2013-12-03 12:47:03 +08:00
|
|
|
cpBodySetAngle(_info->getBody(), PhysicsHelper::float2cpfloat(rotation * M_PI / 180.0f));
|
2013-09-16 21:22:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Point PhysicsBody::getPosition() const
|
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
cpVect vec = cpBodyGetPos(_info->getBody());
|
2013-09-16 21:22:22 +08:00
|
|
|
return PhysicsHelper::cpv2point(vec);
|
|
|
|
}
|
|
|
|
|
|
|
|
float PhysicsBody::getRotation() const
|
|
|
|
{
|
2013-12-03 12:47:03 +08:00
|
|
|
return -PhysicsHelper::cpfloat2float(cpBodyGetAngle(_info->getBody()) / M_PI * 180.0f);
|
2013-09-16 21:22:22 +08:00
|
|
|
}
|
|
|
|
|
2013-11-12 15:28:07 +08:00
|
|
|
PhysicsShape* PhysicsBody::addShape(PhysicsShape* shape, bool addMassAndMoment/* = true*/)
|
2013-09-16 21:22:22 +08:00
|
|
|
{
|
2013-10-29 17:31:35 +08:00
|
|
|
if (shape == nullptr) return nullptr;
|
2013-09-10 17:36:49 +08:00
|
|
|
|
2013-10-09 13:41:19 +08:00
|
|
|
// add shape to body
|
2013-12-07 10:48:02 +08:00
|
|
|
if (_shapes.getIndex(shape) == -1)
|
2013-09-30 20:43:19 +08:00
|
|
|
{
|
2013-10-09 13:41:19 +08:00
|
|
|
shape->setBody(this);
|
2013-09-30 20:43:19 +08:00
|
|
|
|
2013-10-14 14:05:57 +08:00
|
|
|
// calculate the area, mass, and desity
|
|
|
|
// area must update before mass, because the density changes depend on it.
|
2013-11-12 15:28:07 +08:00
|
|
|
if (addMassAndMoment)
|
|
|
|
{
|
|
|
|
_area += shape->getArea();
|
|
|
|
addMass(shape->getMass());
|
|
|
|
addMoment(shape->getMoment());
|
|
|
|
}
|
2013-09-30 20:43:19 +08:00
|
|
|
|
2013-10-15 16:55:08 +08:00
|
|
|
if (_world != nullptr)
|
2013-09-30 20:43:19 +08:00
|
|
|
{
|
2013-10-15 16:55:08 +08:00
|
|
|
_world->addShape(shape);
|
2013-09-30 20:43:19 +08:00
|
|
|
}
|
|
|
|
|
2013-12-07 10:48:02 +08:00
|
|
|
_shapes.pushBack(shape);
|
2013-10-29 17:31:35 +08:00
|
|
|
|
|
|
|
if (_group != CP_NO_GROUP && shape->getGroup() == CP_NO_GROUP)
|
|
|
|
{
|
|
|
|
shape->setGroup(_group);
|
|
|
|
}
|
2013-09-30 20:43:19 +08:00
|
|
|
}
|
2013-10-29 17:31:35 +08:00
|
|
|
|
|
|
|
return shape;
|
2013-09-16 21:22:22 +08:00
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
void PhysicsBody::applyForce(const Vect& force)
|
2013-09-16 21:22:22 +08:00
|
|
|
{
|
2013-10-15 16:55:08 +08:00
|
|
|
applyForce(force, Point::ZERO);
|
2013-09-16 21:22:22 +08:00
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
void PhysicsBody::applyForce(const Vect& force, const Point& offset)
|
2013-09-16 21:22:22 +08:00
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
cpBodyApplyForce(_info->getBody(), PhysicsHelper::point2cpv(force), PhysicsHelper::point2cpv(offset));
|
2013-09-16 21:22:22 +08:00
|
|
|
}
|
|
|
|
|
2013-11-18 16:27:23 +08:00
|
|
|
void PhysicsBody::resetForces()
|
2013-11-12 15:28:07 +08:00
|
|
|
{
|
|
|
|
cpBodyResetForces(_info->getBody());
|
|
|
|
|
|
|
|
// if _gravityEnable is false, add a reverse of gravity force to body
|
|
|
|
if (_world != nullptr && !_gravityEnable)
|
|
|
|
{
|
|
|
|
applyForce(-_world->getGravity() * _mass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
void PhysicsBody::applyImpulse(const Vect& impulse)
|
2013-09-16 21:22:22 +08:00
|
|
|
{
|
|
|
|
applyImpulse(impulse, Point());
|
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
void PhysicsBody::applyImpulse(const Vect& impulse, const Point& offset)
|
2013-09-16 21:22:22 +08:00
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
cpBodyApplyImpulse(_info->getBody(), PhysicsHelper::point2cpv(impulse), PhysicsHelper::point2cpv(offset));
|
2013-09-16 21:22:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicsBody::applyTorque(float torque)
|
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
cpBodySetTorque(_info->getBody(), PhysicsHelper::float2cpfloat(torque));
|
2013-09-16 21:22:22 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicsBody::setMass(float mass)
|
|
|
|
{
|
2013-11-20 10:25:43 +08:00
|
|
|
if (mass <= 0)
|
2013-10-14 13:56:08 +08:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-09-16 21:22:22 +08:00
|
|
|
_mass = mass;
|
|
|
|
_massDefault = false;
|
2013-09-10 17:36:49 +08:00
|
|
|
|
2013-10-14 13:56:08 +08:00
|
|
|
// update density
|
2013-11-27 17:33:33 +08:00
|
|
|
if (_mass == PHYSICS_INFINITY)
|
2013-10-14 13:56:08 +08:00
|
|
|
{
|
2013-11-27 17:33:33 +08:00
|
|
|
_density = PHYSICS_INFINITY;
|
2013-10-14 13:56:08 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (_area > 0)
|
|
|
|
{
|
|
|
|
_density = _mass / _area;
|
|
|
|
}else
|
|
|
|
{
|
|
|
|
_density = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-20 10:25:43 +08:00
|
|
|
// the static body's mass and moment is always infinity
|
|
|
|
if (_dynamic)
|
|
|
|
{
|
|
|
|
cpBodySetMass(_info->getBody(), PhysicsHelper::float2cpfloat(_mass));
|
|
|
|
}
|
2013-09-10 17:36:49 +08:00
|
|
|
}
|
|
|
|
|
2013-10-14 13:56:08 +08:00
|
|
|
void PhysicsBody::addMass(float mass)
|
|
|
|
{
|
2013-11-27 17:33:33 +08:00
|
|
|
if (mass == PHYSICS_INFINITY)
|
2013-10-14 13:56:08 +08:00
|
|
|
{
|
2013-11-27 17:33:33 +08:00
|
|
|
_mass = PHYSICS_INFINITY;
|
2013-10-14 13:56:08 +08:00
|
|
|
_massDefault = false;
|
2013-11-27 17:33:33 +08:00
|
|
|
_density = PHYSICS_INFINITY;
|
2013-10-14 13:56:08 +08:00
|
|
|
}
|
2013-11-27 17:33:33 +08:00
|
|
|
else if (mass == -PHYSICS_INFINITY)
|
2013-10-14 13:56:08 +08:00
|
|
|
{
|
|
|
|
return;
|
|
|
|
}
|
2013-11-27 17:33:33 +08:00
|
|
|
else if (_mass != PHYSICS_INFINITY)
|
2013-10-14 13:56:08 +08:00
|
|
|
{
|
|
|
|
if (_massDefault)
|
|
|
|
{
|
|
|
|
_mass = 0;
|
|
|
|
_massDefault = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_mass + mass > 0)
|
|
|
|
{
|
|
|
|
_mass += mass;
|
|
|
|
}else
|
|
|
|
{
|
|
|
|
_mass = MASS_DEFAULT;
|
|
|
|
_massDefault = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_area > 0)
|
|
|
|
{
|
|
|
|
_density = _mass / _area;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_density = 0;
|
|
|
|
}
|
|
|
|
}
|
2013-10-15 13:48:01 +08:00
|
|
|
|
2013-11-20 10:25:43 +08:00
|
|
|
// the static body's mass and moment is always infinity
|
|
|
|
if (_dynamic)
|
|
|
|
{
|
|
|
|
cpBodySetMass(_info->getBody(), PhysicsHelper::float2cpfloat(_mass));
|
|
|
|
}
|
2013-10-14 13:56:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicsBody::addMoment(float moment)
|
|
|
|
{
|
2013-11-27 17:33:33 +08:00
|
|
|
if (moment == PHYSICS_INFINITY)
|
2013-10-14 13:56:08 +08:00
|
|
|
{
|
2013-11-27 17:33:33 +08:00
|
|
|
// if moment is PHYSICS_INFINITY, the moment of the body will become PHYSICS_INFINITY
|
|
|
|
_moment = PHYSICS_INFINITY;
|
2013-10-14 13:56:08 +08:00
|
|
|
_momentDefault = false;
|
|
|
|
}
|
2013-11-27 17:33:33 +08:00
|
|
|
else if (moment == -PHYSICS_INFINITY)
|
2013-10-14 13:56:08 +08:00
|
|
|
{
|
2013-11-27 17:33:33 +08:00
|
|
|
// if moment is -PHYSICS_INFINITY, it won't change
|
2013-10-14 13:56:08 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2013-11-27 17:33:33 +08:00
|
|
|
// if moment of the body is PHYSICS_INFINITY is has no effect
|
|
|
|
if (_moment != PHYSICS_INFINITY)
|
2013-10-14 13:56:08 +08:00
|
|
|
{
|
|
|
|
if (_momentDefault)
|
|
|
|
{
|
|
|
|
_moment = 0;
|
|
|
|
_momentDefault = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (_moment + moment > 0)
|
|
|
|
{
|
|
|
|
_moment += moment;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
_moment = MOMENT_DEFAULT;
|
|
|
|
_momentDefault = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-20 10:25:43 +08:00
|
|
|
// the static body's mass and moment is always infinity
|
|
|
|
if (_rotationEnable && _dynamic)
|
2013-10-15 16:55:08 +08:00
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
cpBodySetMoment(_info->getBody(), PhysicsHelper::float2cpfloat(_moment));
|
2013-10-15 16:55:08 +08:00
|
|
|
}
|
2013-10-14 13:56:08 +08:00
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
void PhysicsBody::setVelocity(const Point& velocity)
|
2013-09-30 20:43:19 +08:00
|
|
|
{
|
2013-11-19 18:30:12 +08:00
|
|
|
if (!_dynamic)
|
|
|
|
{
|
2013-11-20 10:25:43 +08:00
|
|
|
CCLOG("physics warning: your cann't set velocity for a static body.");
|
2013-11-19 18:30:12 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
cpBodySetVel(_info->getBody(), PhysicsHelper::point2cpv(velocity));
|
2013-09-30 20:43:19 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Point PhysicsBody::getVelocity()
|
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
return PhysicsHelper::cpv2point(cpBodyGetVel(_info->getBody()));
|
2013-09-30 20:43:19 +08:00
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
Point PhysicsBody::getVelocityAtLocalPoint(const Point& point)
|
2013-11-05 15:54:33 +08:00
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
return PhysicsHelper::cpv2point(cpBodyGetVelAtLocalPoint(_info->getBody(), PhysicsHelper::point2cpv(point)));
|
2013-11-05 15:54:33 +08:00
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
Point PhysicsBody::getVelocityAtWorldPoint(const Point& point)
|
2013-11-05 15:54:33 +08:00
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
return PhysicsHelper::cpv2point(cpBodyGetVelAtWorldPoint(_info->getBody(), PhysicsHelper::point2cpv(point)));
|
2013-11-05 15:54:33 +08:00
|
|
|
}
|
|
|
|
|
2013-10-15 16:55:08 +08:00
|
|
|
void PhysicsBody::setAngularVelocity(float velocity)
|
|
|
|
{
|
2013-11-19 18:30:12 +08:00
|
|
|
if (!_dynamic)
|
|
|
|
{
|
2013-11-20 10:25:43 +08:00
|
|
|
CCLOG("physics warning: your cann't set angular velocity for a static body.");
|
2013-11-19 18:30:12 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
cpBodySetAngVel(_info->getBody(), PhysicsHelper::float2cpfloat(velocity));
|
2013-10-15 16:55:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
float PhysicsBody::getAngularVelocity()
|
2013-09-16 21:22:22 +08:00
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
return PhysicsHelper::cpfloat2float(cpBodyGetAngVel(_info->getBody()));
|
2013-10-15 16:55:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicsBody::setVelocityLimit(float limit)
|
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
cpBodySetVelLimit(_info->getBody(), PhysicsHelper::float2cpfloat(limit));
|
2013-10-15 16:55:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
float PhysicsBody::getVelocityLimit()
|
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
return PhysicsHelper::cpfloat2float(cpBodyGetVelLimit(_info->getBody()));
|
2013-10-15 16:55:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicsBody::setAngularVelocityLimit(float limit)
|
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
cpBodySetVelLimit(_info->getBody(), PhysicsHelper::float2cpfloat(limit));
|
2013-10-15 16:55:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
float PhysicsBody::getAngularVelocityLimit()
|
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
return PhysicsHelper::cpfloat2float(cpBodyGetAngVelLimit(_info->getBody()));
|
2013-10-15 16:55:08 +08:00
|
|
|
}
|
|
|
|
|
2013-10-14 13:56:08 +08:00
|
|
|
void PhysicsBody::setMoment(float moment)
|
2013-09-16 21:22:22 +08:00
|
|
|
{
|
2013-10-14 13:56:08 +08:00
|
|
|
_moment = moment;
|
|
|
|
_momentDefault = false;
|
2013-09-16 21:22:22 +08:00
|
|
|
|
2013-11-20 10:25:43 +08:00
|
|
|
// the static body's mass and moment is always infinity
|
|
|
|
if (_rotationEnable && _dynamic)
|
2013-10-15 16:55:08 +08:00
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
cpBodySetMoment(_info->getBody(), PhysicsHelper::float2cpfloat(_moment));
|
2013-10-15 16:55:08 +08:00
|
|
|
}
|
2013-09-16 21:22:22 +08:00
|
|
|
}
|
|
|
|
|
2013-11-05 20:02:58 +08:00
|
|
|
PhysicsShape* PhysicsBody::getShape(int tag) const
|
2013-09-29 09:39:20 +08:00
|
|
|
{
|
2013-12-07 10:48:02 +08:00
|
|
|
for (auto& shape : _shapes)
|
2013-09-29 09:39:20 +08:00
|
|
|
{
|
|
|
|
if (shape->getTag() == tag)
|
|
|
|
{
|
|
|
|
return shape;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2013-11-12 15:28:07 +08:00
|
|
|
void PhysicsBody::removeShape(int tag, bool reduceMassAndMoment/* = true*/)
|
2013-09-29 09:39:20 +08:00
|
|
|
{
|
2013-12-07 10:48:02 +08:00
|
|
|
for (auto& shape : _shapes)
|
2013-09-29 09:39:20 +08:00
|
|
|
{
|
|
|
|
if (shape->getTag() == tag)
|
|
|
|
{
|
2013-11-12 15:28:07 +08:00
|
|
|
removeShape(shape, reduceMassAndMoment);
|
2013-09-29 09:39:20 +08:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-12 15:28:07 +08:00
|
|
|
void PhysicsBody::removeShape(PhysicsShape* shape, bool reduceMassAndMoment/* = true*/)
|
2013-09-29 09:39:20 +08:00
|
|
|
{
|
2013-12-07 14:28:14 +08:00
|
|
|
if (_shapes.getIndex(shape) != -1)
|
2013-09-29 09:39:20 +08:00
|
|
|
{
|
2013-10-14 13:56:08 +08:00
|
|
|
// deduce the area, mass and moment
|
|
|
|
// area must update before mass, because the density changes depend on it.
|
2013-11-12 15:28:07 +08:00
|
|
|
if (reduceMassAndMoment)
|
|
|
|
{
|
|
|
|
_area -= shape->getArea();
|
|
|
|
addMass(-shape->getMass());
|
|
|
|
addMoment(-shape->getMoment());
|
|
|
|
}
|
2013-09-30 20:43:19 +08:00
|
|
|
|
2013-10-17 10:57:48 +08:00
|
|
|
//remove
|
2013-09-29 09:39:20 +08:00
|
|
|
if (_world)
|
|
|
|
{
|
|
|
|
_world->removeShape(shape);
|
|
|
|
}
|
2013-11-07 14:17:57 +08:00
|
|
|
|
|
|
|
// set shape->_body = nullptr make the shape->setBody will not trigger the _body->removeShape function call.
|
|
|
|
shape->_body = nullptr;
|
2013-10-17 10:57:48 +08:00
|
|
|
shape->setBody(nullptr);
|
2013-12-11 17:53:45 +08:00
|
|
|
_shapes.erase(shape);
|
2013-09-29 09:39:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-12 15:28:07 +08:00
|
|
|
void PhysicsBody::removeAllShapes(bool reduceMassAndMoment/* = true*/)
|
2013-09-29 09:39:20 +08:00
|
|
|
{
|
2013-12-07 10:48:02 +08:00
|
|
|
for (auto& child : _shapes)
|
2013-09-29 09:39:20 +08:00
|
|
|
{
|
2013-10-28 11:08:41 +08:00
|
|
|
PhysicsShape* shape = dynamic_cast<PhysicsShape*>(child);
|
|
|
|
|
|
|
|
// deduce the area, mass and moment
|
|
|
|
// area must update before mass, because the density changes depend on it.
|
2013-11-12 15:28:07 +08:00
|
|
|
if (reduceMassAndMoment)
|
|
|
|
{
|
|
|
|
_area -= shape->getArea();
|
|
|
|
addMass(-shape->getMass());
|
|
|
|
addMoment(-shape->getMoment());
|
|
|
|
}
|
2013-10-28 11:08:41 +08:00
|
|
|
|
2013-09-29 09:39:20 +08:00
|
|
|
if (_world)
|
|
|
|
{
|
|
|
|
_world->removeShape(shape);
|
|
|
|
}
|
2013-11-07 14:17:57 +08:00
|
|
|
|
|
|
|
// set shape->_body = nullptr make the shape->setBody will not trigger the _body->removeShape function call.
|
|
|
|
shape->_body = nullptr;
|
2013-10-28 11:08:41 +08:00
|
|
|
shape->setBody(nullptr);
|
2013-09-29 09:39:20 +08:00
|
|
|
}
|
|
|
|
|
2013-12-07 10:48:02 +08:00
|
|
|
_shapes.clear();
|
2013-10-28 11:08:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicsBody::removeFromWorld()
|
|
|
|
{
|
|
|
|
if (_world)
|
|
|
|
{
|
|
|
|
_world->removeBody(this);
|
|
|
|
}
|
2013-09-29 09:39:20 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicsBody::setEnable(bool enable)
|
|
|
|
{
|
|
|
|
if (_enable != enable)
|
|
|
|
{
|
|
|
|
_enable = enable;
|
|
|
|
|
|
|
|
if (_world)
|
|
|
|
{
|
|
|
|
if (enable)
|
|
|
|
{
|
2013-11-07 15:12:13 +08:00
|
|
|
_world->addBodyOrDelay(this);
|
2013-09-29 09:39:20 +08:00
|
|
|
}else
|
|
|
|
{
|
2013-11-07 15:12:13 +08:00
|
|
|
_world->removeBodyOrDelay(this);
|
2013-09-29 09:39:20 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-11-01 16:26:03 +08:00
|
|
|
bool PhysicsBody::isResting() const
|
2013-10-15 16:55:08 +08:00
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
return cpBodyIsSleeping(_info->getBody()) == cpTrue;
|
2013-10-15 16:55:08 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicsBody::update(float delta)
|
|
|
|
{
|
|
|
|
// damping compute
|
|
|
|
if (_dynamic)
|
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
_info->getBody()->v.x *= cpfclamp(1.0f - delta * _linearDamping, 0.0f, 1.0f);
|
|
|
|
_info->getBody()->v.y *= cpfclamp(1.0f - delta * _linearDamping, 0.0f, 1.0f);
|
|
|
|
_info->getBody()->w *= cpfclamp(1.0f - delta * _angularDamping, 0.0f, 1.0f);
|
2013-10-15 16:55:08 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-10-29 17:31:35 +08:00
|
|
|
void PhysicsBody::setCategoryBitmask(int bitmask)
|
|
|
|
{
|
|
|
|
_categoryBitmask = bitmask;
|
|
|
|
|
2013-12-07 14:28:14 +08:00
|
|
|
for (auto& shape : _shapes)
|
2013-10-29 17:31:35 +08:00
|
|
|
{
|
2013-12-07 14:28:14 +08:00
|
|
|
shape->setCategoryBitmask(bitmask);
|
2013-10-29 17:31:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicsBody::setContactTestBitmask(int bitmask)
|
|
|
|
{
|
|
|
|
_contactTestBitmask = bitmask;
|
|
|
|
|
2013-12-07 14:28:14 +08:00
|
|
|
for (auto& shape : _shapes)
|
2013-10-29 17:31:35 +08:00
|
|
|
{
|
2013-12-07 14:28:14 +08:00
|
|
|
shape->setContactTestBitmask(bitmask);
|
2013-10-29 17:31:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicsBody::setCollisionBitmask(int bitmask)
|
|
|
|
{
|
|
|
|
_collisionBitmask = bitmask;
|
|
|
|
|
2013-12-07 14:28:14 +08:00
|
|
|
for (auto& shape : _shapes)
|
2013-10-29 17:31:35 +08:00
|
|
|
{
|
2013-12-07 14:28:14 +08:00
|
|
|
shape->setCollisionBitmask(bitmask);
|
2013-10-29 17:31:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void PhysicsBody::setGroup(int group)
|
|
|
|
{
|
2013-12-07 14:28:14 +08:00
|
|
|
for (auto& shape : _shapes)
|
2013-10-29 17:31:35 +08:00
|
|
|
{
|
2013-12-07 14:28:14 +08:00
|
|
|
shape->setGroup(group);
|
2013-10-29 17:31:35 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Point PhysicsBody::world2Local(const Point& point)
|
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
return PhysicsHelper::cpv2point(cpBodyWorld2Local(_info->getBody(), PhysicsHelper::point2cpv(point)));
|
2013-10-29 17:31:35 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Point PhysicsBody::local2World(const Point& point)
|
|
|
|
{
|
2013-11-05 20:02:58 +08:00
|
|
|
return PhysicsHelper::cpv2point(cpBodyLocal2World(_info->getBody(), PhysicsHelper::point2cpv(point)));
|
2013-10-29 17:31:35 +08:00
|
|
|
}
|
|
|
|
|
2013-09-10 17:36:49 +08:00
|
|
|
NS_CC_END
|
|
|
|
|
|
|
|
#endif // CC_USE_PHYSICS
|