123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984 |
- /****************************************************************************
- Copyright (c) 2013-2016 Chukong Technologies Inc.
- Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
-
- 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.
- ****************************************************************************/
- #include "physics/CCPhysicsShape.h"
- #if CC_USE_PHYSICS
- #include <climits>
- #include <cmath>
- #include <unordered_map>
- #include "chipmunk/chipmunk.h"
- #include "chipmunk/chipmunk_unsafe.h"
- #include "physics/CCPhysicsBody.h"
- #include "physics/CCPhysicsWorld.h"
- #include "physics/CCPhysicsHelper.h"
- NS_CC_BEGIN
- extern const float PHYSICS_INFINITY;
- static cpBody* s_sharedBody = nullptr;
- PhysicsShape::PhysicsShape()
- : _body(nullptr)
- , _type(Type::UNKNOWN)
- , _area(0.0f)
- , _mass(0.0f)
- , _moment(0.0f)
- , _sensor(false)
- , _scaleX(1.0f)
- , _scaleY(1.0f)
- , _newScaleX(1.0f)
- , _newScaleY(1.0f)
- , _tag(0)
- , _categoryBitmask(UINT_MAX)
- , _collisionBitmask(UINT_MAX)
- , _contactTestBitmask(0)
- , _group(0)
- {
- if (s_sharedBody == nullptr)
- {
- s_sharedBody = cpBodyNewStatic();
- }
- }
- PhysicsShape::~PhysicsShape()
- {
- for (auto shape : _cpShapes)
- {
- cpShapeFree(shape);
- }
- }
- void PhysicsShape::setMass(float mass)
- {
- if (mass < 0)
- {
- return;
- }
-
- if (_body)
- {
- _body->addMass(-_mass);
- _body->addMass(mass);
- };
-
- _mass = mass;
- }
- void PhysicsShape::setMoment(float moment)
- {
- if (moment < 0)
- {
- return;
- }
-
- if (_body)
- {
- _body->addMoment(-_moment);
- _body->addMoment(moment);
- };
-
- _moment = moment;
- }
- void PhysicsShape::setMaterial(const PhysicsMaterial& material)
- {
- setDensity(material.density);
- setRestitution(material.restitution);
- setFriction(material.friction);
- }
- void PhysicsShape::setScale(float scaleX, float scaleY)
- {
- if (std::abs(_scaleX - scaleX) > FLT_EPSILON || std::abs(_scaleY - scaleY) > FLT_EPSILON)
- {
- if (_type == Type::CIRCLE && scaleX != scaleY)
- {
- CCLOG("PhysicsShapeCircle WARNING: CANNOT support setScale with different x and y");
- return;
- }
- _newScaleX = scaleX;
- _newScaleY = scaleY;
-
- updateScale();
-
- // re-calculate area and mass
- _area = calculateArea();
- _mass = _material.density * _area;
- _moment = calculateDefaultMoment();
- }
- }
- void PhysicsShape::updateScale()
- {
- _scaleX = _newScaleX;
- _scaleY = _newScaleY;
- }
- void PhysicsShape::addShape(cpShape* shape)
- {
- if (shape)
- {
- cpShapeSetUserData(shape, this);
- cpShapeSetFilter(shape, cpShapeFilterNew(_group, CP_ALL_CATEGORIES, CP_ALL_CATEGORIES));
- _cpShapes.push_back(shape);
- }
- }
- PhysicsShapeCircle::PhysicsShapeCircle()
- {
-
- }
- PhysicsShapeCircle::~PhysicsShapeCircle()
- {
-
- }
- PhysicsShapeBox::PhysicsShapeBox()
- {
-
- }
- PhysicsShapeBox::~PhysicsShapeBox()
- {
-
- }
- PhysicsShapePolygon::PhysicsShapePolygon()
- {
-
- }
- PhysicsShapePolygon::~PhysicsShapePolygon()
- {
-
- }
- PhysicsShapeEdgeBox::PhysicsShapeEdgeBox()
- {
-
- }
- PhysicsShapeEdgeBox::~PhysicsShapeEdgeBox()
- {
-
- }
- PhysicsShapeEdgeChain::PhysicsShapeEdgeChain()
- {
-
- }
- PhysicsShapeEdgeChain::~PhysicsShapeEdgeChain()
- {
-
- }
- PhysicsShapeEdgePolygon::PhysicsShapeEdgePolygon()
- {
-
- }
- PhysicsShapeEdgePolygon::~PhysicsShapeEdgePolygon()
- {
-
- }
- PhysicsShapeEdgeSegment::PhysicsShapeEdgeSegment()
- {
-
- }
- PhysicsShapeEdgeSegment::~PhysicsShapeEdgeSegment()
- {
-
- }
- void PhysicsShape::setDensity(float density)
- {
- if (density < 0)
- {
- return;
- }
-
- _material.density = density;
-
- if (_material.density == PHYSICS_INFINITY)
- {
- setMass(PHYSICS_INFINITY);
- }else if (_area > 0)
- {
- setMass(_material.density * _area);
- }
- }
- void PhysicsShape::setRestitution(float restitution)
- {
- _material.restitution = restitution;
-
- for (cpShape* shape : _cpShapes)
- {
- cpShapeSetElasticity(shape, restitution);
- }
- }
- void PhysicsShape::setFriction(float friction)
- {
- _material.friction = friction;
-
- for (cpShape* shape : _cpShapes)
- {
- cpShapeSetFriction(shape, friction);
- }
- }
- void PhysicsShape::setSensor(bool sensor)
- {
- if (sensor != _sensor)
- {
- for (cpShape* shape : _cpShapes)
- {
- cpShapeSetSensor(shape, sensor);
- }
- _sensor = sensor;
- }
- }
- void PhysicsShape::recenterPoints(Vec2* points, int count, const Vec2& center)
- {
- cpVect* cpvs = new cpVect[count];
- cpVect centroid = cpCentroidForPoly(count, cpvs);
- for(int i=0; i<count; i++){
- cpvs[i] = cpvsub(cpvs[i], centroid);
- }
- PhysicsHelper::cpvs2points(cpvs, points, count);
- delete[] cpvs;
-
- if (center != Vec2::ZERO)
- {
- for (int i = 0; i < count; ++i)
- {
- points[i] += center;
- }
- }
- }
- Vec2 PhysicsShape::getPolygonCenter(const Vec2* points, int count)
- {
- cpVect* cpvs = new (std::nothrow) cpVect[count];
- cpVect center = cpCentroidForPoly(count, PhysicsHelper::points2cpvs(points, cpvs, count));
- delete[] cpvs;
-
- return PhysicsHelper::cpv2point(center);
- }
- Vec2 PhysicsShape::getPolyonCenter(const Vec2* points, int count)
- {
- return getPolygonCenter(points, count);
- }
- void PhysicsShape::setBody(PhysicsBody *body)
- {
- // already added
- if (body && _body == body)
- {
- return;
- }
-
- if (_body)
- {
- _body->removeShape(this);
- }
-
- for (auto shape : _cpShapes)
- {
- cpShapeSetBody(shape, body == nullptr ? s_sharedBody : body->_cpBody);
- }
- _body = body;
- }
- // PhysicsShapeCircle
- PhysicsShapeCircle* PhysicsShapeCircle::create(float radius, const PhysicsMaterial& material/* = MaterialDefault*/, const Vec2& offset/* = Vec2(0, 0)*/)
- {
- PhysicsShapeCircle* shape = new (std::nothrow) PhysicsShapeCircle();
- if (shape && shape->init(radius, material, offset))
- {
- shape->autorelease();
- return shape;
- }
-
- CC_SAFE_DELETE(shape);
- return nullptr;
- }
- bool PhysicsShapeCircle::init(float radius, const PhysicsMaterial& material/* = MaterialDefault*/, const Vec2& offset /*= Vec2(0, 0)*/)
- {
- do
- {
- _type = Type::CIRCLE;
-
- auto shape = cpCircleShapeNew(s_sharedBody, radius, PhysicsHelper::point2cpv(offset));
- CC_BREAK_IF(shape == nullptr);
- cpShapeSetUserData(shape, this);
-
- addShape(shape);
-
- _area = calculateArea();
- _mass = material.density == PHYSICS_INFINITY ? PHYSICS_INFINITY : material.density * _area;
- _moment = calculateDefaultMoment();
-
- setMaterial(material);
- return true;
- } while (false);
-
- return false;
- }
- float PhysicsShapeCircle::calculateArea(float radius)
- {
- return PhysicsHelper::cpfloat2float(cpAreaForCircle(0, radius));
- }
- float PhysicsShapeCircle::calculateMoment(float mass, float radius, const Vec2& offset)
- {
- return mass == PHYSICS_INFINITY ? PHYSICS_INFINITY
- : PhysicsHelper::cpfloat2float(cpMomentForCircle(mass,
- 0,
- radius,
- PhysicsHelper::point2cpv(offset)));
- }
- float PhysicsShapeCircle::calculateArea()
- {
- return PhysicsHelper::cpfloat2float(cpAreaForCircle(0, cpCircleShapeGetRadius(_cpShapes.front())));
- }
- float PhysicsShapeCircle::calculateDefaultMoment()
- {
- auto shape = _cpShapes.front();
-
- return _mass == PHYSICS_INFINITY ? PHYSICS_INFINITY
- : PhysicsHelper::cpfloat2float(cpMomentForCircle(_mass,
- 0,
- cpCircleShapeGetRadius(shape),
- cpCircleShapeGetOffset(shape)));
- }
- float PhysicsShapeCircle::getRadius() const
- {
- return PhysicsHelper::cpfloat2float(cpCircleShapeGetRadius(_cpShapes.front()));
- }
- Vec2 PhysicsShapeCircle::getOffset()
- {
- return PhysicsHelper::cpv2point(cpCircleShapeGetOffset(_cpShapes.front()));
- }
- void PhysicsShapeCircle::updateScale()
- {
- cpFloat factor = std::abs(_newScaleX / _scaleX);
- cpShape* shape = _cpShapes.front();
- cpVect v = cpCircleShapeGetOffset(shape);
- v = cpvmult(v, factor);
- cpCircleShapeSetOffset(shape, v);
- cpCircleShapeSetRadius(shape, cpCircleShapeGetRadius(shape) * factor);
- PhysicsShape::updateScale();
- }
- // PhysicsShapeEdgeSegment
- PhysicsShapeEdgeSegment* PhysicsShapeEdgeSegment::create(const Vec2& a, const Vec2& b, const PhysicsMaterial& material/* = MaterialDefault*/, float border/* = 1*/)
- {
- PhysicsShapeEdgeSegment* shape = new (std::nothrow) PhysicsShapeEdgeSegment();
- if (shape && shape->init(a, b, material, border))
- {
- shape->autorelease();
- return shape;
- }
-
- CC_SAFE_DELETE(shape);
- return nullptr;
- }
- bool PhysicsShapeEdgeSegment::init(const Vec2& a, const Vec2& b, const PhysicsMaterial& material/* = MaterialDefault*/, float border/* = 1*/)
- {
- do
- {
- _type = Type::EDGESEGMENT;
-
- auto shape = cpSegmentShapeNew(s_sharedBody,
- PhysicsHelper::point2cpv(a),
- PhysicsHelper::point2cpv(b),
- border);
- CC_BREAK_IF(shape == nullptr);
- cpShapeSetUserData(shape, this);
-
- addShape(shape);
-
- _mass = PHYSICS_INFINITY;
- _moment = PHYSICS_INFINITY;
-
- setMaterial(material);
-
- return true;
- } while (false);
-
- return false;
- }
- Vec2 PhysicsShapeEdgeSegment::getPointA() const
- {
- return PhysicsHelper::cpv2point(cpSegmentShapeGetA(_cpShapes.front()));
- }
- Vec2 PhysicsShapeEdgeSegment::getPointB() const
- {
- return PhysicsHelper::cpv2point(cpSegmentShapeGetB(_cpShapes.front()));
- }
- Vec2 PhysicsShapeEdgeSegment::getCenter()
- {
- auto a = PhysicsHelper::cpv2point(cpSegmentShapeGetA(_cpShapes.front()));
- auto b = PhysicsHelper::cpv2point(cpSegmentShapeGetB(_cpShapes.front()));
- return ( a + b ) / 2;
- }
- void PhysicsShapeEdgeSegment::updateScale()
- {
- cpFloat factorX = _newScaleX / _scaleX;
- cpFloat factorY = _newScaleY / _scaleY;
- cpShape* shape = _cpShapes.front();
- cpVect a = cpSegmentShapeGetA(shape);
- a.x *= factorX;
- a.y *= factorY;
- cpVect b = cpSegmentShapeGetB(shape);
- b.x *= factorX;
- b.y *= factorY;
- cpSegmentShapeSetEndpoints(shape, a, b);
- PhysicsShape::updateScale();
- }
- // PhysicsShapeBox
- PhysicsShapeBox* PhysicsShapeBox::create(const Size& size, const PhysicsMaterial& material/* = MaterialDefault*/, const Vec2& offset/* = Vec2(0, 0)*/, float radius/* = 0.0f*/)
- {
- PhysicsShapeBox* shape = new (std::nothrow) PhysicsShapeBox();
- if (shape && shape->init(size, material, offset, radius))
- {
- shape->autorelease();
- return shape;
- }
-
- CC_SAFE_DELETE(shape);
- return nullptr;
- }
- bool PhysicsShapeBox::init(const Size& size, const PhysicsMaterial& material/* = MaterialDefault*/, const Vec2& offset /*= Vec2(0, 0)*/, float radius/* = 0.0f*/)
- {
- do
- {
- _type = Type::BOX;
-
- auto wh = PhysicsHelper::size2cpv(size);
- cpVect vec[4] =
- {
- {-wh.x/2.0f, -wh.y/2.0f}, {-wh.x/2.0f, wh.y/2.0f}, {wh.x/2.0f, wh.y/2.0f}, {wh.x/2.0f, -wh.y/2.0f}
- };
-
- cpTransform transform = cpTransformTranslate(PhysicsHelper::point2cpv(offset));
-
- auto shape = cpPolyShapeNew(s_sharedBody, 4, vec, transform, radius);
- CC_BREAK_IF(shape == nullptr);
- cpShapeSetUserData(shape, this);
-
- addShape(shape);
-
- _area = calculateArea();
- _mass = material.density == PHYSICS_INFINITY ? PHYSICS_INFINITY : material.density * _area;
- _moment = calculateDefaultMoment();
-
- setMaterial(material);
-
- return true;
- } while (false);
-
- return false;
- }
- Size PhysicsShapeBox::getSize() const
- {
- cpShape* shape = _cpShapes.front();
- return PhysicsHelper::cpv2size(cpv(cpvdist(cpPolyShapeGetVert(shape, 1), cpPolyShapeGetVert(shape, 2)),
- cpvdist(cpPolyShapeGetVert(shape, 0), cpPolyShapeGetVert(shape, 1))));
- }
- // PhysicsShapePolygon
- PhysicsShapePolygon* PhysicsShapePolygon::create(const Vec2* points, int count, const PhysicsMaterial& material/* = MaterialDefault*/, const Vec2& offset/* = Vec2(0, 0)*/, float radius/* = 0.0f*/)
- {
- PhysicsShapePolygon* shape = new (std::nothrow) PhysicsShapePolygon();
- if (shape && shape->init(points, count, material, offset, radius))
- {
- shape->autorelease();
- return shape;
- }
-
- CC_SAFE_DELETE(shape);
- return nullptr;
- }
- bool PhysicsShapePolygon::init(const Vec2* points, int count, const PhysicsMaterial& material/* = MaterialDefault*/, const Vec2& offset/* = Vec2(0, 0)*/, float radius/* = 0.0f*/)
- {
- do
- {
- _type = Type::POLYGON;
-
- auto vecs = new (std::nothrow) cpVect[count];
- PhysicsHelper::points2cpvs(points, vecs, count); //count = cpConvexHull((int)count, vecs, nullptr, nullptr, 0);
- cpTransform transform = cpTransformTranslate(PhysicsHelper::point2cpv(offset));
- auto shape = cpPolyShapeNew(s_sharedBody, count, vecs, transform, radius);
- CC_SAFE_DELETE_ARRAY(vecs);
-
- CC_BREAK_IF(shape == nullptr);
- cpShapeSetUserData(shape, this);
-
- addShape(shape);
-
- _area = calculateArea();
- _mass = material.density == PHYSICS_INFINITY ? PHYSICS_INFINITY : material.density * _area;
- _moment = calculateDefaultMoment();
-
- setMaterial(material);
-
- return true;
- } while (false);
-
- return false;
- }
- float PhysicsShapePolygon::calculateArea(const Vec2* points, int count)
- {
- cpVect* vecs = new (std::nothrow) cpVect[count];
- PhysicsHelper::points2cpvs(points, vecs, count);
- float area = PhysicsHelper::cpfloat2float(cpAreaForPoly(count, vecs, 0.0f));
- CC_SAFE_DELETE_ARRAY(vecs);
-
- return area;
- }
- float PhysicsShapePolygon::calculateMoment(float mass, const Vec2* points, int count, const Vec2& offset, float radius)
- {
- cpVect* vecs = new (std::nothrow) cpVect[count];
- PhysicsHelper::points2cpvs(points, vecs, count);
- float moment = mass == PHYSICS_INFINITY ? PHYSICS_INFINITY
- : PhysicsHelper::cpfloat2float(cpMomentForPoly(mass, count, vecs, PhysicsHelper::point2cpv(offset), radius));
- CC_SAFE_DELETE_ARRAY(vecs);
-
- return moment;
- }
- float PhysicsShapePolygon::calculateArea()
- {
- auto shape = _cpShapes.front();
- int count = cpPolyShapeGetCount(shape);
- cpVect* vecs = new cpVect[count];
- for(int i=0;i<count;++i)
- vecs[i] = cpPolyShapeGetVert(shape, i);
- float area = PhysicsHelper::cpfloat2float(cpAreaForPoly(count, vecs, cpPolyShapeGetRadius(shape)));
- CC_SAFE_DELETE_ARRAY(vecs);
- return area;
- }
- float PhysicsShapePolygon::calculateDefaultMoment()
- {
- if(_mass == PHYSICS_INFINITY)
- {
- return PHYSICS_INFINITY;
- }
- else
- {
- auto shape = _cpShapes.front();
- int count = cpPolyShapeGetCount(shape);
- cpVect* vecs = new cpVect[count];
- for(int i=0;i<count;++i)
- vecs[i] = cpPolyShapeGetVert(shape, i);
- float moment = PhysicsHelper::cpfloat2float(cpMomentForPoly(_mass, count, vecs, cpvzero, cpPolyShapeGetRadius(shape)));
- CC_SAFE_DELETE_ARRAY(vecs);
- return moment;
- }
- }
- Vec2 PhysicsShapePolygon::getPoint(int i) const
- {
- return PhysicsHelper::cpv2point(cpPolyShapeGetVert(_cpShapes.front(), i));
- }
- void PhysicsShapePolygon::getPoints(Vec2* outPoints) const
- {
- auto shape = _cpShapes.front();
- int count = cpPolyShapeGetCount(shape);
- cpVect* vecs = new cpVect[count];
- for(int i=0;i<count;++i)
- vecs[i] = cpPolyShapeGetVert(shape, i);
- PhysicsHelper::cpvs2points(vecs, outPoints, count);
- CC_SAFE_DELETE_ARRAY(vecs);
- }
- int PhysicsShapePolygon::getPointsCount() const
- {
- return cpPolyShapeGetCount(_cpShapes.front());
- }
- Vec2 PhysicsShapePolygon::getCenter()
- {
- auto shape = _cpShapes.front();
- int count = cpPolyShapeGetCount(shape);
- cpVect* vecs = new cpVect[count];
- for(int i=0;i<count;++i)
- vecs[i] = cpPolyShapeGetVert(shape, i);
-
- Vec2 center = PhysicsHelper::cpv2point(cpCentroidForPoly(count, vecs));
- CC_SAFE_DELETE_ARRAY(vecs);
-
- return center;
- }
- void PhysicsShapePolygon::updateScale()
- {
- cpFloat factorX = _newScaleX / _scaleX;
- cpFloat factorY = _newScaleY / _scaleY;
- auto shape = _cpShapes.front();
- int count = cpPolyShapeGetCount(shape);
- cpVect* vects = new cpVect[count];
- for(int i=0;i<count;++i)
- vects[i] = cpPolyShapeGetVert(shape, i);
- for (int i = 0; i < count; ++i)
- {
- vects[i].x *= factorX;
- vects[i].y *= factorY;
- }
- // convert hole to clockwise
- if (factorX * factorY < 0)
- {
- for (int i = 0; i < count / 2; ++i)
- {
- cpVect v = vects[i];
- vects[i] = vects[count - i - 1];
- vects[count - i - 1] = v;
- }
- }
-
- cpPolyShapeSetVertsRaw(shape, count, vects);
- CC_SAFE_DELETE_ARRAY(vects);
-
- PhysicsShape::updateScale();
- }
- // PhysicsShapeEdgeBox
- PhysicsShapeEdgeBox* PhysicsShapeEdgeBox::create(const Size& size, const PhysicsMaterial& material/* = MaterialDefault*/, float border/* = 1*/, const Vec2& offset/* = Vec2(0, 0)*/)
- {
- PhysicsShapeEdgeBox* shape = new (std::nothrow) PhysicsShapeEdgeBox();
- if (shape && shape->init(size, material, border, offset))
- {
- shape->autorelease();
- return shape;
- }
-
- CC_SAFE_DELETE(shape);
- return nullptr;
- }
- bool PhysicsShapeEdgeBox::init(const Size& size, const PhysicsMaterial& material/* = MaterialDefault*/, float border/* = 1*/, const Vec2& offset/*= Vec2(0, 0)*/)
- {
- do
- {
- _type = Type::EDGEBOX;
-
- cpVect vec[4] = {};
- vec[0] = PhysicsHelper::point2cpv(Vec2(-size.width/2+offset.x, -size.height/2+offset.y));
- vec[1] = PhysicsHelper::point2cpv(Vec2(+size.width/2+offset.x, -size.height/2+offset.y));
- vec[2] = PhysicsHelper::point2cpv(Vec2(+size.width/2+offset.x, +size.height/2+offset.y));
- vec[3] = PhysicsHelper::point2cpv(Vec2(-size.width/2+offset.x, +size.height/2+offset.y));
-
- int i = 0;
- for (; i < 4; ++i)
- {
- auto shape = cpSegmentShapeNew(s_sharedBody, vec[i], vec[(i + 1) % 4], border);
- CC_BREAK_IF(shape == nullptr);
- cpShapeSetUserData(shape, this);
- addShape(shape);
- }
- CC_BREAK_IF(i < 4);
-
- _mass = PHYSICS_INFINITY;
- _moment = PHYSICS_INFINITY;
-
- setMaterial(material);
-
- return true;
- } while (false);
-
- return false;
- }
- // PhysicsShapeEdgeBox
- PhysicsShapeEdgePolygon* PhysicsShapeEdgePolygon::create(const Vec2* points, int count, const PhysicsMaterial& material/* = MaterialDefault*/, float border/* = 1*/)
- {
- PhysicsShapeEdgePolygon* shape = new (std::nothrow) PhysicsShapeEdgePolygon();
- if (shape && shape->init(points, count, material, border))
- {
- shape->autorelease();
- return shape;
- }
-
- CC_SAFE_DELETE(shape);
- return nullptr;
- }
- bool PhysicsShapeEdgePolygon::init(const Vec2* points, int count, const PhysicsMaterial& material/* = MaterialDefault*/, float border/* = 1*/)
- {
- cpVect* vec = nullptr;
- do
- {
- _type = Type::EDGEPOLYGON;
-
- vec = new (std::nothrow) cpVect[count];
- PhysicsHelper::points2cpvs(points, vec, count);
-
- int i = 0;
- for (; i < count; ++i)
- {
- auto shape = cpSegmentShapeNew(s_sharedBody, vec[i], vec[(i + 1) % count], border);
- CC_BREAK_IF(shape == nullptr);
- cpShapeSetUserData(shape, this);
- cpShapeSetElasticity(shape, 1.0f);
- cpShapeSetFriction(shape, 1.0f);
- addShape(shape);
- }
- CC_SAFE_DELETE_ARRAY(vec);
-
- CC_BREAK_IF(i < count);
-
- _mass = PHYSICS_INFINITY;
- _moment = PHYSICS_INFINITY;
-
- setMaterial(material);
-
- return true;
- } while (false);
-
- CC_SAFE_DELETE_ARRAY(vec);
-
- return false;
- }
- Vec2 PhysicsShapeEdgePolygon::getCenter()
- {
- int count = (int)_cpShapes.size();
- cpVect* points = new (std::nothrow) cpVect[count];
- int i = 0;
- for(auto shape : _cpShapes)
- {
- points[i++] = cpSegmentShapeGetA(shape);
- }
-
- Vec2 center = PhysicsHelper::cpv2point(cpCentroidForPoly(count, points));
- delete[] points;
-
- return center;
- }
- void PhysicsShapeEdgePolygon::getPoints(cocos2d::Vec2 *outPoints) const
- {
- int i = 0;
- for(auto shape : _cpShapes)
- {
- outPoints[i++] = PhysicsHelper::cpv2point(cpSegmentShapeGetA(shape));
- }
- }
- int PhysicsShapeEdgePolygon::getPointsCount() const
- {
- return static_cast<int>(_cpShapes.size());
- }
- // PhysicsShapeEdgeChain
- PhysicsShapeEdgeChain* PhysicsShapeEdgeChain::create(const Vec2* points, int count, const PhysicsMaterial& material/* = MaterialDefault*/, float border/* = 1*/)
- {
- PhysicsShapeEdgeChain* shape = new (std::nothrow) PhysicsShapeEdgeChain();
- if (shape && shape->init(points, count, material, border))
- {
- shape->autorelease();
- return shape;
- }
-
- CC_SAFE_DELETE(shape);
- return nullptr;
- }
- void PhysicsShapeEdgePolygon::updateScale()
- {
- cpFloat factorX = _newScaleX / _scaleX;
- cpFloat factorY = _newScaleY / _scaleY;
- for (auto shape : _cpShapes)
- {
- cpVect a = cpSegmentShapeGetA(shape);
- a.x *= factorX;
- a.y *= factorY;
- cpVect b = cpSegmentShapeGetB(shape);
- b.x *= factorX;
- b.y *= factorY;
- cpSegmentShapeSetEndpoints(shape, a, b);
- }
-
- PhysicsShape::updateScale();
- }
- bool PhysicsShapeEdgeChain::init(const Vec2* points, int count, const PhysicsMaterial& material/* = MaterialDefault*/, float border/* = 1*/)
- {
- cpVect* vec = nullptr;
- do
- {
- _type = Type::EDGECHAIN;
-
- vec = new (std::nothrow) cpVect[count];
- PhysicsHelper::points2cpvs(points, vec, count);
-
- int i = 0;
- for (; i < count - 1; ++i)
- {
- auto shape = cpSegmentShapeNew(s_sharedBody, vec[i], vec[i + 1], border);
- CC_BREAK_IF(shape == nullptr);
- cpShapeSetUserData(shape, this);
- cpShapeSetElasticity(shape, 1.0f);
- cpShapeSetFriction(shape, 1.0f);
- addShape(shape);
- }
- CC_SAFE_DELETE_ARRAY(vec);
- CC_BREAK_IF(i < count - 1);
-
- _mass = PHYSICS_INFINITY;
- _moment = PHYSICS_INFINITY;
-
- setMaterial(material);
-
- return true;
- } while (false);
-
- CC_SAFE_DELETE_ARRAY(vec);
-
- return false;
- }
- Vec2 PhysicsShapeEdgeChain::getCenter()
- {
- int count = (int)_cpShapes.size() + 1;
- cpVect* points = new (std::nothrow) cpVect[count];
- int i = 0;
- for(auto shape : _cpShapes)
- {
- points[i++] = cpSegmentShapeGetA(shape);
- }
-
- points[i++] = cpSegmentShapeGetB(_cpShapes.back());
-
- Vec2 center = PhysicsHelper::cpv2point(cpCentroidForPoly(count, points));
- delete[] points;
-
- return center;
- }
- void PhysicsShapeEdgeChain::getPoints(Vec2* outPoints) const
- {
- int i = 0;
- for(auto shape : _cpShapes)
- {
- outPoints[i++] = PhysicsHelper::cpv2point(cpSegmentShapeGetA(shape));
- }
-
- outPoints[i++] = PhysicsHelper::cpv2point(cpSegmentShapeGetB(_cpShapes.back()));
- }
- int PhysicsShapeEdgeChain::getPointsCount() const
- {
- return static_cast<int>(_cpShapes.size() + 1);
- }
- void PhysicsShapeEdgeChain::updateScale()
- {
- cpFloat factorX = _newScaleX / _scaleX;
- cpFloat factorY = _newScaleY / _scaleY;
- for (auto shape : _cpShapes)
- {
- cpVect a = cpSegmentShapeGetA(shape);
- a.x *= factorX;
- a.y *= factorY;
- cpVect b = cpSegmentShapeGetB(shape);
- b.x *= factorX;
- b.y *= factorY;
- cpSegmentShapeSetEndpoints(shape, a, b);
- }
-
- PhysicsShape::updateScale();
- }
- void PhysicsShape::setGroup(int group)
- {
- if (group < 0)
- {
- for (auto shape : _cpShapes)
- {
- cpShapeSetFilter(shape, cpShapeFilterNew(group, CP_ALL_CATEGORIES, CP_ALL_CATEGORIES));
- }
- }
-
- _group = group;
- }
- bool PhysicsShape::containsPoint(const Vec2& point) const
- {
- for (auto shape : _cpShapes)
- {
- if (cpShapePointQuery(shape, PhysicsHelper::point2cpv(point), nullptr) < 0)
- {
- return true;
- }
- }
-
- return false;
- }
- NS_CC_END
- #endif // CC_USE_PHYSICS
|