2011-12-13 30 views
5

Trong cocos2d, bạn có thể dễ dàng trong CCSprites và di chuyển chúng xung quanh bằng mọi cách. Quan trọng nhất - họ có thể giảm bớt trong/ngoài. Đối với hầu hết các trò chơi, điều này là mong muốn cho chuyển động trơn tru, v.v.Di chuyển các đối tượng Box2d Giống như các đối tượng CCSprite

id action = [CCMoveTo actionWithDuration:dur position:pos]; 
move = [CCEaseInOut actionWithAction:action rate:2]; 
[self runAction: move]; 

Khi di chuyển hộp2, phần tử gắn liền với nó được cập nhật sau bước box2d(). Di chuyển các sprite và sau đó cập nhật cơ thể không phải là một lựa chọn ở đây, vì nó hoàn toàn đánh bại mục đích của khung vật lý. Vì vậy, các tùy chọn khác, mà tôi đã thực hiện thành công, là để tính toán chuyển, vận tốc và gia tốc của một sprite bằng cách xử lý nó như là một thực thể cơ học theo đúng nghĩa của nó. Mỗi lần tôi gọi cập nhật của tôi() trên sprite để nhân vật có thể quyết định nơi để di chuyển vv, siêu lớp của tôi cũng lưu trữ vị trí và vận tốc trước đó. Chúng được lưu trữ dưới dạng giá trị tuân thủ box2d bằng cách chia cho PTM_RATIO.

Trong lớp con của CCSprite, gọi FMSprite:

-(CGPoint) displacement { 
    return ccpSub(self.position, lastPos); 
} 

-(b2Vec2) getSpriteVelocity:(ccTime)dt { 
    return b2Vec2(self.displacement.x/dt/PTM_RATIO, 
        self.displacement.y/dt/PTM_RATIO); 
} 

-(b2Vec2) getSpriteAccel:(ccTime)dt { 
    b2Vec2 currVel = [self getSpriteVelocity:dt]; 
    if (dt == 0) { 
     return b2Vec2(0,0); 
    } else {  
     float accelX = (currVel.x - lastVel.x)/dt; 
     float accelY = (currVel.y - lastVel.y)/dt; 
     return b2Vec2(accelX, accelY); 
    } 
} 

// This is called each update() 
-(void) updateLast:(ccTime)dt { 
    // MUST store lastVel before lastPos is updated since it uses displacement 
    lastVel = [self getSpriteVelocity:dt]; 
    lastPos = ccp(self.X, self.Y); 
} 

// Leave this method untouched in subclasses 
-(void) update:(ccTime)dt { 
    [self updateObject:dt]; 

    // Store previous update values 
    [self updateLast:dt]; 
} 

// Override this method in subclasses for custom functionality 
-(void) updateObject:(ccTime)dt { 

} 

Tôi đã sau đó subclassed "FMSprite" vào "FMObject", mà các cửa hàng một b2Body, vv

Để di chuyển cơ thể , Trước tiên tôi phải di chuyển một sprite và theo dõi gia tốc của nó, thông qua đó tôi có thể tìm thấy lực lượng cần thiết (sử dụng khối lượng) cần thiết để theo dõi chuyển động của sprite. Vì tôi không thể di chuyển sprite của đối tượng (được đồng bộ với cơ thể), tôi tạo một sprite khác được gọi là "beacon", thêm nó như một đứa trẻ vào đối tượng và di chuyển nó xung quanh. Tất cả những gì chúng ta cần làm là có chức năng đồng bộ hóa vị trí của thân box2d với ngọn hải đăng này bằng cách sử dụng các lực tôi đã đề cập trước đây.

-(void) followBeaconWithDelta:(ccTime)dt { 
    float forceX = [beacon getSpriteAccel:dt].x * self.mass; 
    float forceY = [beacon getSpriteAccel:dt].y * self.mass; 
    [self addForce:b2Vec2(forceX, forceY)]; 
} 

Kết quả là rực rỡ, một chuyển động nới lỏng mịn của b2body di chuyển nơi nào bạn muốn nó, mà không chơi đùa với bất kỳ lực lượng của riêng mình, mà đúng hơn là sao chép của một CCSprite và tái tạo chuyển động của nó. Vì nó là tất cả các lực, nó sẽ không gây ra sự rung và méo mó khi va chạm với các đối tượng b2Body khác. Nếu bất cứ ai có bất kỳ phương pháp khác để làm điều này, xin vui lòng gửi một câu trả lời. Cảm ơn!

+0

Xin chào, Cảm ơn bài đăng này. Tôi chưa hiểu một điều. Tại sao bạn cần một ngọn hải đăng sprite? nếu một đối tượng kiểu FMObject (là một CCSprite) đang được di chuyển bằng cách sử dụng một số hành động tùy chỉnh, tại sao không làm cho b2Body trong FMObject theo sau sprite cha. Tôi không chắc những gì 'đồng bộ hóa với cơ thể' có nghĩa là gì. Tại sao bạn lại cần một ngọn hải đăng và di chuyển nó xung quanh? – Aks

+0

Đã gần 3 năm kể từ khi tôi đăng bài này, nhưng tôi nghĩ bạn có thể đúng. Tôi không thể thấy lý do để có một ngọn hải đăng. Tôi nghĩ đó chỉ là một chi tiết thực hiện. Bạn sẽ có thể thay thế chính 'FMObject'. –

Trả lời

4

Điều tôi làm khác với bạn, nhưng cũng có thể di chuyển các đối tượng Box2d Giống như đối tượng CCSprite và thậm chí sử dụng CCAction. Điều quan trọng nhất là tạo một đối tượng chứa ccSprite và b2body.

@interface RigidBody : CCNode { 
    b2Body *m_Body; 
    CCSprite *m_Sprite; 
} 

Sau đó, viết lại phương pháp setPosition.

-(void)setPosition:(CGPoint)position 
{ 
    CGPoint currentPosition = position_; 
    b2Transform transform = self.body->GetTransform(); 
    b2Vec2 p = transform.p; 
    float32 angle = self.body->GetAngle(); 
    p += [CCMethod toMeter:ccpSub(position, currentPosition)]; 
    self.body->SetTransform(p, angle); 
    position_ = position; 
} 

Phương pháp setPosition tính toán vị trí thay đổi và đặt vị trí thành b2body.

Tôi hy vọng tôi hiểu câu hỏi của bạn và câu trả lời là hữu ích cho bạn ...

+0

Tính năng này hoạt động để định vị nhưng SetTransform sẽ đặt vị trí cơ thể mỗi lần thay vì sử dụng lực.Điều này có nghĩa là khi hai đối tượng RigidBody va chạm với nhau, chúng sẽ tạo ra hiệu ứng jittering thay vì tung ra một cách trơn tru. Phương thức addForce làm việc nhiều hơn, nhưng sẽ đảm bảo rằng vật lý trơn tru. –

+0

Có, nhưng sử dụng vũ lực là khó khăn để giữ cho cơ thể ở một tốc độ ổn định và một vị trí xác định. Tôi không bao giờ nhận được bất kỳ sai lầm khi tôi sử dụng phương pháp của tôi, nhưng tôi không có ý tưởng nếu cả hai cơ thể là b2_dynamicBody. –

Các vấn đề liên quan