/****************************************************************************
Copyright (c) 2013 Chukong Technologies Inc.
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.
****************************************************************************/
#ifndef __CCPHYSICS_BODY_H__
#define __CCPHYSICS_BODY_H__
#include "ccConfig.h"
#if CC_USE_PHYSICS
#include "CCRef.h"
#include "CCGeometry.h"
#include "CCPhysicsShape.h"
#include "CCVector.h"
NS_CC_BEGIN
class Node;
class Sprite;
class PhysicsWorld;
class PhysicsJoint;
class PhysicsBodyInfo;
typedef Point Vect;
const PhysicsMaterial PHYSICSBODY_MATERIAL_DEFAULT(0.1f, 0.5f, 0.5f);
/**
* 一个由物理因素构成的body, 它可以附上一个或多个形状
* 你可以用createXXX创建一个body,它将用你指定的值(默认情况 PHYSICSBODY_MATERIAL_DEFAULT的默认密度为0.1)自动计算质量和力矩。
基本公式:mass = density * area.
* 你可以用createEdgeXXX创建一个body,质量和力矩由默认值PHYSICS_INFINITY决定,它将是一个静态的body。
* 你可以用setMass()改变质量,用setMoment()改变密度,用setDynamic()设置成一个静态的body。
*/
class PhysicsBody : public Ref
{
public:
/** 用默认质量和力矩创建一个body */
static PhysicsBody* create();
/** mass 和 默认力矩,创建一个body */
static PhysicsBody* create(float mass);
/** mass 和 moment,创建一个body */
static PhysicsBody* create(float mass, float moment);
/**
@brief: 创建一个圆形body
radius: 半径
material: 材质
*/
static PhysicsBody* createCircle(float radius, const PhysicsMaterial& material = PHYSICSBODY_MATERIAL_DEFAULT, const Point& offset = Point::ZERO);
/**
@brief: 创建一个方形body
size: size(widht,height)
*/
static PhysicsBody* createBox(const Size& size, const PhysicsMaterial& material = PHYSICSBODY_MATERIAL_DEFAULT, const Point& offset = Point::ZERO);
/**
* @brief: 创建一个多边形的body
* points: point数组,按顺时针方向绕成的封闭图形。
*/
static PhysicsBody* createPolygon(const Point* points, int count, const PhysicsMaterial& material = PHYSICSBODY_MATERIAL_DEFAULT, const Point& offset = Point::ZERO);
/**
@brief: 创建一个静态的线段
border: 边缘宽度
*/
static PhysicsBody* createEdgeSegment(const Point& a, const Point& b, const PhysicsMaterial& material = PHYSICSBODY_MATERIAL_DEFAULT, float border = 1);
/**
@brief: 创建一个静态的方形
*/
static PhysicsBody* createEdgeBox(const Size& size, const PhysicsMaterial& material = PHYSICSBODY_MATERIAL_DEFAULT, float border = 1, const Point& offset = Point::ZERO);
/**
@brief: 创建一个静态的多边形
*/
static PhysicsBody* createEdgePolygon(const Point* points, int count, const PhysicsMaterial& material = PHYSICSBODY_MATERIAL_DEFAULT, float border = 1);
/**
@brief: 创建一个静态的链条形
*/
static PhysicsBody* createEdgeChain(const Point* points, int count, const PhysicsMaterial& material = PHYSICSBODY_MATERIAL_DEFAULT, float border = 1);
/*
* @brief 添加一个形状到body
* @param shape 添加的形状
* @param addMassAndMoment == true,添加形状的质量个力矩将被添加,默认为true。
*/
virtual PhysicsShape* addShape(PhysicsShape* shape, bool addMassAndMoment = true);
/*
* @brief 从body移除一个形状
* @param shape 移除的形状
* @param addMassAndMoment == true,移除形状的质量个力矩将被移除,默认为true。
*/
void removeShape(PhysicsShape* shape, bool reduceMassAndMoment = true);
/*
* @brief 通过tag标记移除一个形状
*/
void removeShape(int tag, bool reduceMassAndMoment = true);
/* 移除所有形状 */
void removeAllShapes(bool reduceMassAndMoment = true);
/* 获取body的所有形状 */
inline const Vector
/* 获取body的第一个形状 */
inline PhysicsShape* getFirstShape() const { return _shapes.size() >= 1 ? _shapes.at(0) : nullptr; }
/* 通过tag标记获取一个形状 */
PhysicsShape* getShape(int tag) const;
/**
@brief: 给body施加一个力,循序渐进——ApplyForce
force: 动力方向上的一个向量。
*/
virtual void applyForce(const Vect& force);
/**
@brief: 给body施加一个力,循序渐进——ApplyForce
force: 动力方向上的一个向量。
offset: 偏移度,值越大 旋转越快 偏移角度越大
*/
virtual void applyForce(const Vect& force, const Point& offset);
/** 重置所有应用到body上的力 */
virtual void resetForces();
/**
@brief: 给body施加一个力,即时叠加——applyImpulse
*/
virtual void applyImpulse(const Vect& impulse);
/** Applies a continuous force to body. */
virtual void applyImpulse(const Vect& impulse, const Point& offset);
/**
@brief: 给body施加一个力,朝向设定点角度方向的力矩,使其旋转。
*/
virtual void applyTorque(float torque);
/** 设置速度 */
virtual void setVelocity(const Vect& velocity);
/** 获取速度 */
virtual Point getVelocity();
/** 设置角速度 */
virtual void setAngularVelocity(float velocity);
/** 设置角速度,相对于局部某一点 */
virtual Point getVelocityAtLocalPoint(const Point& point);
/** 设置角速度,相对于世界某一点 */
virtual Point getVelocityAtWorldPoint(const Point& point);
/** 获取角速度 */
virtual float getAngularVelocity();
/** 设置速度的最大值 */
virtual void setVelocityLimit(float limit);
/** 获取速度的最大值 */
virtual float getVelocityLimit();
/** 设置角速度的最大值 */
virtual void setAngularVelocityLimit(float limit);
/** 获取角速度的最大值 */
virtual float getAngularVelocityLimit();
/** 将body从它所加入的物理世界移除 */
void removeFromWorld();
/** 获取body所在的物理世界 */
inline PhysicsWorld* getWorld() const { return _world; }
/** 获取所有关节 */
inline const std::vector
/** 获取body所设置的精灵 */
inline Node* getNode() const { return _node; }
/**
* 设置类别掩码
* 用1bit掩码位来标记,物理body所属的一个类别。
* 每一个物理body在场景中能被分配到多达32个不同的类别,它们分别对应一个比特的比特掩码位。你可以定义你在游戏中使用的掩码值。
* 当您定义物理body相互作用时,你的游戏通知这些相互作用, 属性collisionBitMask和属性contactTestBitMask可以结合使用。
* 默认值是0xFFFFFFFF,所有位都设置。
*/
void setCategoryBitmask(int bitmask);
/**
* 设置接触掩码
* 当两个body共享相同的空间时,每个body的类别掩码对其他body的接触掩码执行逻辑与。
* 如果任意比较结果为非零值,PhysicsContact对象被创建并且传递到物理世界的委托。
* 为获得最佳的性能,我仅仅设置我们感兴趣接触掩码位。
* 默认值是0x00000000(所有位为空)。
*/
void setContactTestBitmask(int bitmask);
/**
* 设置碰撞掩码
* 当两个body相互接触,发生碰撞时。该body的碰撞掩码与另一个body的类别掩码执行逻辑与操作。
* 如果结果为非零值,该body将受到另一个body的碰撞。
* 每个body都可以独立的选择,他们是否受到其他body的影响。
* 例如:你可以用这一点来进行避免碰撞计算,这将使你忽略掉速度的改变。
* 默认值为0xFFFFFFFF,(所有位都设置)
*/
void setCollisionBitmask(int bitmask);
/** get the category bit mask */
inline int getCategoryBitmask() const { return _categoryBitmask; }
/** get the contact test bit mask */
inline int getContactTestBitmask() const { return _contactTestBitmask; }
/** get the collision bit mask */
inline int getCollisionBitmask() const { return _collisionBitmask; }
/**
* 设置body组。
* 碰撞组让你指定一个完整的组下标。你可以让同一个组下标的所有body都接受碰撞或者都不接收碰撞。
* 它比位掩码优先级更高。
*/
void setGroup(int group);
/** 获取body属于哪个组 */
inline int getGroup() const { return _group; }
/** 获取body位置 */
Point getPosition() const;
/** 获取body角度 */
float getRotation() const;
/** 设置body的偏移量, 它是相对于节点的位置 */
void setPositionOffset(const Point& position);
/** get body position offset. */
Point getPositionOffset() const;
/** 获取偏移量 */
void setRotationOffset(float rotation);
/** 设置旋转偏移量 */
float getRotationOffset() const;
/**
* @brief body是否为动态的。
*/
inline bool isDynamic() const { return _dynamic; }
/**
* @brief 设置body,true为动态,false为静态。就是不动。
*/
void setDynamic(bool dynamic);
/**
* @brief 设置body的质量。
* 备注:如果你需要给body增加或者减少质量,不要使用setMass(getMass() +/- mass),
* 因为body的质量可能等于PHYSICS_INFINITY,那么它将引起一些不可意料的结果,请用addMass()代替。
*/
void setMass(float mass);
/** 获取body质量 */
inline float getMass() const { return _mass; }
/**
* @brief 增加质量
* 如果 _mass == PHYSICS_INFINITY,那么body质量不变;
* 如果 mass == PHYSICS_INFINITY,那么body质量为PHYSICS_INFINITY;
* 如果 mass == -PHYSICS_INFINITY,那么body质量将不会改变;
* 如果 mass + _mass <= 0,那么body的质量将会等于MASS_DEFAULT(1.0);
* 其他情况mass = mass + _mass;
*/
void addMass(float mass);
/**
* @brief 设置body力矩,
* 备注:同设置质量一样。
*/
void setMoment(float moment);
/** 获取body力矩 */
inline float getMoment() const { return _moment; }
/**
* @brief 添加body力矩
*/
void addMoment(float moment);
/** 获取线性阻力 */
inline float getLinearDamping() const { return _linearDamping; }
/**
* 设置线性阻力
* 它被用来模拟body与流体或空气的阻力。
* 它的值在0.0f 到 1.0f之间。
*/
inline void setLinearDamping(float damping) { _linearDamping = damping; updateDamping(); }
/** 获取角阻力 */
inline float getAngularDamping() const { return _angularDamping; }
/** 设置角阻力 */
inline void setAngularDamping(float damping) { _angularDamping = damping; updateDamping(); }
/** body是否为休息状态 */
bool isResting() const;
/** set body to rest */
void setResting(bool rest) const;
/**
* body是否可用
*/
inline bool isEnabled() const { return _enable; }
/**
* set the enable value.
* if the body it isn't enabled, it will not has simulation by world
*/
void setEnable(bool enable);
/** 角旋转是否可用 */
inline bool isRotationEnabled() const { return _rotationEnable; }
/** set the body is allow rotation or not */
void setRotationEnable(bool enable);
/** 是否受到物理世界的引力 */
inline bool isGravityEnabled() const { return _gravityEnable; }
/** set the body is affected by the physics world's gravitational force or not. */
void setGravityEnable(bool enable);
/** 获取body的tag标记 */
inline int getTag() const { return _tag; }
/** set the body's tag */
inline void setTag(int tag) { _tag = tag; }
/** 世界坐标转换成本地坐标 */
Point world2Local(const Point& point);
/** 本地坐标转换成世界坐标 */
Point local2World(const Point& point);
protected:
bool init();
virtual void setPosition(Point position);
virtual void setRotation(float rotation);
void update(float delta);
void removeJoint(PhysicsJoint* joint);
inline void updateDamping() { _isDamping = _linearDamping != 0.0f || _angularDamping != 0.0f; }
protected:
PhysicsBody();
virtual ~PhysicsBody();
protected:
Node* _node;
std::vector
Vector
PhysicsWorld* _world;
PhysicsBodyInfo* _info;
bool _dynamic;
bool _enable;
bool _rotationEnable;
bool _gravityEnable;
bool _massDefault;
bool _momentDefault;
float _mass;
float _area;
float _density;
float _moment;
bool _isDamping;
float _linearDamping;
float _angularDamping;
int _tag;
int _categoryBitmask;
int _collisionBitmask;
int _contactTestBitmask;
int _group;
bool _positionResetTag; /// 为了避免body位置复位的时候调用 Node::setPosition().
bool _rotationResetTag; /// 为了避免body位置复位的时候调用 Node::setPosition().
Point _positionOffset;
float _rotationOffset;
friend class PhysicsWorld;
friend class PhysicsShape;
friend class PhysicsJoint;
friend class Node;
};
NS_CC_END
#endif // CC_USE_PHYSICS
#endif // __CCPHYSICS_BODY_H__