2014-05-24 50 views
0

我唯一能想到的方法就是在每次碰撞過程中檢查所有物理體的速度。如何知道什麼時候所有物理實體已經停止在Cocos2d V3.0中與Chipmunk一起移動

- (BOOL)ccPhysicsCollisionBegin:(CCPhysicsCollisionPair *)pair piece:(CCNode *)pieceA piece:(CCNode *)pieceB{ 

    float x = 0; 
    float y = 0; 

    for (int i = 0; i < [[_physicsWorld children] count]; i++) { 

     x = x + [[[_physicsWorld children][i] physicsBody] velocity].x; 
     y = y + [[[_physicsWorld children][i] physicsBody] velocity].y; 
    } 

    if (x == 0 && y == 0) { 
     NSLog(@"stopped"); 
    } 

    return YES; 

} 

此日誌中多次「停止」時的情景首次加載,那麼不記錄「停止」了,甚至在物理機構已經明確開始移動和碰撞,然後停下來。

理想情況下,我想要一個委託方法,當所有物理實體停止移動時通知我,但我似乎無法找到一個方法。

FYI:我使用的是真實烤成的Cocos2D V3.0

回答

0

我發現一些作品的標準Chipmunk的物理引擎。

TL;博士

的基本思路是,以保持精靈的位置跟蹤自己,然後定期檢查他們是否有任何人因爲他們是最後一次檢查已經轉移。

加長版

我創建CCNode與類名Piece一個子類。

這些是我添加到物理世界的物體。

@implementation Piece { 

    float _previousX; 
    float _previousY; 
} 

-(void)updatePreviousScreenXandY{ 

    _previousX = self.position.x; 
    _previousY = self.position.y; 
} 

-(BOOL)hasntMoved{ 

    float currentX = self.position.x; 
    float currentY = self.position.y; 

    if (currentX == _previousX && currentY == _previousY) { 
     return TRUE; 
    }else{ 
     return FALSE; 
    } 
} 

這是我的CCNode充當遊戲場景

-(void)doStuffAfterPiecesStopMoving:(NSTimer*)timer{ 


    BOOL noPiecesHaveMoved = TRUE; 

    for (int i = 0; i < [[_physicsWorld children] count]; i++) { 
     if ([[_physicsWorld children][i] hasntMoved] == FALSE) { 
      noPiecesHaveMoved = FALSE; 
      break; 
     } 
    } 

    if (noPiecesHaveMoved) { 
     [timer invalidate]; 
     NSLog(「Pieces have stopped moving」); 
    }else{ 
     NSLog(「Pieces are still moving」); 
     [self updateAllPreviousPiecePositions]; 
    } 

} 

-(void)updateAllPreviousPiecePositions{ 

    for (int i=0; i < [[_physicsWorld children] count]; i++) { 
     Piece *piece = (Piece*)[_physicsWorld children][i]; 
     [piece updatePreviousScreenXandY]; 
    } 

} 

所有我需要做的就是

[NSTimer scheduledTimerWithTimeInterval:TIME_BETWEEN_CHECKS 
           target:_gamePlay 
           selector:@selector(doStuffAfterPiecesStopMoving:) 
           userInfo:nil 
           repeats:YES]; 

,它會所有的片之後,運行我想要的任何代碼節點已停止移動。

使其正常工作的關鍵是獲取Chipmunk空間的sleepTimeThreshold值和上面定時器的值儘可能低。

我運行實驗表明以下設置工作還行,但任何降低都會導致問題(即碰撞沒有發生正常):

sleepTimeThreshold = 0.15

我的定時器= 0.05

如果有人對上述代碼有不同的/更好的解決方案或改進,請發佈。

0

花栗鼠有一個內部機制,如果激活,它可以自動停用物理實體。我的做法(我用cocos2dx 3.11.1而不是-obj版本與花栗鼠7.0.1)是:

  1. 激活花栗鼠空轉機構(間隔0.5秒 - 這意味着,如果一個對象不動了長於0。5秒將被取消):

    cpSpaceSetSleepTimeThreshold(space, 0.5f); 
    

你並不需要使用

cpSpaceSetIdleSpeedThreshold(space, <speed>); 

因爲花栗鼠計算閾值的速度爲你(根據使用的引力)。

  • 使用用於測定此代碼,如果所有對象都沒有運動(靜態和動態機構從來不睡覺):

    bool isAnyPhysicsBodyMoving(){ 
        int i = 0; bool isMoving = false; 
        const Vector<PhysicsBody*>& bodies = getPhysicsWorld()->getAllBodies(); 
        while(i < bodies.size() && !isMoving){ 
         PhysicsBody *body = bodies.at(i); 
         isMoving = cpBodyGetType(body->getCPBody()) == CP_BODY_TYPE_DYNAMIC 
            && !body->isResting(); 
         i++; 
        } 
        return isMoving; 
    } 
    
  • 使用靜態(不運動)體用於牆壁,爲了讓對象入睡:

    // wall 
    Size visibleSize = Director::getInstance()->getWinSize(); 
    Vec2 origin = Director::getInstance()->getVisibleOrigin(); 
    float border = 10.0f; 
    Size wallBodySize = Size(visibleSize.width+2*border, visibleSize.height+2*border); 
    PhysicsBody *wallBody = PhysicsBody::createEdgeBox(wallBodySize, PhysicsMaterial(1.0f, 1.0f, 0.5f), border); 
    Node* wall = Node::create(); 
    wall->addComponent(wallBody); 
    wall->setAnchorPoint(Vec2(0.5f, 0.5f)); 
    wall->setPosition(Point(visibleSize.width/2+origin.x, visibleSize.height/2+origin.y)); 
    
    cpVect tt; 
    tt.x = wall->getPosition().x; tt.y = wall->getPosition().y; 
    //set position manually and BEFORE adding the object into the space 
    cpBodySetPosition(wallBody->getCPBody(), tt); 
    cpBodySetType(wallBody->getCPBody(), CP_BODY_TYPE_STATIC); 
    addChild(wall); 
    
  • 連接到動力學體(例如鋪設)不限動體不會休眠。

  • 與DEBUG測試激活

    getPhysicsWorld()->setDebugDrawMask(PhysicsWorld::DEBUGDRAW_ALL); 
    
  • 的框(其內容)必須成爲灰色(=睡眠),而不是紅色(=活性): enter image description here

    爲了讓它工作,我有:

    1. 加入的訪問方法(獲取cpSpace)在CCPhysicsWorld.h:的

      cpBodySetTorque(body, 0.0f);` 
      
      在CCPhysicsBody.cpp

      inline cpSpace* getSpace() const { return _cpSpace; } 
      
    2. 修正調用

      if (body->t != 0.0f){ 
          cpBodySetTorque(body, 0.0f); 
      } 
      
    3. 修復呼叫

      cpBodySetPosition(_cpBody, tt);` 
      

      在CCPhysicsBody.cpp到

      if (!cpveql(tt, cpBodyGetPosition(_cpBody))){ 
          cpBodySetPosition(_cpBody, tt); 
      } 
      

    步驟1,2和3是必須的,以避免相同的物理體特性,其喚醒休眠體的設置。

    這種方法的優點是,花栗鼠不會對這些物理體進行任何計算 - 節省CPU和電池。

    相關問題