CCPhysicsWorld.h 14.8 KB
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436
/****************************************************************************
 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.
 ****************************************************************************/

#ifndef __CCPHYSICS_WORLD_H__
#define __CCPHYSICS_WORLD_H__

#include "base/ccConfig.h"
#if CC_USE_PHYSICS

#include <list>
#include "base/CCVector.h"
#include "math/CCGeometry.h"
#include "physics/CCPhysicsBody.h"

struct cpSpace;

NS_CC_BEGIN

class PhysicsBody;
class PhysicsJoint;
class PhysicsShape;
class PhysicsContact;

class Director;
class Node;
class Sprite;
class Scene;
class DrawNode;
class PhysicsDebugDraw;
class EventDispatcher;

class PhysicsWorld;

typedef struct PhysicsRayCastInfo
{
    PhysicsShape* shape;
    Vec2 start;
    Vec2 end;              ///< in lua, it's name is "ended"
    Vec2 contact;
    Vec2 normal;

    // FIXME: correct thing to do is use `cpFloat` instead of float.
    // but in order to do so, we should include "chipmunk_types.h"
    // in Chipmunk v7.0, chipmunk_types includes all the mac types that
    // conflicts with cocos2d Size, Point,... etc types. And all the CocosStudio
    // lib will need to use the `cocos2d::` namespace prefix. And it is easier to do this
    // than change all the cocosstudio library (and also users code)
    float fraction;
    void* data;
}PhysicsRayCastInfo;

/**
 * @brief Called for each fixture found in the query. You control how the ray cast
 * proceeds by returning a float:
 * return true: continue
 * return false: terminate the ray cast
 * @param fixture the fixture hit by the ray
 * @param point the point of initial intersection
 * @param normal the normal vector at the point of intersection
 * @return true to continue, false to terminate
 */
typedef std::function<bool(PhysicsWorld& world, const PhysicsRayCastInfo& info, void* data)> PhysicsRayCastCallbackFunc;
typedef std::function<bool(PhysicsWorld&, PhysicsShape&, void*)> PhysicsQueryRectCallbackFunc;
typedef PhysicsQueryRectCallbackFunc PhysicsQueryPointCallbackFunc;

/**
 * @addtogroup physics
 * @{
 * @addtogroup physics_2d
 * @{
 */

/**
 * @class PhysicsWorld CCPhysicsWorld.h
 * @brief An PhysicsWorld object simulates collisions and other physical properties. You do not create PhysicsWorld objects directly; instead, you can get it from an Scene object.
 */
class CC_DLL PhysicsWorld
{
public:
    static const int DEBUGDRAW_NONE;        ///< draw nothing
    static const int DEBUGDRAW_SHAPE;       ///< draw shapes
    static const int DEBUGDRAW_JOINT;       ///< draw joints
    static const int DEBUGDRAW_CONTACT;     ///< draw contact
    static const int DEBUGDRAW_ALL;         ///< draw all
    
public:
    /**
    * Adds a joint to this physics world.
    *
    * This joint will be added to this physics world at next frame.
    * @attention If this joint is already added to another physics world, it will be removed from that world first and then add to this world.
    * @param   joint   A pointer to an existing PhysicsJoint object.
    */
    virtual void addJoint(PhysicsJoint* joint);

    /**
    * Remove a joint from this physics world.
    *
    * If this world is not locked, the joint is removed immediately, otherwise at next frame. 
    * If this joint is connected with a body, it will be removed from the body also.
    * @param   joint   A pointer to an existing PhysicsJoint object.
    * @param   destroy   true this joint will be destroyed after remove from this world, false otherwise.
    */
    virtual void removeJoint(PhysicsJoint* joint, bool destroy = true);

    /**
    * Remove all joints from this physics world.
    * 
    * @attention This function is invoked in the destructor of this physics world, you do not use this api in common.
    * @param   destroy   true all joints will be destroyed after remove from this world, false otherwise.
    */
    virtual void removeAllJoints(bool destroy = true);
    
    /**
    * Remove a body from this physics world. 
    * 
    * If this world is not locked, the body is removed immediately, otherwise at next frame.
    * @attention If this body has joints, those joints will be removed also.
    * @param   body   A pointer to an existing PhysicsBody object.
    */
    virtual void removeBody(PhysicsBody* body);
    
    /**
    * Remove body by tag. 
    * 
    * If this world is not locked, the object is removed immediately, otherwise at next frame.
    * @attention If this body has joints, those joints will be removed also.    
    * @param   tag   An integer number that identifies a PhysicsBody object.
    */
    virtual void removeBody(int tag);

    /**
    * Remove all bodies from physics world. 
    * 
    * If this world is not locked, those body are removed immediately, otherwise at next frame.
    */
    virtual void removeAllBodies();
    
    /**
    * Searches for physics shapes that intersects the ray. 
    *
    * Query this physics world along the line segment from start to end.
    * @param   func   Func is called for each shape found.
    * @param   start   A Vec2 object contains the begin position of the ray.
    * @param   end   A Vec2 object contains the end position of the ray.
    * @param   data   User defined data, it is passed to func. 
    */
    void rayCast(PhysicsRayCastCallbackFunc func, const Vec2& start, const Vec2& end, void* data);
    
    /**
    * Searches for physics shapes that contains in the rect. 
    *
    * Query this physics world to find all shapes overlap rect.
    * @param   func   Func is called for each shape whose bounding box overlaps rect. 
    * @param   rect   A Rect object contains a rectangle's x, y, width and height.
    * @param   data   User defined data, it is passed to func. 
    */
    void queryRect(PhysicsQueryRectCallbackFunc func, const Rect& rect, void* data);
    
    /**
    * Searches for physics shapes that contains the point. 
    *
    * @attention The point must lie inside a shape.
    * @param   func   Func is called for each shape contains the point.
    * @param   point   A Vec2 object contains the position of the point.
    * @param   data   User defined data, it is passed to func. 
    */
    void queryPoint(PhysicsQueryPointCallbackFunc func, const Vec2& point, void* data);
    
    /**
    * Get physics shapes that contains the point. 
    * 
    * All shapes contains the point will be pushed in a Vector<PhysicsShape*> object.
    * @attention The point must lie inside a shape.
    * @param   point   A Vec2 object contains the position of the point.
    * @return A Vector<PhysicsShape*> object contains all found PhysicsShape pointer.
    */
    Vector<PhysicsShape*> getShapes(const Vec2& point) const;
    
    /**
    * Get the nearest physics shape that contains the point. 
    * 
    * Query this physics world at point and return the closest shape.
    * @param   point   A Vec2 object contains the position of the point.
    * @return A PhysicsShape object pointer or nullptr if no shapes were found
    */
    PhysicsShape* getShape(const Vec2& point) const;

    /**
    * Get all the bodies that in this physics world.
    *
    * @return A Vector<PhysicsBody*>& object contains all bodies in this physics world. 
    */
    const Vector<PhysicsBody*>& getAllBodies() const;

    /**
    * Get a body by tag. 
    * 
    * @param   tag   An integer number that identifies a PhysicsBody object. 
    * @return A PhysicsBody object pointer or nullptr if no shapes were found.
    */
    PhysicsBody* getBody(int tag) const;
    
    /**
    * Get a scene contain this physics world.
    * 
    * @attention This value is initialized in constructor
    * @return A Scene object reference.
    */
    Scene& getScene() const { return *_scene; }
    
    /**
    * Get the gravity value of this physics world.
    *
    * @return A Vec2 object.
    */
    Vec2 getGravity() const { return _gravity; }
    
    /**
    * set the gravity value of this physics world.
    *
    * @param gravity A gravity value of this physics world.
    */
    void setGravity(const Vec2& gravity);
    
    /**
     * Set the speed of this physics world.
     *
     * @attention if you setAutoStep(false), this won't work.
     * @param speed  A float number. Speed is the rate at which the simulation executes. default value is 1.0.
     */
    void setSpeed(float speed) { if(speed >= 0.0f) { _speed = speed; } }
    
    /**
    * Get the speed of this physics world.
    *
    * @return A float number.
    */
    float getSpeed() { return _speed; }
    
    /**
     * Set the update rate of this physics world
     * 
     * Update rate is the value of EngineUpdateTimes/PhysicsWorldUpdateTimes.
     * Set it higher can improve performance, set it lower can improve accuracy of physics world simulation.
     * @attention if you setAutoStep(false), this won't work.
     * @param rate An integer number, default value is 1.0.
     */
    void setUpdateRate(int rate) { if(rate > 0) { _updateRate = rate; } }


    /**
    * Get the update rate of this physics world.
    *
    * @return An integer number.
    */
    int getUpdateRate() { return _updateRate; }

    /**
     * set the number of substeps in an update of the physics world.
     * 
     * One physics update will be divided into several substeps to increase its accuracy.
     * @param steps An integer number, default value is 1.
     */
    void setSubsteps(int steps);

    /**
    * Get the number of substeps of this physics world.
    *
    * @return An integer number.
    */
    int getSubsteps() const { return _substeps; }
    
    /**
     * set the number of update of the physics world in a second.
     * 0 - disable fixed step system
     * default value is 0
     */
    void setFixedUpdateRate(int updatesPerSecond) { if(updatesPerSecond > 0) { _fixedRate = updatesPerSecond; } }
    /** get the number of substeps */
    int getFixedUpdateRate() const { return _fixedRate; }

    /**
    * Set the debug draw mask of this physics world.
    * 
    * This physics world will draw shapes and joints by DrawNode according to mask.
    * @param mask Mask has four value:DEBUGDRAW_NONE, DEBUGDRAW_SHAPE, DEBUGDRAW_JOINT, DEBUGDRAW_CONTACT and DEBUGDRAW_ALL, default is DEBUGDRAW_NONE
    */
    void setDebugDrawMask(int mask);

    /**
     * set the callback which invoked before update of each object in physics world.
     */
    void setPreUpdateCallback(const std::function<void()> &callback);

    /**
     * set the callback which invoked after update of each object in physics world.
     */
    void setPostUpdateCallback(const std::function<void()> &callback);

    /**
    * Get the debug draw mask.
    *
    * @return An integer number.
    */
    int getDebugDrawMask() { return _debugDrawMask; }
    
    /**
     * To control the step of physics.
     *
     * If you want control it by yourself( fixed-timestep for example ), you can set this to false and call step by yourself.
     * @attention If you set auto step to false, setSpeed setSubsteps and setUpdateRate won't work, you need to control the time step by yourself.
     * @param autoStep A bool object, default value is true.
     */
    void setAutoStep(bool autoStep){ _autoStep = autoStep; }


    /**
    * Get the auto step of this physics world.
    *
    * @return A bool object.
    */
    bool isAutoStep() { return _autoStep; }

    /**
     * The step for physics world.
     *
     * The times passing for simulate the physics.
     * @attention You need to setAutoStep(false) first before it can work.
     * @param   delta   A float number.
     */
    void step(float delta);
    
protected:
    static PhysicsWorld* construct(Scene* scene);
    bool init();
    
    
    virtual void addBody(PhysicsBody* body);
    virtual void addShape(PhysicsShape* shape);
    virtual void removeShape(PhysicsShape* shape);
    virtual void update(float delta, bool userCall = false);

    virtual void debugDraw();
    
    virtual bool collisionBeginCallback(PhysicsContact& contact);
    virtual bool collisionPreSolveCallback(PhysicsContact& contact);
    virtual void collisionPostSolveCallback(PhysicsContact& contact);
    virtual void collisionSeparateCallback(PhysicsContact& contact);
    
    virtual void doAddBody(PhysicsBody* body);
    virtual void doRemoveBody(PhysicsBody* body);
    virtual void doRemoveJoint(PhysicsJoint* joint);
    virtual void addBodyOrDelay(PhysicsBody* body);
    virtual void removeBodyOrDelay(PhysicsBody* body);
    virtual void updateBodies();
    virtual void updateJoints();

protected:
    Vec2 _gravity;
    float _speed;
    int _updateRate;
    int _updateRateCount;
    float _updateTime;
    int _substeps;
    int _fixedRate;
    cpSpace* _cpSpace;
    
    bool _updateBodyTransform;
    Vector<PhysicsBody*> _bodies;
    std::list<PhysicsJoint*> _joints;
    Scene* _scene;
    
    bool _autoStep;
    DrawNode* _debugDraw;
    int _debugDrawMask;
    
    EventDispatcher* _eventDispatcher;

    Vector<PhysicsBody*> _delayAddBodies;
    Vector<PhysicsBody*> _delayRemoveBodies;
    std::vector<PhysicsJoint*> _delayAddJoints;
    std::vector<PhysicsJoint*> _delayRemoveJoints;
    
    std::function<void()> _preUpdateCallback;
    std::function<void()> _postUpdateCallback;

protected:
    PhysicsWorld();
    virtual ~PhysicsWorld();
    
    void beforeSimulation(Node *node, const Mat4& parentToWorldTransform, float nodeParentScaleX, float nodeParentScaleY, float parentRotation);
    void afterSimulation(Node* node, const Mat4& parentToWorldTransform, float parentRotation);

    friend class Node;
    friend class Sprite;
    friend class Scene;
    friend class Director;
    friend class PhysicsBody;
    friend class PhysicsShape;
    friend class PhysicsJoint;
    friend class PhysicsWorldCallback;
    friend class PhysicsDebugDraw;
};

extern const float CC_DLL PHYSICS_INFINITY;

/** @} */
/** @} */

NS_CC_END

#endif // CC_USE_PHYSICS
#endif // __CCPHYSICS_WORLD_H__